Building Dynamic Query Using Case in Where Clause

2019-08-18 02:38发布

问题:

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 .

回答1:

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.


回答2:

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.



回答3:

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


回答4:

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