Setting BIT variable using CASE statements - sql

I'm in the middle of a migration that uses some reporting elements from Crystal and attempting to convert what existed previously into SQL. It looks to use VB scripting but I can't figure out how to make the switch over.
Initially I'd assume a CASE WHEN statement would suffice but I can't determine the right logic behind the query.
Sample of the VB below:
Dim HasValue As Boolean
If isnull({Reference.Shallow}) Then
HasValue=False
formula="MISSING"
Else
HasValue=True
End If
I am aware that IF does exist in SQL Server but when researching it, people tend to stray away from it as CASE WHEN does the same?
I have some psuedo that I'd imagine should work in the same way but this does not resolve as you cannot set a variable within a CASE WHEN statement (I believe):
DECLARE HasValue BIT
CASE WHEN Reference.Shallow IS NULL
THEN SET #HasValue = 1
ELSE SET #HasValue = 0
END AS Shallow
What would be the most appropriate way of doing this within SQL?

You must use this code snippet
DECLARE #HasValue BIT
SELECT #HasValue=CASE WHEN Shallow IS NULL THEN CAST(1 AS BIT) ELSE CAST(0 AS
BIT) END FROM Reference.Shallow

CASE returns a scalar value, not a operation or boolean result. You set the value of the variable to the result of the CASE:
SET #HasValue = (SELECT CASE WHEN R.Shallow IS NULL THEN 1 ELSE 0 END
FROM dbo.Reference R
/*WHERE...? */);

Related

SQL CASE statement needs to handle Text

