CASE equivalent of a nested IIF statement - sql

Can anyone please decode the following nested IIF to a CASE statement in SQL.. I know IIF is allowed in SQL Server 2012 but I find it hard to get an easy grasp of a nested IIF logic.. following is my nested IIF statement
IIF(IIF(TABLE_A.Col_1 = 0, TABLE_A.Col_2 + (2*TABLE_A.Col_3), TABLE_A.Col_1)<=.5, 'A', 'B') AS Result
Any help is much appreciated.

This should be the equivalent:
CASE
WHEN
CASE
WHEN TABLE_A.Col_1 = 0
THEN TABLE_A.Col_2 + (2*TABLE_A.Col_3)
ELSE TABLE_A.Col_1
END <= .5
THEN 'A'
ELSE 'B'
END As Result

CASE
WHEN
(CASE
WHEN TABLE_A.Col1= 0
THEN TABLE_A.Col2_2 + (2*TABLE_A.Col3)
ELSE TABLE_A.Col1
END) <=0.5
THEN 'A'
ELSE 'B'
END
AS result

I think this is what it boils down to in one CASE expression:
CASE
WHEN TABLE_A.Col_1 = 0 AND TABLE_A.Col_2 + (2*TABLE_A.Col_3) <= .5 THEN 'A'
WHEN TABLE_A.Col_1 <> 0 AND TABLE_A.Col_1 <= .5 THEN 'A'
ELSE 'B'
END

This is old now, and there are other answers that already work, but for fun it is possible to write this as a functional expression without any CASE statements at all, like this:
char(65 + ceiling(ceiling(COALESCE(NULLIF(TABLE_A.Col_1, 0), TABLE_A.Col_2 + (2*TABLE_A.Col_3))) - .5 / 10000000000000))
There is a very small chance that the functional approach will perform noticeably better on large sets with good indexing.
Here's my proof-of-concept test script:
http://sqlfiddle.com/#!3/a95b3/2

Related

Case expression degrading performance in Correlated Sub query

SUM((CASE WHEN ([t2].[__measure__8] > 1) THEN (CASE WHEN [t2].[__measure__8] = 0 THEN NULL ELSE (CAST([t2].[__measure__9] as float) / [t2].[__measure__8]) END) ELSE [t2].[__measure__9] END))
when I use this calculation above Correlated Subquery which has a group by too . Its is taking more than 5 minutes to receive the result set. Moreover, the inner subset of query retrieves in just 4 sec. Am I missing something else?
What is the best way to write this case expression?
Sub case statement looks like unnecessary. You can remove CASE WHEN [t 2].[_ measure _8] = 0
SUM(CASE
WHEN ([t2].[__measure__8] > 1) THEN (CAST([t2].[__measure__9] as float) / [t2].[__measure__8])
ELSE [t2].[__measure__9]
END )
Since you only have 1 condition on your case statement, I suggest to use iif function instead.
sum(
iif([t2].[__measure__8] > 1,
iif([t2].[__measure__8] = 0, null, cast([t2].[__measure__9] as float)/[t2].[__measure__8]),
[t2].[__measure__9])
)
Try to break down your query by using subqueries, remove the sum() first then check the improvements.

How to have 3 conditions to fulfill in CASE WHEN in SQL

I am having difficulty when trying to have 3 conditions to fulfill in CASE WHEN in SQL server. Here is my original script but only return value 0 instead of 1 and 0. My purpose is to check when a customer purchase ITEM_01 with more than or equal to 0.06 AND ITEM_02 with more than or equal to 0.06 THEN return value 1 else 0. Here is my script:
CASE WHEN SUM ( CASE WHEN ITEM_01)='DH' AND (ITEM_02)='DH Classic' THEN NVL
(SALE_OUTLETD.PRE_SALES_QTY * SKU_UOM_CONV.MULTIPLIER,0) + NVL
(SALE_OUTLETD.SALES_QTY * SKU_UOM_CONV.MULTIPLIER, 0) -NVL
(SALE_OUTLETD.FRESH_RTN_QTY *SKU_UOM_CONV.MULTIPLIER, 0) - NVL
(SALE_OUTLETD.OLD_RTN_QTY * SKU_UOM_CONV.MULTIPLIER,0) - NVL
(SALE_OUTLETD.DAMAGED_RTN_QTY *SKU_UOM_CONV.MULTIPLIER, 0) - NVL
(SALE_OUTLETD.WITHDRAWAL_RTN_QTY *SKU_UOM_CONV.MULTIPLIER, 0) ELSE 0 END )
>= 0.06 THEN 1 ELSE 0 END 3_PACK_AND_ABOVE
Please help on this question because I have been stuck for few hours now. Any help would be greatly appreciated!
I am finding your example impossible to read but the basic form of CASE is:
select case WHEN first_boolean THEN first_value
WHEN second_boolean THEN second_value
WHEN third_boolean THEN third_value
...
ELSE default_value
Always try to build things off that model. Nested CASE statements like what you are doing are never fun and tend to be fairly error prone.

