SQL Case Statement - mysql

I have a table named as "allocation" with the columns named as "all_code", "grs_amt" and "cut_amt". I want to create a SQL statement to be got results as Gross_Value, Cut_Value and Net_Value. If the "cut_amt" IsNull then assign 0 for the Cut_Value and then calculate Net_Value using that assigned 0 value or available value in the "cut_amt". I used the following query.
SELECT allocation.grs_amt AS Gross_Value,
IfNull(allocation.cut_amt, 0) AS Cut_Value,
allocation.grs_amt - allocation.cut_amt AS Net_Value FROM
allocation
02) But unable to get the desired output. Can not understand what I am going wrong . Can anyone help me?

You have to repeat the expression:
SELECT a.grs_amt AS Gross_Value,
coalesce(a.cut_amt, 0) AS Cut_Value,
(a.grs_amt - coalesce(a.cut_amt, 0)) AS Net_Value
FROM allocation a;
I prefer coalesce() under most circumstances because it is ANSI standard.

Related

SQL Sum returns a false value

I have an issue with the SUM-Function in my MySQL Workbench. When I use the function, it returns a false value.
I´d like to SUM these three numbers:
56,03
35,59
54,35
The result should be 145,97, but its just 145 instead. I tried these different codes:
SELECT SUM(price) FROM table;
This one returns the value 145.
SELECT ROUND(SUM(price),2) FROM table;
The second one returns the value 145.00.
I was wondering whats wrong with the code, because I tried it in another DB that I have in my MySQL Workbench. Also tried it over the Terminal in both databases. In the other database the function works correctly.
Best thing to do would be to change your table so that it is a decimal field.
However, if you can't do that, the following query should get what you want:
SELECT SUM(replace(price,',', '.')) FROM tbl;
You can test in on SQLFiddle

SSRS casting a parameter to decimal multi select

