【问题标题】:Case...When...In a WHERE CLAUSE案例...当...在 WHERE 子句中
【发布时间】:2014-02-18 15:24:46
【问题描述】:

我认为它会起作用的代码如下:

WHERE cp.OwnerId = 1
AND CASE
    WHEN [CustAccountNote] <> 'n/a' AND [CustRulesDocPath] <> 'n/a' 
    THEN (cp.NAME = 'IQRRulesLinks' OR cp.NAME = 'AccountNote')
END 
AND pp.lastupdated BETWEEN '01/01/2013' AND GETDATE()

如果 [CustAccountNote] 和 [CustRulesDocPath] 都为“n/a”,我不可避免地要做的是省略 THEN 语句中的内容。 T-SQL 不喜欢我正在做的事情。 (震惊)。

我将如何编写这个 WHERE 语句,以便如果这两个字段结果都是“n/a”,它不会运行“cp.Name = .....”?

【问题讨论】:

  • CASE 在 T-SQL 中是一个可以返回值的 表达式 - 它不能用于有条件地执行代码块/语句。

标签: sql sql-server tsql where-clause


【解决方案1】:

这样的?

WHERE cp.OwnerId = 1
  AND (    ([CustAccountNote] = 'n/a' AND [CustRulesDocPath] = 'n/a')
        or (cp.NAME = 'IQRRulesLinks' OR cp.NAME = 'AccountNote')
      )
  AND pp.lastupdated BETWEEN '01/01/2013' AND GETDATE()

所以,如果CustAccountNoteCustRulesDocPath both 都等于'n/a',那么cp.name 具有什么值并不重要。

或者,如果CustAccountNoteCustRulesDocPath 中的任何 不等于“n/a”,那么cp.name 必须是“IQRRulesLinks”或“AccountNote”。 p>

【讨论】:

  • 这个似乎可以解决问题,尽管我可能也会尝试其他的。我必须不使用 [CustAccountNote] 或 [CustRulesDocPath] 的别名,而是使用字段名称本身。我现在得到了我正在寻找的结果。谢谢大家。
【解决方案2】:

你不能完全按照你的意愿去做,因为 Case 只能返回一个值,但是你可以破解它:

WHERE cp.OwnerId = 1
AND 
(
    cp.NAME = 'IQRRulesLinks' 
    OR cp.NAME = 'AccountNote'
    Or 1 =  CASE
                WHEN [CustAccountNote] = 'n/a' AND [CustRulesDocPath] = 'n/a' Then 1
                Else 0
            End
)
AND pp.lastupdated BETWEEN '01/01/2013' AND GETDATE()

本质上,这里是说 Name 必须等于 IQRRulesLinks,或者 Name 必须等于 Name 1 必须等于由 Case 语句确定的值。当 CustAccountNote 为 n/a 或 CustRulesDocPath 为 n/a 时,该值为 1 - 有效地将整个括号内的 where 子句短路。

【讨论】:

  • 这是一个丑陋的黑客,我一直在使用。 +1。
【解决方案3】:

逻辑上,A =&gt; B 等价于(NOT A) OR B。因此,您可以按如下方式重写您的 SQL:

WHERE cp.OwnerId = 1
AND ([CustAccountNote] = 'n/a'
    OR [CustRulesDocPath] = 'n/a'
    OR cp.NAME = 'IQRRulesLinks' 
    OR cp.NAME = 'AccountNote')
AND pp.lastupdated BETWEEN '01/01/2013' AND GETDATE()

【讨论】:

  • 如果他只想显示两列 CustAccountNoteCustRulesDocPath 具有 'n/a' 的行,则会给出错误的结果
  • @Fabio:这取决于他想要什么。他的问题文本(如果两者都是 n/a,则忽略 THEN)与他的 SQL 示例不匹配(如果其中任何一个是 n/a,则忽略 THEN)。
【解决方案4】:

基于作者的要求,如果其他两个列不为 n/a,则不评估两个名称条件,此 case 语句将正确实现所请求的逻辑快捷方式,并且是我个人所知道的唯一实现方式这个任务。此外,由于名称基于两个等效比较,因此使用 IN 运算符是编写该特定段的更简单方法。

WHERE cp.OwnerId = 1
  AND (CASE
    WHEN [CustAccountNote] <> 'n/a' AND [CustRulesDocPath] <> 'n/a' 
      THEN 1
    WHEN cp.NAME IN ('IQRRulesLinks', 'AccountNote')
      THEN 1
    ELSE 0 END) = 1
  AND pp.lastupdated BETWEEN '01/01/2013' AND GETDATE()

【讨论】:

  • 大卫,感谢您的帮助。我尝试了这条路线,当我解析它时,我得到:Msg 207,Level 16,State 1,Line 31 Invalid column name 'CustAccountNote'。消息 207,级别 16,状态 1,第 31 行无效的列名称“CustRulesDocPath”。它似乎没有挖掘我的别名或其他东西。
  • @JohnWaclawski 我完全复制了您在问题中的示例。我没有像 SELECT 和 FROM 这样的查询的其余部分。我会说确保您的目标表在您的 FROM 语句中。
【解决方案5】:

尝试在WHERE 子句中使用ANDOR

WHERE cp.OwnerId = 1
AND (([CustAccountNote] <> 'n/a' AND [CustRulesDocPath] <> 'n/a' 
    AND (cp.NAME = 'IQRRulesLinks' OR cp.NAME = 'AccountNote'))
    OR 
    ([CustAccountNote] = 'n/a' AND [CustRulesDocPath] = 'n/a'))
AND pp.lastupdated BETWEEN '01/01/2013' AND GETDATE()

用样本数据检查SQL Fiddle

【讨论】:

    【解决方案6】:
    I have replaced the last part of `THEN` Statement with `Coalesce` function.
    
    
      WHERE cp.OwnerId = 1
        AND (CASE
            WHEN [CustAccountNote] <> 'n/a' AND [CustRulesDocPath] <> 'n/a'
               THEN cp.NAME = COALESCE(cp.NAME,'IQRRulesLinks', 'AccountNote')
        END )
        AND pp.lastupdated BETWEEN '01/01/2013' AND GETDATE()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多