76

我正在创建一个需要条件where子句的 SQL 查询。

它应该是这样的:

SELECT 
    DateAppr,
    TimeAppr,
    TAT,
    LaserLTR,
    Permit,
    LtrPrinter,
    JobName,
    JobNumber,
    JobDesc,
    ActQty,
    (ActQty-LtrPrinted) AS L,
    (ActQty-QtyInserted) AS M,
    ((ActQty-LtrPrinted)-(ActQty-QtyInserted)) AS N
FROM 
    [test].[dbo].[MM]
WHERE 
    DateDropped = 0
            --This is where i need the conditional clause 
    AND CASE
            WHEN @JobsOnHold = 1 THEN DateAppr >=  0
            ELSE  DateAppr != 0
        END

上面的查询不起作用。这不是正确的语法还是我不知道的另一种方法?

我不想使用动态 SQL,所以有没有其他方法或者我必须使用解决方法,例如使用和使用具有不同子句if else的相同查询?where

4

6 回答 6

98

尝试这个

SELECT 
    DateAppr,
    TimeAppr,
    TAT,
    LaserLTR,
    Permit,
    LtrPrinter,
    JobName,
    JobNumber,
    JobDesc,
    ActQty,
    (ActQty-LtrPrinted) AS L,
    (ActQty-QtyInserted) AS M,
    ((ActQty-LtrPrinted)-(ActQty-QtyInserted)) AS N
FROM 
    [test].[dbo].[MM]
WHERE 
    DateDropped = 0
    AND (
    (ISNULL(@JobsOnHold, 0) = 1 AND DateAppr >= 0) 
    OR 
    (ISNULL(@JobsOnHold, 0) != 1 AND DateAppr != 0)
    )

您可以在此处阅读有关条件 WHERE 的更多信息。

于 2013-09-05T07:01:03.700 回答
26

试试这个——

WHERE DateDropped = 0
    AND (
        (ISNULL(@JobsOnHold, 0) = 1 AND DateAppr >= 0) 
        OR 
        (ISNULL(@JobsOnHold, 0) != 1 AND DateAppr != 0)
    )
于 2013-09-05T06:29:09.670 回答
13

要回答如何在 WHERE 子句中使用 CASE 表达式的基本问题:

首先要记住,CASE 表达式的值必须是普通数据类型值,而不是布尔值。它必须是 varchar 或 int 或其他东西。这与您不能说SELECT Name, 76 = Age FROM [...]并期望进入'Frank', FALSE结果集中的原因相同。

此外,WHERE 子句中的所有表达式都需要有一个布尔值。它们不能具有 varchar 或 int 的值。你不能说WHERE Name;WHERE 'Frank';。您必须使用比较运算符使其成为布尔表达式,所以WHERE Name = 'Frank';

这意味着 CASE 表达式必须位于布尔表达式的一侧。您必须将 CASE 表达式与某些东西进行比较。它不能自立!

这里:

WHERE 
    DateDropped = 0
    AND CASE
            WHEN @JobsOnHold  = 1 AND DateAppr >= 0 THEN 'True'
            WHEN DateAppr != 0 THEN 'True'
            ELSE 'False'
        END = 'True'

请注意,左侧的 CASE 表达式最终如何将布尔表达式转换为'True' = 'True'or 'False' = 'True'

'False'请注意, and没有什么特别之处'True'。如果你愿意,0你也可以使用。1

您通常可以将 CASE 表达式重写为我们更熟悉的布尔表达式,这通常对性能更好。但是,有时使用现有表达式比转换逻辑更容易或更易于维护。

于 2015-09-02T14:01:00.653 回答
7

您的查询的问题在于,在CASE表达式中,THENandELSE部分必须有一个表达式,该表达式可以计算为数字或 varchar 或任何其他数据类型,但不能计算为布尔值。

您只需要使用布尔逻辑(或者更确切地说是 SQL 使用的三元逻辑)并重写它:

WHERE 
    DateDropped = 0
AND ( @JobsOnHold = 1 AND DateAppr >= 0 
   OR (@JobsOnHold <> 1 OR @JobsOnHold IS NULL) AND DateAppr <> 0
    )
于 2013-09-05T06:28:51.153 回答
3

通常,当您使用条件 WHERE 子句时,您最终会得到一个非常低效的查询,这对于使用索引的大型数据集是显而易见的。针对参数的不同值优化查询的一个好方法是为参数的每个值制定不同的执行计划。您可以使用OPTION (RECOMPILE).

在这个例子中,它可能不会有太大的区别,但是如果说这个条件应该只用于两种情况之一,那么你会注意到一个很大的影响。

在这个例子中:

WHERE 
    DateDropped = 0
    AND (
    (ISNULL(@JobsOnHold, 0) = 1 AND DateAppr >= 0) 
    OR 
    (ISNULL(@JobsOnHold, 0) <> 1 AND DateAppr <> 0)
    )
OPTION (RECOMPILE)

参数嗅探、嵌入和重新编译选项

于 2019-02-05T14:32:05.230 回答
1

这似乎更容易考虑可以将两个参数中的任何一个传递到存储过程的位置。它似乎工作:

SELECT * 
FROM x 
WHERE CONDITION1
AND ((@pol IS NOT NULL AND x.PolicyNo = @pol) OR (@st IS NOT NULL AND x.State = @st))
AND OTHERCONDITIONS
于 2020-11-02T14:55:55.743 回答