Control several elements based on their values with WHERE - mysql

I would like to substract 1 from SEVERAL elements in a table if they are not equal to 0.
Code for one element
UPDATE `database` SET a1=a1-1 WHERE a1!='0' AND username='bob';
I want to do the same thing on the same command for several elements, a2, a3... (username stay the same for all elements)
Thank you

You're probably looking for conditionals within your set expressions. This can be achieved with the keyword CASE:
UPDATE 'database'
SET
a1 = CASE WHEN a1 != 0 THEN (a1 - 1) END,
a2 = CASE WHEN a2 != 0 THEN (a2 - 1) END
WHERE
username='bob';
Be sure to understand the principles of the sql update syntax which consists basically of a single UPDATE ... SET ... [WHERE] pattern.
Hint: I'm pretty sure your a1,a2,a3,.. fields are of type integer, so - unlike in your code example - the value to check must not put into quotes!

Related

CASE query answer data type changes depending on the data type of the unused statement

I have a simple CASE query, however I noticed something I find surprising - the type of data that the query returns changes depending on what data type is in the unused (not chosen) branch.
Let's consider two case queries:
A1:
SELECT
CASE 1
WHEN 3 THEN '7'
ELSE 'text answer' END
FROM SomeDatabase
B1:
SELECT
CASE 1
WHEN 3 THEN '7'
ELSE float_attribute END
FROM SomeDatabase
The A1 query will return 'the same'
The B1 query will return the value of float_attribute (which is of the float type - important!)
So far so good...
The issue I have is if we change these queries so that the condition is fullfilled
A2:
SELECT
CASE 1
WHEN 1 THEN '7'
ELSE 'the same' END
FROM SomeDatabase
B2:
SELECT
CASE 1
WHEN 1 THEN '7'
ELSE float_attribute END
FROM SomeDatabase
Now here is where my confusion starts:
Query A2 returns 7
Query B2 returns 7.000000
Despite both queries containing the same chosen branch WHEN 1 THEN '7'
the queries return a value of a different type.
Clearly, the type depends on the type of the value/attribute that's in the second branch, even when it isn't chosen.
WHY IS THAT?? Is that normal SQL behaviour?
This is not surprising at all. A CASE expressions returns a single value. That value has a specified type.
The rules for determining the type of the return value have a preference for numbers and dates over strings. So if any of the return values is a number, then the overall value is a number. This is an easy way to get conversion errors, in some databases.
This is standard behavior. I'm pretty sure every data documents this as part of the explanation of the CASE expression.
The CASE statement Returns the highest precedence type from the set of types in result_expressions and the optional else_result_expression. For more information, see Data Type Precedence (Transact-SQL). Reference
In your case, string is lower than float.

How to combine CONCAT() and WHERE in MariaDB?

I like to use the result from another query to address the column name. For this I like to use CONCAT(). But somehow it don't work; when I run this line I get 0 rows back:
SELECT * FROM cover WHERE CONCAT('c','9') = 1;
When I don't make use of CONCAT() it work perfectly:
SELECT * FROM cover WHERE c9 = 1;
And also CONCAT() seems to work. With this I get a result:
SELECT CONCAT('c','9');
I tried all solution from this question:
MySQL select with CONCAT condition
like this one, but i always got 0rows back:
SELECT * FROM (
SELECT id, CONCAT('c', '9') as target
FROM cover) base
WHERE target = "1"
My MySQL Version is; 10.1.16-MariaDB
It is bad schema design to splay an array across a bunch of columns. And, as you are discovering, it is hard to use the columns. Build another table for the c values.
Or...
With lots of 0/1 "columns", consider SET or BIGINT UNSIGNED; either will hold up to 64 boolean flags in a tiny fraction of the space. And, with different code, BLOB could be used.
To extract bit 22 from a BIGINT, ((col >> 22) & 1) will give you 0 or 1.
Consider using a case when, since the number of options is known beforehand (you can only access columns that exist):
SELECT id
FROM cover
WHERE case ?
when 1 then c1
when 2 then c2
when 9 then c9
end = 1
... where the question mark would be the provided value, like 9 in your example.

SSRS Parameter values in WHERE clause

