Building Dynamic Query Using Case in Where Clause - sql

I have a stored procedure and I want implement the following query using Case Statement , but I am not sure how to do it .
pseudocode of what I want is provided here :
declare #PI_X decimal(18);
declare #PI_y decimal (18);
SELECT F1, F2,F3
FROM TABLE T
WHERE
CASE
WHEN #PI_X IS NULL THEN #PI_Y = T.Y
WHEN #PI_Y IS NULL THEN #PI_X = T.X
It seems that using case statement for conditions is not true and its for values.
NOTE:
I want to run this query in DB2 and SQL server , but really Data Base vendor is not important for me ,using sql dynamic query and (OR) in where clause has a performance hit . and I don't want it. I really like to know how it's possible to achieve such a logic using case in where clause.
Could you please help me to handle this problem . Any help and suggestions would be so appreciated .

The result of a CASE expression is a value, not an expression. You can't use a CASE expression to decide which code will run. You can only use it to choose what value will be used with your code.
In this case, you can accomplish your goal like this:
declare #PI_X decimal(18);
declare #PI_y decimal (18);
SELECT F1, F2,F3
FROM TABLE T
WHERE 1 =
CASE
WHEN #PI_X IS NULL AND #PI_Y = T.Y THEN 1
WHEN #PI_X IS NOT NULL AND #PI_Y IS NULL AND #PI_X = T.X THEN 1
ELSE 0 END
You could also try it like this:
declare #PI_X decimal(18);
declare #PI_y decimal (18);
SELECT F1, F2,F3
FROM TABLE T
WHERE coalesce(#PI_X, T.X) = T.X AND coalesce(#PI_y, T.Y) = T.Y
Though this second option might produce unexpected results if #PI_y might be something other than NULL when #PI_x has a value. If you can guarantee one or the other of the two variables will have a value, but never both, then you could also simplify the first option to remove the extra #PI_X IS NOT NULL AND part of the expression.

I'm not sure why your question is tagged with both SQL Server AND DB2... But I'll assume SQL Server...
declare #PI_X decimal(18);
declare #PI_y decimal (18);
SELECT
T.F1,
T.F2,
T.F3
FROM
TABLE T
WHERE
(#PI_X = T.X OR #PI_X IS NULL)
AND ((#PI_y = T.Y OR #PI_y IS NULL)
OPTION (RECOMPILE); -- Prevent's the forced scan operation cause by the use of "optional" parameters.

You can try out putting the if condition which will be readable however increasing the lines of code.
if(#PI_X IS NULL)
begin
select
....
where
T.Y=#PI_Y
end
else
begin
select
....
where
T.X = #PI_X
end

Instead of using an OR in the WHERE clause you could also build 2 separate queries and use IF...ELSE... to decide which one to use; something along the lines of what Coder1991 suggested. Or you could use a UNION ALL construction to avoid the IF and eliminate any branching.
SELECT F1, F2,F3
FROM TABLE T
WHERE #PI_X IS NULL
AND #PI_Y = T.Y
UNION ALL
SELECT F1, F2,F3
FROM TABLE T
WHERE #PI_Y IS NULL
AND #PI_X = T.X

Related

Using the LIKE operator and "greater than" in a Case When expression

This is for a section in a unit test that I'm writing.
I am trying to say pass if any row in a column contains a certain string. So in words, what I want is "if the number of row that contain astring is greater than zero than pass the test".
I have something like the code below, but it fails saying that myVariable needs to be declared. What am I doing wrong?
DECLARE #myVariable BIT =
(
SELECT CASE
WHEN Count(Description) LIKE '%astring%' > 0
THEN
1
ELSE
0
END
FROM TABLE
SELECT #myVariable
I think you want:
DECLARE #myVariable BIT =
(SELECT (CASE WHEN Count(*) > 0 THEN 1 ELSE 0 END)
FROM TABLE
WHERE Description LIKE '%astring%'
);
I wouldn't recommend a bit for this. SQL Server doesn't really support booleans. Integers (or tinyints even) are usually easier to work with than bits.
Just:
DECLARE #myVariable BIT = (
SELECT MAX(CASE WHEN Description LIKE '%astring%' THEN 1 ELSE 0 END)
FROM mytable
);
This sets the variable to 1 if at least one row in the table has a Description that matches the pattern.
DECLARE #myVariable BIT=
(
SELECT IIF(ISNULL(count(*),0)>0,1,0)
FROM TABLE
WHERE EXISTS(SELECT * FROM TABLE WHERE Description LIKE '%astring%')
)
SELECT #myVariable AS myVariable

Why doesn't the Select statement assigns an empty string or null value if it doesn't return a result?

I have the following code:
declare #testValue nvarchar(50) = 'TEST';
select #testValue = 'NOTUSED' where 1 > 2;
select #testValue; -- Outputs 'TEST'
select #testValue = 'USED' where 2 > 1;
select #testValue; -- Outputs 'USED'
With the above, the first assignment is never used because the where clause fails. The second one is done properly and used is returned.
Why doesn't SQL return a null in this case and assigns a NULL value to #testValue after the first assignment where the where clause fails?
This is the expected behavior:
"If the SELECT statement returns no rows, the variable retains its present value. If expression is a scalar subquery that returns no value, the variable is set to NULL."
https://msdn.microsoft.com/en-us/library/ms187330.aspx
You can get around this in your example by using a subquery in the right side.
SELECT #testValue = (SELECT 'NOTUSED' where 1 > 2);
As for why it is this way, I cannot say for certain. Perhaps the entire #testValue = 'NOTUSED' is equating to NULL instead of only the right side 'NOTUSED' portion of the statement, and this prevents the parameter from being set. Not directly related but I can say it took me some time to grow confident with writing queries when NULLs are involved. You need to be aware of / familiar with the ANSI NULL spec and associated behavior.
This is the default behavior of SELECT.
When assigning a value to a variable using SELECT, if there is no value returned, SELECT will not make the assignment at all so the variable's value will not be changed.
On the other hand, SET will assign NULL to the variable if there is no value returned.
For more info
NULL is the ideal value you would like but the SQL engine is not clever enough, because some else may want empty string , ' ' in that situation or 0 or 1, you see. So no single default value is set. Best is set your own default value. You can see below
DECLARE #testValue NVARCHAR(50) = 'TEST';
SELECT #testValue = 'NOTUSED' WHERE 2 > 1;
IF 2 <> 1
SELECT #testValue = NULL;
SELECT #testValue; -- Outputs 'TEST'
SELECT #testValue = 'USED' WHERE 1 > 2;
SELECT #testValue; -- Outputs 'USED'
NULL in SQL is used to denote missing data or an unknown value. In this case the data is not missing, the value of #testValue is known, it is just failing an assignment condition, so it gets no new value.
If you were to change your initial assignment to be like this
declare #testValue nvarchar(50)
You would get NULL like below :
select #testValue = 'NOTUSED' where 1 > 2;
select #testValue; -- Outputs NULL
select #testValue = 'USED' where 2 > 1;
select #testValue; -- Outputs 'USED'
Don't be too disappointed your not getting NULL back in the your example. NULL is not easy to handle.
For example, you can not compare two NULL values, because instances of NULL are not equal. Consequently you also need to use special operators like ISNULL to check for it.
In general, NULL as a programming construct should be avoided in my opinion. This is a bit of area of contention across the programming languages. But consdier this, even the creator of null Tony Hoare, calls the creation of null his 'billion dollar mistake'.

Comparing 2 variables in SQL stored procedure where 1 of them could be NULL [duplicate]

I must to check if two values, X and Y are different. If both are null, they must be considered as equal.
The unique way I found is:
select 1 as valueExists
where (#X is null and #Y is not null)
or (#Y is null and #X is not null)
or (#X <> #Y)
Is there a smart way to write this expression?
Thanks!
I think you could use COALESCE for that
WHERE coalesce(#X, '') <> coalesce(#Y, '')
What it does it returns an empty string if one of variables is null, so if two variables are null the two empty strings become equal.
I typically use a technique I picked up from here
SELECT 1 AS valuesDifferent
WHERE EXISTS (SELECT #X
EXCEPT
SELECT #Y)
WHERE EXISTS returns true if the sub query it contains returns a row. This will happen in this case if the two values are distinct. null is treated as a distinct value for the purposes of this operation.
You could try using NULLIF like this:
WHERE NULLIF(#X,#Y) IS NOT NULL OR NULLIF(#Y,#X) IS NOT NULL
You can use ISNULL
WHERE ISNULL(#X,'') <> ISNULL(#Y,'')

SELECT statement having where clause with dynamic condition

I have a small select query which picks data from a table as per the parameter passed to a procedure.
DECLARE #flgParam bit
.
.
SELECT *
FROM tablename
WHERE flgRequired like <If #flgparam is 0 then 1 or zero , Else 1>
what is the best way to construct the where clause
I'm thinking something like this:
SELECT *
from tablename
where #flgparam is null or #flgcolumnval = #flgparam;
#flgparam is declared as a bit, so it can only take on the values of NULL, 0, and 1.
EDIT:
I'm trying to understand the logic. Adapted for the right names:
SELECT *
from sample
where (#flgparam = 0 and flgRequired is not null) or
(coalesce(#flgparam, 1) = 1 and flgRequired = 1)
The like is unnecessary; you can do strict equality.
A bit rough, but it should work, based on requirements:
select
S.itemname
,S.flgrequired
from
sample S
where
(S.flgRequired >= #flgParam)
Tested on sqlfiddle.
You cant use variables to substitute columns in the querys, to achieve that you should create your query as a string #QUERY and execute it using exec #QUERY

Select a column if other column is null

I need to select a field called ProgramID from a table and if the ProgramID is NULL then I need to select the value in the InterimProgramID from the same table and alias it as ProgramID.
How can I make a conditional SELECT statement to do this?
You need the ISNULL function.
SELECT ISNULL(a, b)
b gets selected if a is null.
Also, you can use the WHEN/THEN select option, lookup in BOL. Essentially: its c switch/case block meets SQL.
select COALESCE ( ProgramID , InterimProgramID ) as 'ProgramID'
You can use either the ISNULL function or the COALESCE function. They both do pretty much the same thing, however ISNULL only takes two parameters and COALESCE takes multiple parameters (returning the first non-null it encounters). Both try the first param, then the second, (and COALESCE continues on)
DECLARE #IAMNULL VARCHAR
DECLARE #IAMNOTNULL VARCHAR
SET #IAMNOTNULL = 'NOT NULL'
SELECT ISNULL(#IAMNULL, #IAMNOTNULL)
--Output: 'NOT NULL'
DECLARE #IAMNULLALSO VARCHAR
SELECT COALESCE(#IAMNULL, #IAMNULLALSO, #IAMNOTNULL)
--Output: 'NOT NULL'
SELECT ProgramID
FROM a_table
WHERE ProgramID IS NOT NULL
UNION
SELECT InterimProgramID AS ProgramID
FROM a_table
WHERE ProgramID IS NULL;
Coalesce('zzz-' + ProgramID, InterimID) as programID will still ignore ProgramID even if you have a pretext value. It's a cool little function
There is also:
Select NVL(Column_A, Column_B) From 'schema'.'table_name'
The NVL( ) function is available in Oracle, and not in MySQL or SQL Server. This function is used to replace NULL value with another value. It is similar to the IFNULL Function in MySQL and the ISNULL Function in SQL Server.
https://www.1keydata.com/sql/sql-nvl.html
You can also use IFNULL function
select IFNULL(ProgramId,interimId) as ProgramId