Switching fields in WHERE clause SQL 2005 [duplicate]

I am creating a SQL query in which I need a conditional where clause.
It should be something like this:
SELECT
DateAppr,
TimeAppr,
TAT,
LaserLTR,
Permit,
LtrPrinter,
JobName,
JobNumber,
JobDesc,
ActQty,
(ActQty-LtrPrinted) AS L,
(ActQty-QtyInserted) AS M,
((ActQty-LtrPrinted)-(ActQty-QtyInserted)) AS N
FROM
[test].[dbo].[MM]
WHERE
DateDropped = 0
--This is where i need the conditional clause
AND CASE
WHEN #JobsOnHold = 1 THEN DateAppr >= 0
ELSE DateAppr != 0
END
The above query is not working. Is this not the correct syntax or is there another way to do this that I don't know?
I don't want to use dynamic SQL, so is there any other way or do I have to use a workaround like using if else and using the same query with different where clauses?
Try this
SELECT
DateAppr,
TimeAppr,
TAT,
LaserLTR,
Permit,
LtrPrinter,
JobName,
JobNumber,
JobDesc,
ActQty,
(ActQty-LtrPrinted) AS L,
(ActQty-QtyInserted) AS M,
((ActQty-LtrPrinted)-(ActQty-QtyInserted)) AS N
FROM
[test].[dbo].[MM]
WHERE
DateDropped = 0
AND (
(ISNULL(#JobsOnHold, 0) = 1 AND DateAppr >= 0)
OR
(ISNULL(#JobsOnHold, 0) != 1 AND DateAppr != 0)
)
You can read more about conditional WHERE here.
Try this one -
WHERE DateDropped = 0
AND (
(ISNULL(#JobsOnHold, 0) = 1 AND DateAppr >= 0)
OR
(ISNULL(#JobsOnHold, 0) != 1 AND DateAppr != 0)
)
To answer the underlying question of how to use a CASE expression in the WHERE clause:
First remember that the value of a CASE expression has to have a normal data type value, not a boolean value. It has to be a varchar, or an int, or something. It's the same reason you can't say SELECT Name, 76 = Age FROM [...] and expect to get 'Frank', FALSE in the result set.
Additionally, all expressions in a WHERE clause need to have a boolean value. They can't have a value of a varchar or an int. You can't say WHERE Name; or WHERE 'Frank';. You have to use a comparison operator to make it a boolean expression, so WHERE Name = 'Frank';
That means that the CASE expression must be on one side of a boolean expression. You have to compare the CASE expression to something. It can't stand by itself!
Here:
WHERE
DateDropped = 0
AND CASE
WHEN #JobsOnHold = 1 AND DateAppr >= 0 THEN 'True'
WHEN DateAppr != 0 THEN 'True'
ELSE 'False'
END = 'True'
Notice how in the end the CASE expression on the left will turn the boolean expression into either 'True' = 'True' or 'False' = 'True'.
Note that there's nothing special about 'False' and 'True'. You can use 0 and 1 if you'd rather, too.
You can typically rewrite the CASE expression into boolean expressions we're more familiar with, and that's generally better for performance. However, sometimes is easier or more maintainable to use an existing expression than it is to convert the logic.
The problem with your query is that in CASE expressions, the THEN and ELSE parts have to have an expression that evaluates to a number or a varchar or any other datatype but not to a boolean value.
You just need to use boolean logic (or rather the ternary logic that SQL uses) and rewrite it:
WHERE
DateDropped = 0
AND ( #JobsOnHold = 1 AND DateAppr >= 0
OR (#JobsOnHold <> 1 OR #JobsOnHold IS NULL) AND DateAppr <> 0
)
Often when you use conditional WHERE clauses you end upp with a vastly inefficient query, which is noticeable for large datasets where indexes are used. A great way to optimize the query for different values of your parameter is to make a different execution plan for each value of the parameter. You can achieve this using OPTION (RECOMPILE).
In this example it would probably not make much difference, but say the condition should only be used in one of two cases, then you could notice a big impact.
In this example:
WHERE
DateDropped = 0
AND (
(ISNULL(#JobsOnHold, 0) = 1 AND DateAppr >= 0)
OR
(ISNULL(#JobsOnHold, 0) <> 1 AND DateAppr <> 0)
)
OPTION (RECOMPILE)
Source Parameter Sniffing, Embedding, and the RECOMPILE Options
This seemed easier to think about where either of two parameters could be passed into a stored procedure. It seems to work:
SELECT *
FROM x
WHERE CONDITION1
AND ((#pol IS NOT NULL AND x.PolicyNo = #pol) OR (#st IS NOT NULL AND x.State = #st))
AND OTHERCONDITIONS

CASE WHEN ... THEN

I'm trying to edit a code someone wrote some months ago, but I can't understand some parts, for example:
CASE
WHEN #PROMPT('SEL_TYPE')# = '%' then 1
WHEN #PROMPT('SEL_TYPE')# = 'ALL' then 1
WHEN e.evt_job = #PROMPT('SEL_TYPE')# then 1
ELSE 0
END = 1
Wherever I read about how CASE .. WHEN works, it's like:
CASE A
WHEN 'ok' THEN C = 'ok'
WHEN 'bad' THEN C = 'bad'
But im my example it's just THEN 1 or ELSE 0.
Whats the meaning of that 1 or 0? It's something I'm missing on the code, or that 1 or 0 means something?
Thanks all, and sorry for my English :)
You should understand the difference between the CASE expression and the CASE statement. This is a CASE expression:
CASE
WHEN #PROMPT('SEL_TYPE')# = '%' then 1
WHEN #PROMPT('SEL_TYPE')# = 'ALL' then 1
WHEN e.evt_job = #PROMPT('SEL_TYPE')# then 1
ELSE 0
END = 1
This is an incomplete CASE statement (Supported by other databases, like Oracle or MySQL, but not SQL Server):
CASE A
WHEN 'ok' THEN C = 'ok'
WHEN 'bad' THEN C = 'bad'
An expression is something that can be evaluated on the right hand side of an assignment, or in a SELECT statement, for instance.
A statement is a command that can be used in an imperative language, i.e. in a stored procedure. The CASE statement (if supported by a database) works just like an IF statement.
It means someone has overcomplicated things. If SQL Server had a boolean data type, they'd probably have just had then true, else false and no comparison at the end. But because that's not possible in SQL Server, they've substituted 1 and 0 and then just compare that to 1 at the end to make it a logical comparison.
It could equally have been written as:
#PROMPT('SEL_TYPE')# = '%' OR
#PROMPT('SEL_TYPE')# = 'ALL' OR
e.evt_job = #PROMPT('SEL_TYPE')#
With no need for a CASE expression at all.
Or even, probably, as just #PROMPT('SEL_TYPE')# IN ('%','ALL',e.evt_job), but some may feel that this obscures the intent a little too much.
So,
select code, wo_num, desc from table1
where org = #PROMPT('SEL_ORG')# and
CASE
WHEN #PROMPT('SEL_WO_TYPE')# = '%' then 1
WHEN #PROMPT('SEL_WO_TYPE')# = 'ALL' then 1
WHEN e.evt_jobtype = #PROMPT('SEL_WO_TYPE')# then 1 ELSE 0 END = 1
and e.evt_type in (''A,'B')
Could have more simply been written as:
select code, wo_num, desc from table1
where org = #PROMPT('SEL_ORG')# and
e.evt_type in (''A,'B') and
(
#PROMPT('SEL_TYPE')# = '%' OR
#PROMPT('SEL_TYPE')# = 'ALL' OR
e.evt_job = #PROMPT('SEL_TYPE')#
)
Someone wrote a CASE expression (and then had to introduce the 1s and 0s) when all they needed was basic boolean logic.

How to evaluate expression in standard sql?

I have an alphanumeric expression which I like to evaluate to true/false.
For example ('A' = 'B' or 10 > 5) should return true.
I am working with DB2 for i, so a standard sql would be required.
I tried
Select ('A' = 'B' or 10 > 5) from sysibm/sysdummy1
and
Select (('A' = 'B' or 10 > 5) = '1') from sysibm/sysdummy1
but the error says in the first case Token '(' required and in the second case Token '=' invalid.
How would you do this?
Thanks
Try like this please:
select case when 'A' ='B' or 10 > 5 then 1 else 0 end
Also maybe this post can help Boolean Expressions in SQL Select list