CASE WHEN ... THEN - sql

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.

Related

Using function inside CASE

I am trying to use the SUBSTR and NVL functions inside the case. The case is in the where clause of the select statement.
The code below gives the following error:
ORA-00905: missing keyword
AND ( CASE
WHEN SUBSTR(upper(p_open_invoice),1,1) = 'Y' THEN
NVL(P.AMOUNT_DUE_REMAINING,0) = 0
ELSE
1=1
END)
This looks like a syntax error around equal operator of NVL function.
That is not how case expressions work (in Oracle) -- there is no boolean type to return.
The simplest method is to remove the `case and express this as simple logic:
AND (SUBSTR(upper(p_open_invoice), 1, 1) <> 'Y' OR
COALESCE(P.AMOUNT_DUE_REMAINING, 0) = 0
)
If p_open_invoice can be NULL, you need to take that into account as well.
You cannot use a collation as a result for case..when statements, it's better converting the condition to
AND (( SUBSTR(upper(p_open_invoice),1,1) = 'Y' AND NVL(P.AMOUNT_DUE_REMAINING,0) = 0 )
OR SUBSTR(upper(p_open_invoice),1,1) != 'Y' )
If you're accustomed to programming in PL/SQL you may have seen that there's a BOOLEAN type in PL/SQL. However, this is not true in the Oracle database itself. The way I usually work around this is to use character expressions which return 'Y' or 'N' instead of TRUE or FALSE.
Keeping this in mind - if you really want to use a CASE expression similar to what you had originally you can use the following:
AND CASE
WHEN SUBSTR(upper(p_open_invoice),1,1) = 'Y'
THEN CASE
WHEN NVL(P.AMOUNT_DUE_REMAINING,0) = 0 THEN 'Y'
ELSE 'N'
END
ELSE 'Y'
END = 'Y'
Here the CASE expression returns either 'Y' or 'N', which is then compared with 'Y'.

Case statement in where clause using not like and is not null

I'm pulling data from an existing table using a stored procedure that has some yes or no choices that the user picks on the front end through a checkbox. I want to limit writing a bunch of different If statements for every choice they make.
This portion of my where clause works. Data is either Y or N for this column.
Where... and IsSigned = Case When #IncludeSigned = 'Y' then IsSigned else 'N' end
I would like to add to the where using is not null and not like if this is possible between the square brackets. So far I have
and SignatureType = case when #IncludeElectronic = 'Y' then Type else [NOT like electronic] end
also
and ReviewDate = Case When #HasReviewDate = 'Y' then [ReviewDate is not null] else null end
This may help you use AND/OR instead of case
where (ReviewDate is not null or #HasReviewDate = 'Y' ) And (....)
ie when #HasReviewDate = 'Y' query will return the records with ReviewDate is not null
and when #HasReviewDate != 'Y' then query will return the records with ReviewDate is null
think of it this way:-
Your first case statement has two possible results:-
IsSigned = 'Y'
IsSigned = 'N'
Your subsequent ones have problems as they don't make sense syntactically. So the second one as written returns
SignatureType = Type
SignatureType = [NOT like electronic]
and your third:
ReviewDate = [ReviewDate is not null]
ReviewDate = null end
SO the operator has to be before the case statement and apply to all of the results of the case statement.
For example
WHERE myfield not like CASE WHEN thatfield=1 THEN 'Fish' ELSE 'Chips END
would produce either
myfield not like 'Fish'
myfield not like 'Chips'
I believe you can not use in this way, apart of that, the impact that is not like can have inside your query can be high, my recommendation changes the strategy that you are using.

Does the SQL'%' wild card character capture null values?

Recently I've come across a problem with a query that isn't returning everything that it's expected to return. Part of the query which selects by a condition is as follows:
AND field LIKE
CASE WHEN #val = 1 THEN
'%'
ELSE
'N'
END
Now, when #val is 1, I'd expect this piece of code to essentially do nothing, as in the condition to basically accept any value what so ever, including null values.
Am I wrong about this? And if so, does anyone have a solution? I was thinking something along the lines of
AND field LIKE
CASE WHEN #val = 1 THEN
'%' OR ISNULL(field)
ELSE
'N'
END
However SQL doesn't work like that, but that's basically what I wish to accomplish.
Thanks all, and sorry if this is a duplicate, I couldn't find an answer.
Based on what you're trying to accomplish, it seems your query could be optimized to this:
AND (#val = 1 OR field = 'N')
There doesn't seem to be a reason for the LIKE.
UPDATE
Since you are trying to understand the behavior of LIKE and CASE moreso than working with existing queries, here are some variations of the accepted answer.
To use CASE within the LIKE, you have to use something like COALESCE to handle the null case as well.
COALESCE(Field, '') LIKE (CASE WHEN #val = 1 THEN '%' ELSE 'N' END)
Otherwise, you can use the LIKE within the CASE (like accepted answer), but probably personal preference that this seems easier to read:
1 = (CASE WHEN #val = 1 OR Field LIKE 'N' THEN 1 ELSE 0 END)
field LIKE '%' does not match null. CASE expressions must return a single type of result, I like int in most of mine.
AND 1 = CASE
WHEN #val = 1 THEN 1
WHEN field like 'N' THEN 1
ELSE 0
END
Try this (assuming that field is varchar or nvarchar) -
AND ISNULL(field,'') LIKE
CASE WHEN #val = 1 THEN
'%'
ELSE
'N'
END

SQL Case statement with 'or' and 'and'

Can I use a case statement as follows?
CASE
WHEN (condition1 = 1 or 2)
AND condition2 = 3
THEN result = 'Result'
ELSE
NULL
END
Conditions 1 and 2 will be looking for different values, just fyi.
If not, is there a better way to write this?
Thank you!
Would this work?
CASE WHEN condition1 in (1, 2) AND condition2 = 3
THEN 'Result'
ELSE NULL
END
AS result
Well it depends on the system you are using. For example if you use Oracle and PL/SQL you can check the statement here
http://www.techonthenet.com/oracle/functions/case.php
What DB are you using? And do you want the statement in SQL or in some other kind of code or stored procedure?
I'm not sure what you want to do with the statement. In a select statement, it would be:
SELECT (CASE WHEN (condition1 = 1 or 2) AND condition2 = 3
THEN 'Result'
END) as result
You don't need the else because NULL is returned by the statement automatically if none of the when conditions are met.
In a where, it would be:
WHERE (condition1 = 1 or 2) AND (condition2 = 3) AND (result = 'Result')
The else condition is equivalent to false.

CASE equivalent of a nested IIF statement

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