Im trying to cast a parameter in SSRS to a decimal. I have a in clause since its multi select. I can select 1 and it runs fine however if i select more than 1 it will say
"Incorrect syntax near the keyword 'as'."
I am casting my parameter in my where clause in my query statement.
WHERE LOAD_NO IN (CAST(#Load as DECIMAL))
I am confused as to why it would bring back the syntax error if I select more than one from list.
Thanks
I am confused as to why it would bring back the syntax error if I
select more than one from list.
Short answer
Because WHERE LOAD_NO IN (CAST(1,2,N as DECIMAL)) is not a valid T-SQL statement.
Long answer
When you use a multi-value parameter in a query, reporting services will generate different queries if your parameter contains 1 value, or multiple values.
Let's simplify your example to the following query:
SELECT * FROM TABLE WHERE LOAD_NO IN (#Load)
With only one value, the query will have the following format:
exec sp_executesql N'SELECT * FROM TABLE WHERE LOAD_NO IN (#Load)', N'#Load int', #Load=<YourValue>
It's a query with a parameter: #Load.
Now, with multiple values, the query will become
exec sp_executesql N'SELECT * FROM TABLE WHERE LOAD_NO IN (<YourValue1>, <YourValue2>,<YourValueN>)'
The #Load parameter has been replaced by the list of values.
So now my advise will be to rethink the design of your query and treat #Load as a list of values.
We cannot provide you the best solution because it really depends on the data and only you have all the details but I could still throw some ideas.
On the top of my head I could think of:
Cast LOAD_NO instead, but the execution plan may loose the benefits of indexes if any.
In most cases, using a IF EXISTS when possible instead of IN.
Use a subquery.
Do not hesitate to run a SQL Server Profiler to see the generated query if you have other issues.
I'm not sure what your data looks like, so I'm not sure if these options would help, but here's a couple suggestions:
Try putting the CAST on LOAD_NO instead:
WHERE CAST(LOAD_NO AS VARCHAR) IN (#Load)
Create a splitString function like the accepted post here (T-SQL split string) and access it in your WHERE clause:
WHERE LOAD_NO IN (SELECT CAST(val AS DECIMAL) FROM dbo.splitString(#Load, ','))

Mysql where clause syntax

I was running through some of our code at work and came across this structure for an sql query and was sure it was a typo in the variables of our PHP, I ran it and it works.
Select column from table where value = column;
Anyone I know was always taught the correct syntax is:
Select column from table where column = value;
Is there any reason for this being legal, other than SQL just checks are both sides of an equation equal to each other?
I'm more posting this because I found it really interesting, like a 'the more you know' kind of thing.
The equality operator (=) is symmetric - if a=b is true, then so is b=a. a and b can be column names, values or complex expressions. It's common to use the form column=value, but syntactically speaking, it's completely equivalent to value=column.
Yes, you have it right sql just checks both sides of an equation. The equation could even contain a column on neither side! such as
SELECT column from table where 1=2;
The syntax of an SQL query is :
SELECT what_to_select
FROM which_table
WHERE conditions_to_satisfy;
You can use any condition you want, for example :
SELECT * FROM table WHERE 1
will return you all the rows
while
SELECT * FROM table WHERE 0
will return you nothing
after a WHERE you must have a condition, nothing else

MySql explode/in_array functionalilty

In my table I have a field with data such as 1,61,34, and I need to see if a variable is in that.
So far I have this
SELECT id, name FROM siv_forms WHERE LOCATE(TheVariable, siteIds) > 0
Which works, with the exception that if the siteIds were 2,61,53, and TheVariable was 1, it would return the row as there is a 1 in 61. Is there anyway around this using native MySql, or would I need to just loop the results in PHP and filter the siteIds that way?
I've looked through the list of string functions in MySql and can't see anything that would do what I'm after.
Try with find_in_set function.
SELECT id, name FROM siv_forms WHERE find_in_set(TheVariable, siteIds);
Check Manual for find_in_set function.

Subtracting the value from the last row using variable assignment in MySQL

According to the MySQL documentation:
As a general rule, you should never assign a value to a user variable and read the value within the same statement. You might get
the results you expect, but this is not guaranteed.
http://dev.mysql.com/doc/refman/5.6/en/user-variables.html
However, in the book High Perfomance MySQL there are a couple of examples of using this tactic to improve query performance anyway.
Is the following an anti-pattern and if so is there a better way to write the query while maintaining good performance?
set #last = null;
select tick, count-#last as delta, #last:=count from measurement;
For clarification, my goal is to find the difference between this row and the last. My table has a primary key on tick which is a datetime column.
Update:
After trying Shlomi's suggestion, I have reverted back to my original query. It turns out that using a case statement with aggregate functions produces unexpected behavior. See for example:
case when (#delta := (max(measurement.count) - #lastCount)) AND 0 then null
when (#lastCount := measurement.count) AND 0 then null
else #delta end
It appears that mysql evaluates the expressions that don't contain aggregate functions on a first pass through the results, and then evaluates the aggregate expressions on a second (grouping) pass. It appears to evaluate the case expression during or after that second pass and use the precalculated values from the first pass in that evaluation. The result is that the third line #delta is always the initial value of #delta (because assignment didn't happen until the grouping pass). I attempted to incorporate a group function into the line with #delta but couldn't get it to behave as expected. So I ultimately when back to my original query which didn't have this problem.
I would still love to hear any more suggestions about how to better handle a query like this.
Update 2:
Sorry for the lack of response on this question, I didn't have a chance to investigate further until now.
Using Shlomi's solution it looks like I had a problem because I was using a group by function when I read my #last variable but not when I set it. My code looked something like this:
CASE
WHEN (#delta := count - #last) IS NULL THEN NULL
WHEN (#last:= count ) IS NULL THEN NULL
ELSE (CASE WHEN cumulative THEN #delta ELSE avg(count) END)
END AS delta
MySQL appears to process expressions that don't contain aggregate functions in a first pass and ones that do in a second pass. The strange thing in the code above is that even when cumulative evaluates to true MySQL must see the AVG aggregate function in the ELSE clause and decides to evaluate the whole inner CASE expression in the second pass. Since #delta is set in an expression without an aggregate function it seems to be getting set on the first pass and by the time the second pass happens MySQL is done evaluating the lines that set #delta and #last.
Ultimately I seem to have found a fix by including aggregate functions in the first expressions as well. Something like this:
CASE
WHEN (#delta := max(count) - #last) IS NULL THEN NULL
WHEN (#last:= max(count) ) IS NULL THEN NULL
ELSE (CASE WHEN cumulative THEN #delta ELSE avg(count) END)
END AS delta
My understanding of what MySQL is doing is purely based on testing and conjecture since I didn't read the source code, but hopefully this will help others who might run into similar problems.
I am going to accept Shlomi's answer because it really is a good solution. Just be careful how you use aggregate functions.
I've researched this issue in depth, and wrote a few improvements on the above.
I offer a solution in this post, which uses functions whose order can be expected. Also consider my talk last year.
Constructs such as CASE and functions such as COALESCE have known underlying behavior (at least until this is changed, right?).
For example, a CASE clause inspects the WHEN conditions one by one, by order of definition.
Consider a rewrite of the original query:
select
tick,
CASE
WHEN (#delta := count-#last) IS NULL THEN NULL
WHEN (#last:=count ) IS NULL THEN NULL
ELSE #delta
END AS delta
from
measurement,
(select #last := 0) s_init
;
The CASE clause has three WHEN conditions. It executes them by order until it meets the first that succeeds. I've written them such that the first two will always fail. It therefore executes the first, then turns to execute the second, then finally returns the third. Always.
I thus overcome the problem of expecting order of evaluation, which is a real and true problem, mostly evident when you start adding more complex clauses such as GROUP BY, DISTINCT, ORDER BY and such.
As a final note, my solution differs from yours in the first row on the result set -- with yours' it returns NULL, with mine it returns the delta between 0 and count. Had I used NULL I would have needed to change the WHEN conditions in some other way -- making sure they would fail on NULL values.