SQL Server中的条件WHERE子句

59 sql t-sql sql-server where-clause sql-server-2008

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

它应该是这样的:

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
Run Code Online (Sandbox Code Playgroud)

以上查询无效.这不是正确的语法,还是有其他方法可以做到这一点,我不知道?

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

Mah*_*esh 72

试试这个

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)
    )
Run Code Online (Sandbox Code Playgroud)

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

  • 随着表的增长,您将希望观察最终查询的性能,因为优化器可能会对这些类型的查询感到非常不满意. (4认同)
  • 您可以使用“@JobsOnHold IS NULL”或“IS NOT NULL”代替“(ISNULL(@JobsOnHold, 0) = 1” (2认同)
  • @shaijut 这类事情往往表明需要不同的方法。考虑专门为手头的查询提供服务的物化视图,或者,如果您有灵活性,可以考虑将数据复制到单独区域的方法,从而为读取端提供更多选项(例如 CQRS)。 (2认同)

Dev*_*art 25

试试这个 -

WHERE DateDropped = 0
    AND (
        (ISNULL(@JobsOnHold, 0) = 1 AND DateAppr >= 0) 
        OR 
        (ISNULL(@JobsOnHold, 0) != 1 AND DateAppr != 0)
    )
Run Code Online (Sandbox Code Playgroud)

  • OP已经改变了代码 - 一个不那么微不足道的变化 - 并使我们的答案看起来相当愚蠢:) (2认同)

Bac*_*its 11

要回答如何在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'
Run Code Online (Sandbox Code Playgroud)

请注意,左边的CASE表达式如何将布尔表达式转换为'True' = 'True'或者'False' = 'True'.

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

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


ype*_*eᵀᴹ 7

您的查询的问题在于,在CASE表达式中,THENELSE部分必须具有一个表达式,该表达式的计算结果为数字或varchar或任何其他数据类型,但不是布尔值.

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

WHERE 
    DateDropped = 0
AND ( @JobsOnHold = 1 AND DateAppr >= 0 
   OR (@JobsOnHold <> 1 OR @JobsOnHold IS NULL) AND DateAppr <> 0
    )
Run Code Online (Sandbox Code Playgroud)

  • 不确定你在问什么.那里的问题/答案是关于短路的.你真的不应该担心 - 除非你有一些性能问题. (2认同)

wez*_*zix 6

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

在此示例中,它可能不会产生太大差异,但假设该条件仅应在两种情况之一中使用,那么您可能会注意到很大的影响。

在这个例子中:

WHERE 
    DateDropped = 0
    AND (
    (ISNULL(@JobsOnHold, 0) = 1 AND DateAppr >= 0) 
    OR 
    (ISNULL(@JobsOnHold, 0) <> 1 AND DateAppr <> 0)
    )
OPTION (RECOMPILE)
Run Code Online (Sandbox Code Playgroud)

参数嗅探、嵌入和 RECOMPILE 选项