Apologies if this has been asked before - I've spent a couple of hours searching but not found anything that's helped.
It's quite simple really - I've been asked to create a query which includes a field that when it was set up (not by me) was created as a VARCHAR instead of an INT.
I need to do some calculations on this field, however some users have been entering text into it, so the calculations fail as it can't convert the data to an INT.
Is there anything I can add to a CASE statement to handle where there's text?
I was thinking something like the below, but don't know what the actual code is:
CASE
WHEN [Field1] IS TEXT THEN 1 ;
ELSE [Field2] as [Chose name]
END
Edit: Note that this is in MS SQL Server.
Thanks.
In SQL Server, you can use try_convert() and isnull() for this:
isnull(try_convert(int, field), 1)
try_convert() attempts you cast field to an int. When that fails, null is returned; you can trap that with isnull() and turn the result to 1 instead.
Note that this only works as long as field is not null (otherwise, you would get 1 as a result).
In SQL Server
Declare #Salary varchar(100);
Set #Salary = 50000;
Select Case when ISNUMERIC(#Salary) = 1 then 1
else 0 end as [Check]
May be this will be Helpful.

Defining the (alias) name of a field

I've been looking over some code in an old Classic ASP system of ours that builds its own SQL within the stored procedure and then executes it {shudders}.
Several of the SELECTion lines contain an assignment, similar to:
SELECT
my_field = CASE WHEN value = whatever THEN 1 ELSE 0 END
...
Is there any difference (or anything I need to be aware of) between this and using a standard AS alias?...
SELECT
CASE WHEN value = whatever THEN 1 ELSE 0 END AS my_field
...
No, the following code is all synonymous:
SELECT one = 1;
SELECT 1 one;
SELECT 1 AS one;
SELECT 'one' = 1; --this is deprecated, don't use it.
Which you use (apart from the last), is normally down the preference. Personally, I use AS. One reason is I can then easily tell queries that return datasets, and those that assign values to variables a part.
The 2 examples that you have given are identical. However, when you go through the old code you might also find a variant with an # sign before my_field, like this:
SELECT
#my_field = CASE WHEN value = whatever THEN 1 ELSE 0 END
In this case a varable called #my_field is assigned a value, but nothing is SELECTed. This you can not rewrite to the other syntax using AS #myfield.

SQL Where statement with CASE variable

Im sorry I do not have a complete query because my original is actually very long but I feel you may be able to spot where I have an error in my syntax. Basically I declare 2 variables and if one variable is blank I need the where statement to be where the field is not in the other variable.
Where dnCP_FromServiceDate >= '01/01/2016' And
dnCP_FromServiceDate <= '01/31/2016' And
dnCP_RecordStatus <> 'V'
AND CASE WHEN #inpDXIN = '' THEN
predxDiagnosisCode not in (#inpDXNOTIN)
ELSE predxDiagnosisCode IN (#inpDXIN)
END
Even if I could get a snippet of a query using a similar statement i can figure mine out but i cant find anything similar. Any help is greatly appreciated
In general, you don't want to use case in a where clause. Instead, just use regular boolean logic:
Where dnCP_FromServiceDate >= '2016-01-01' and
dnCP_FromServiceDate <= '2016-01-31' and
dnCP_RecordStatus <> 'V' and
( (#inpDXIN = '' and predxDiagnosisCode <> #inpDXNOTIN) or
(#inpDXIN <> '' and predxDiagnosisCode IN (#inpDXIN)
)
Notes:
Use ISO/ANSI standard date formats. Much less ambiguous.
IN (#var) is the same as = #var. You cannot pass an in list through a variable. If you need that functionality, then ask another question.
Most dialects of SQL do not allow boolean expressions to be returned from a case. The above gets around this "limitation".

db2 stored procedure if else variable comparison

I am trying to compare a variable in db 2 sp using like, however it always goes to the else part of the statement, can someone correct the syntax here..here is the part of the code
do
IF(#variable like '%abc') THEN
set #anotherVariable='abc';
ELSEIF (#variable like '%def') THEN
set #anotherVariable='def';
ELSEIF (#variable like '%def') THEN
set #anotherVariable='def';
ELSE
set #anotherVariable='xyz';
END IF;
END FOR;
This code is part of a cursor, query always returns 1 value, however my comparison is not working(incorrect syntax?), it always goes to the last else as if it never was able to match. I know that value is there but its not comparing in this manner...Thanks
Are you writing SQL-PL code? Because variables are referenced directly by its name, not preceded by the '#' sign.
Another thing is that you are using the like operator outside a query. 'Like' is not a function, it is a predicate: http://pic.dhe.ibm.com/infocenter/db2luw/v10r5/topic/com.ibm.db2.luw.sql.ref.doc/doc/r0000751.html
Instead, you can use a 'case' in the select and then return the corresponding value. In that way you do not need to do an 'if-else': http://pic.dhe.ibm.com/infocenter/db2luw/v10r5/topic/com.ibm.db2.luw.sql.ref.doc/doc/r0023458.html

SQL Server 2008 - Conditional Query

SQL is not one of my strong suits. I have a SQL Server 2008 database. This database has a stored procedure that takes in eight int parameters. For the sake of keeping this question focused, I will use one of these parameters for reference:
#isActive int
Each of these int parameters will be -1, 0, or 1. -1 means "Unknown" or "Don't Care". Basically, I need to query a table such that if the int parameter is NOT -1, I need to consider it in my WHERE clause. Because there are eight int parameters, an IF-ELSE statement does not seem like a good idea. At the same time, I do not know how else to do this?
Is there an elegant way in SQL to add a WHERE conditional if a parameter does NOT equal a value?
Thank you!
best source for dynamic search conditions:
Dynamic Search Conditions in T-SQL by Erland Sommarskog
there are a lot of subtle implications on how you do this as to if an index can be used or not. If you are on the proper release of SQL Server 2008 you can just add OPTION (RECOMPILE) to the query and the local variable's value at run time is used for the optimizations.
Consider this, OPTION (RECOMPILE) will take this code (where no index can be used with this mess of ORs):
WHERE
(#search1 IS NULL or Column1=#Search1)
AND (#search2 IS NULL or Column2=#Search2)
AND (#search3 IS NULL or Column3=#Search3)
and optimize it at run time to be (provided that only #Search2 was passed in with a value):
WHERE
Column2=#Search2
and an index can be used (if you have one defined on Column2)
WHERE coalesce(active,1) = (CASE
WHEN #isActive = -1 THEN coalesce(active,1)
ELSE #isActive
END)
Rather than using -1 to signify that you don't know or don't care, how about just using Null for that? Pretty much what it was made for. Then you could switch to a Bit rather than an Int.
Also, I'm sure TomTom will disagree, but I think using a CASE statement is the way to go for this stuff.
Your mileage may vary, but it seems that the query engine handles it a lot better than wrapping things in IsNull or having multiple OR statements, which can get rather messy as you start adding other conditions.
No matter which way you go, the execution plan is going to suffer a little bit depending on what you're passing in, but it shouldn't be TOO horrible.
The extra benefit of going with CASE statements is that you can add a bit of complexity without much extra code (versus going with a bunch of OR statements). Also, the first condition to match your criteria can prevent the extra evaluations, which isn't always the case when dealing with OR's...
So, for 8 optional parameters with -1 as the value use to ignore the search, what you end up with is something along the lines of:
WHERE
#Search1 = CASE WHEN #Search1 = -1 THEN #Search1 ELSE #Column1 END
AND #Search2 = CASE WHEN #Search2 = -1 THEN #Search1 ELSE #Column2 END
AND #Search3 = CASE WHEN #Search3 = -1 THEN #Search1 ELSE #Column3 END
AND #Search4 = CASE WHEN #Search4 = -1 THEN #Search1 ELSE #Column4 END
AND #Search5 = CASE WHEN #Search5 = -1 THEN #Search1 ELSE #Column5 END
AND #Search6 = CASE WHEN #Search6 = -1 THEN #Search1 ELSE #Column6 END
AND #Search7 = CASE WHEN #Search7 = -1 THEN #Search1 ELSE #Column7 END
AND #Search8 = CASE WHEN #Search8 = -1 THEN #Search1 ELSE #Column8 END
NOTE: As KM pointed out, the NULL method falls short if the columns you're working will can potentially have NULL values, since NULL=NULL won't evaluate properly. So, for fun, I changed my answer back to what the original poster requested, which is to use their own identifier for skipping the search.
The pattern (column = #param OR #param IS NULL) will give you optional parameters. You can use NULLIF to neutralize your -1. Even better would be to allow null parameters, instead of using a magic number.
WHERE
(Customer.IsActive = NULLIF(#isActive, -1) OR NULLIF(#isActive, -1) IS NULL)
.... Where field=case #isActive WHEN -1 THEN field ELSE #isActive END ....
There is NOT an elegant way - all ways suck.
WHERE #isActive == -1 OR isActive = #isActive
is basically the only way - but even then you please make sure that the query plan is reevaluated every time, otherwise most queries will use the wrong query plan.
THis is a classical case where stored procedures are bad. Querying should IMHO not be done using stored procedures at all since modern times - which started about 15 years ago when someone was smart enough to write the first ORM.