(edited to clean up)
I have an SSRS report with a multi-value parameter. What I need is for each value of the parameter to correspond to a condition in the "where" clause.
So my query is like this:
select stuff,...
WHERE
column A != column B OR
column C != column D OR...
just like that all the way down. It's to give results only if there's a difference between different pairs of columns.
So hope I'm describing it well. So, for example, if the above is my where clause, I want the parameter to have values like this:
"Difference between A & B"
"Difference between C & D"
and be able to select multiple...so only the ones the user selects are incorporated.
EDIT - PARTIAL SOLUTION **********************************************
Ok I have the logic, thanks to the right direction from Hannover Fist, I came up with this:
WHERE
col 1 <> CASE WHEN CHARINDEX("Where1",#Parameter) = 0 THEN col 1 ELSE col 2 END OR
col 3 <> CASE WHEN CHARINDEX("Where2",#Parameter) = 0 THEN col 3 ELSE col 4 END
...etc.....
This way, if the parameter is not selected, that part of the where clause looks for results where that column is not equal to itself--so none, of course...
However, one problem remains. This works in SSRS if I only choose 1 of the parameter values, but if I choose more than one, I get an error "charindex function requires 2 to 3 arguments." >-(
I deployed it and it spat something slightly different:
Argument data type nvarchar is invalid for argument 3 of charindex function
Something about SSRS's handling of this is flapdoodle, but I'm not sure what.
I'm a little fuzzy as to how you're trying to do this.
How about having your WHERE clause in your SQL and use your parameter to determine whether that part of the WHERE is used? This may not be exactly what you need but should give you an idea of what I mean.
WHERE (ColA <> ColB or CHARINDEX("Where1", #Parameter) = 0)
Your Parameter would have Where1 as one of the selections (for the Value - the Label could be more descriptive). If it's chosen, the CHARINDEX result would not be 0 and the ColA <> ColB condition would need to be true to show that record.
Repeat for each parameter/WHERE combo you need.
Got it.
As edited above, this code works (helpful nudge in this direction from Hannover Fist):
WHERE
col 1 <> CASE WHEN CHARINDEX("Where1",#Parameter) = 0 THEN col 1 ELSE col 2 END OR
col 3 <> CASE WHEN CHARINDEX("Where2",#Paremeter) = 0 THEN col 3 ELSE col 4 END
etc...
And the parameter issue is new to my experience, but put simply (which is not done often--hence my difficulty :-P), SSRS includes the commas between parameter values (which makes sense since we can use an IN statement such as
WHERE column IN (#Parameter)
So that is why it complained when I selected more than one. Incorporating the excellent selected answer here:
Passing multiple values for a single parameter in Reporting Services
Solved the rest of the problem :)
When you are passing the multivalue parameter to dataset
join the multivalue parameter with expression
= JOIN(Parameters!multivalue parameter.Value,",")

Mysql Update 2 columns from 2 different tables with extra condition

I want to update two different columns from two different tables in mysql. This is the brief version of what I want to do.
In more detail I want to update a column from table 1 only if a condition is true. Otherwise I want to update a other column from table 1.
The same I want to do for table 2 and this should be all done in a single UPDATE statement.
I tried something like this:
UPDATE `grouped_messages`
JOIN `messages` ON (`messages`.group_msg_id = 1) SET
(CASE WHEN(`grouped_messages`.`conversation_partner1`=10) THEN `grouped_messages`.`deletion_status_partner1`=1
WHEN(`grouped_messages`.`conversation_partner2`=10) THEN `grouped_messages`.`deletion_status_partner2`=1 END),
(CASE WHEN(`messages`.`from`=10) THEN `messages`.`deletion_status_from`=1
WHEN(`messages`.`to`=10) THEN `messages`.`deletion_status_to`=1 END);
but this is not working. Does anybody know a solution, which would work for my case?
You can't do an assignment within a CASE expression. Your SET clause is invalid. It needs to be SET column = expression.
To have the column conditionally updated; that is, to have the column not updated, have the expression return the current value of the column.
Let's use an alias of g for grouped_messages.
When the condition you are checking is true, you want the SET clause to be equivalent to:
SET g.deletion_status_partner1 = 1
When the condition is not true, you want to assign the current value of the column to itself, so the SET clause to equivalent to:
SET g.deletion_status_partner1 = g.deletion_status_partner1
To get that, you could do something like this:
SET g.deletion_status_partner1
= CASE WHEN g.conversation_partner1 = 10
THEN 1
ELSE g.deletion_status_partner1 -- existing column value
END
To modify an additional column, you'd need to add to the SET clause
, g.deletion_status_partner2
= CASE WHEN some_other_condition
THEN new_value
ELSE g.deletion_status_partner2 -- existing column value
END
(I haven't checked anything else in your statement; I only highlight the most obvious issue, and how to get an update statement to do "conditional" assignment.)

creating a proportion column with two decimal places

I have two existing columns and have created a new blank column.
Column1 Column2 NewColumn
A B A/B
C D C/D
When I try the following my NewColumn is populated with 1's and 0's. I would like a decimal representation of the proportion.
update MyTable
set NewColumnd = ((Column1/Column2)*1.00)
where Column2 != 0
You're performing the conversion too late - the division has already been performed using integer math, and than the conversion to float occurs. Maybe try:
update MyTable
set NewColumnd = ((Column1*1.00)/Column2)
where Column2 != 0
Although it should be noted that, if the formula should always hold, a computed column would be better than something produced via an UPDATE.