使用Where子句中的Case构建动态查询

时间:2017-09-24 02:46:06

标签: sql sql-server query-optimization

我有一个存储过程,我想使用Case语句实现以下查询,但我不知道该怎么做。 我想要的伪代码在这里提供:

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

似乎使用条件的案例陈述不是真的,而是values

注意:

我想在DB2和SQL服务器中运行此查询,但实际上数据库供应商对我来说并不重要,使用 sql动态查询 (或)where子句有性能损失。。我不想要它。我真的很想知道如何使用where子句中的case来实现这样的逻辑。

你能帮我解决一下这个问题。 非常感谢任何帮助和建议。

4 个答案:

答案 0 :(得分:1)

我不确定为什么你的问题用SQL Server和DB2标记......但我会假设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.

答案 1 :(得分:1)

CASE表达式的结果是,而不是表达式。您不能使用CASE表达式来决定运行哪些代码。您只能使用它来选择代码使用的值。

在这种情况下,您可以像这样完成目标:

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 

你也可以这样试试:

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

如果@PI_yNULL有值时@PI_x可能不是@PI_X IS NOT NULL AND,则第二个选项可能会产生意外结果。如果您可以保证两个变量中的一个或另一个将具有值,但从不两者都有,那么您还可以简化第一个选项以删除表达式的额外const child = require("child_process"); const gutil = require("gulp-util"); gulp.task("jekyll", (done) => { let jekyll = child.spawn("jekyll", ["serve", "--incremental", "--drafts"]) .on("close", () => { done(); // let gulp know the task has completed }); let jekyllLogger = function (buffer) { buffer.toString() .split(/\n/) .forEach(function (message) { if (message) { gutil.log("Jekyll: " + message); } }); }; jekyll.stdout.on("data", jekyllLogger); jekyll.stderr.on("data", jekyllLogger) } 部分。

答案 2 :(得分:1)

您可以尝试将if条件设置为可读,但会增加代码行。

if(@PI_X IS NULL)
begin
select 
....
where 
T.Y=@PI_Y
end

else
begin
select 
....
where 
T.X = @PI_X
end

答案 3 :(得分:1)

您可以构建2个单独的查询,并使用OR来决定使用哪个查询,而不是在WHERE子句中使用IF...ELSE...;符合Coder1991建议的内容。或者您可以使用UNION ALL构造来避免IF并消除任何分支。

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