【问题标题】:SQL - CASE expression inside WHERESQL - WHERE 中的 CASE 表达式
【发布时间】:2009-01-05 20:39:12
【问题描述】:

我在这里读到了关于在 WHERE 子句中使用 CASE 表达式的信息:

http://scottelkin.com/sql/using-a-case-statement-in-a-sql-where-clause/

我正在尝试使用它来过滤我的 select 语句中的结果,基于将由用户的应用程序传入的合同号。无论传入什么,我的代码当前都会引发“无效参数”错误。我验证 SELECT/FROM 工作正常,就像没有 CASE 表达式的 WHERE 子句一样。这是我的代码。

WHERE     (CASE WHEN @ContractNo = 0 THEN @ContractNo ELSE @ContractNo END =
tblContracts.ContractNo)

代码的冗余是出于故障排除的目的,我计划稍后在 CASE 上使用通配符过滤。我现在专注于降低语法。我相信这应该返回参数与存储在表中的合同编号匹配的所有记录。任何帮助或建议将不胜感激。

【问题讨论】:

    标签: sql where-clause


    【解决方案1】:

    您确定要这样做吗?您的案例语句总是返回@ContractNo。我认为您正在寻找的是:

    where 
        case @ContractNo 
            when 0 then tblContracts.ContractNo 
            else @ContractNo 
        end = tblContracts.ContractNo
    

    上面的过滤器说“给我ContractNo等于参数的合同,或者如果参数为0,则全部给我。

    之前的过滤器只过滤了合约编号字段与参数完全相等的地方。

    无论如何,你应该这样做:

    where @ContractNo = 0 or @ContractNo = tblContracts.ContractNo
    

    逻辑更容易理解,最重要的是(不要引用我的话),优化器可能会在 case 语句之外更好地工作。

    【讨论】:

    • 我误读了您最初 casperOne 所说的内容,对此感到抱歉。
    【解决方案2】:

    阅读您的解释后,没有CASE 有更好的方法:

    WHERE @ContractNo = 0 OR tblContracts.ContractNo = @ContractNo
    

    这将只返回匹配的合同号,除非@ContractNo 为 0,在这种情况下它将返回所有记录。

    编辑:我刚刚注意到casperOne proposed the same thing。我没看到。做大自己。

    【讨论】:

    • 非常感谢!这帮助很大
    • 既然递归解决了你的问题,你应该用绿色的大复选框“接受”他的回答。
    【解决方案3】:

    不管怎样,请尽量去掉放在错误位置的括号 - 正确的括号应该在“END”之后。

    【讨论】:

    • Parens 看起来不错。它在抱怨变量。
    • 实际上它是在抱怨一个参数,而不是一个变量。但你是对的,它可能是一个设置不正确的参数值。
    【解决方案4】:

    也许你忘了声明@ContractNo?是否可以与 0 和 tblContracts.ContractNo 相媲美?

    【讨论】:

      【解决方案5】:

      Recursive 的帖子正好解决了我的问题。

      我看到有人抱怨我的原始帖子的清晰度。将来,我可以做些什么来使我所说的更直接?我不习惯用措辞表达有关代码的问题,并为它所拥有的任何混乱的事情道歉。我是否只需要像我的第二篇文章那样提供详细信息?

      再次感谢大家的帮助。

      【讨论】:

      • 在语句中添加换行符,无需滚动即可阅读
      • 一方面,您应该将更新作为对原始问题的编辑,而不是将其作为附加解决方案发布。至于这个问题,最好使用一个不会减少到零的示例代码,和/或在原始帖子中说明您的最终目标。
      • 哦,是的,如果我的解决方案能解决您的问题,您应该“接受”它,并将其标记为已接受的解决方案。
      • 谢谢,对不起。
      【解决方案6】:

      将右括号移到 = 之前,如下所示:

      WHERE     (CASE WHEN @ContractNo = 0 THEN @ContractNo ELSE @ContractNo END)=tblContracts.ContractNo
      

      我看不到这个 case 语句会做什么......如果@ContractNo = 0 或者不是......

      正确的语法是:

        Select...
        ...
        Where(
          Case
            When <Condition>
              Then <Return if true>
              Else <Return if false>
            End
       ) = <Whatever is being matched to the output of the case statement>
      

      不管语法如何,您的示例没有多大意义,如果您要查找所有匹配或合同编号为 0 的项目,那么您会这样做:

      Select...
      ...
      Where (
        @ContractNo = 0 Or
        @ContractNo = tblContracts.ContractNo
      )
      

      这似乎比您尝试使用 case 语句更有意义。

      编辑:我一定是稍微误读了这个问题 - 缺少的参数通常意味着参数(在本例中为 @ContractNo)未在您的查询/程序范围内声明。但是有人已经指出了这一点,所以我不能为此承担任何责任。

      【讨论】:

      • 简单 CASE 和搜索 CASE 的区别。在这里阅读更多:msdn.microsoft.com/en-us/library/ms181765.aspx
      • @David B:我在这里的某个地方错过了你的观点。鉴于问题不明确,您如何确定哪个是正确的?
      • 是的,你是对的。问题不够清晰(这就是我还没有回答的原因)。然而,他的链接和他的代码显示“搜索的 CASE”,而您的语法示例显示“简单的 CASE”。
      • @David B: Simple Case is: Case When... and Searched Case is: Case When Then... 因此我对搜索的案例使用了正确的语法,我错过了什么?
      【解决方案7】:

      case语句的原因,包括整个“如果为0,则给出参数,否则,只给出参数”是为了测试它以尝试使语法正确。最初,我曾尝试说“如果它是 0,则传入 '%',以返回每个值。我在那里发布的代码是因为我不断收到 'Invalid Parameter' 并认为我的语法一定有问题。当我把它分成基本参数匹配,像这样,

      WHERE @ContractNo = tblContracts.ContractNo
      

      它返回的记录很好。让我再解释一下。

      我从一堆不同的表中提取,并使用未包含在 select 语句中的信息过滤内容(即 tblContracts 没有从 Select 中提取的信息,它仅在 Where 中使用)。用户将从一个组合框中进行选择,该组合框将具有不同的合同编号,以及默认值“全部”。

      当组合框的索引发生变化时,我将举办一个活动。如果是“全部”,0 将作为参数传入,我不希望进行任何过滤。否则,我只想要那个合同号的信息(Else @ContractNo 的原因)。

      【讨论】:

        【解决方案8】:

        你的意思不是这样吗?

        SELECT * 
            FROM tblContracts
            WHERE     
            CASE 
               WHEN tblContracts.ContractNo = 0 THEN @ContractNo 
               ELSE tblContracts.ContractNo
            END = tblContracts.ContractNo
        

        其中@ContractNo 是与 tblContracts.ContractNo 具有相同数据类型的变量

        【讨论】:

          【解决方案9】:

          为什么还需要案例陈述?

          当@ContractNo = 0 然后 ( 0 = tblContracts.ContractNo) 否则 @ContractNo 然后 (@ContractNo = tblContracts.ContractNo)

          这是没有意义的,因为你可以简单地把它写成

          其中@contractNo = tblContracts.contractNo

          【讨论】:

            【解决方案10】:

            合同编号实际上是一个数字,还是一个总是恰好是数字的字符串。检查表和参数与 CASE 语句之间的数据类型(例如,“= 0”或“= '0'”)

            【讨论】:

            • ContractNo 是一个字符串,这是一个错误。然而,当我尝试“CASE WHEN @ContractNo = 'All'”时,我也遇到了同样的问题。
            【解决方案11】:

            这种语法应该可以工作(在 Oracle 中可以)

            WHERE CASE WHEN tblContracts.ContractNo = 0 
                       THEN @ContractNo 
                       ELSE tblContracts.ContractNo
                  END = tblContracts.ContractNo
            

            【讨论】:

              【解决方案12】:

              当你说:

              我从一堆不同的表中提取,并使用未包含在 select 语句中的信息过滤内容(即 tblContracts 没有从 Select 中提取的信息,它仅在 Where 中使用)。用户将从一个组合框中进行选择,该组合框将具有不同的合同编号,以及默认值“全部”。

              那么在我看来应该有一个“在哪里存在”子句。因为您没有从该表中提取任何信息?!

              【讨论】:

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