【问题标题】:Using SQL Server CASE statement in WHERE在 WHERE 中使用 SQL Server CASE 语句
【发布时间】:2018-07-23 13:36:04
【问题描述】:

我想从存储过程中的表中选择记录。给定的参数可以是空的,也可以是包含一些用逗号分隔的键(1、2 等)的字符串 我想管理当参数为空字符串时,“WHERE”忽略搜索。 我正在使用此代码:

where (CASE when @PatientID <> 0 then ( dental.ID_Sick in (1,2)) else (1=1) end)

类似的东西正在 W3School 中工作。我的意思是:

SELECT * FROM Customers
WHERE (case when 1=1 then (Country IN ('Germany', 'France', 'UK')) else 1=1 end);

我的查询中有什么问题不起作用? SQLServerManagementStudio 在“IN”语句中给出错误。

【问题讨论】:

  • 在 WHERE 子句中使用 AND/OR 结构而不是 case 表达式通常会更好。
  • @jarlh 怎么办?
  • 参考这个,类似的问题在这里解释。 stackoverflow.com/questions/11232267/…
  • @Shaho 不要。 “动态”过滤器会导致错误的执行计划。如果您不想想要使用@PatientID 参数,不要使用@PatientID 参数。 不要创建这样的catch-all 存储过程。如果您需要使用不同的参数,请使用像 EF 和 LINQ 这样的 ORM
  • 当前语法的问题是没有布尔结果。 CASE 表达式只是硬币的一面。这不是CASE 声明,这是您理解错误的地方。 CASE i WHEN 1 then 'Left' ELSE 'Right' END = 'Right' 将是 WHERE 的布尔结果。您不要将布尔逻辑放在 WHEN/ELSE 旁边。

标签: sql sql-server tsql case where


【解决方案1】:

如下重写你的语句会更好阅读:

WHERE @PatientID = 0 
OR dental.ID_Sick in (1,2)

关于您的实际问题,我建议您阅读B House 提供的链接问题。

【讨论】:

  • 最好不要使用@PatientID 参数。这样的catch all 查询会导致错误的执行计划
  • @PanagiotisKanavos 没错,但这取决于 Shaho 使用的工具。例如。 SSRS 或 C#。他可能是在学习 t-sql 的概念,而不是在构建实际的生产工具。
  • 但你回答的逻辑不是我的目标......我在那个 select 语句中还有一些其他过滤器要做。
  • @Shaho 使用 CASE 语句并没有比(嵌套的)AND/OR 结构给您更多的可能性。两者都基于逻辑 IF this THEN that,其中 this 和 that 是某些语句的布尔结果。
  • @Shaho 它回答了上述问题。
【解决方案2】:

试试这个:

    WHERE 1=(CASE WHEN @PatientID <>0 AND dental.ID_Sick in (1,2) THEN 1
            WHEN @PatientID =0 THEN 1
            ELSE 0
            END)

【讨论】:

    【解决方案3】:

    SQL Server 没有Bool 数据类型,因此您不能像在其他语言中那样将比较结果分配或返回为Bool。比较只能与 IF-statements 或 WHERE-clauses 一起使用,或者在 CASE...WHEN 的 WHEN 部分中使用,但不能在其他任何地方使用。

    你的具体例子会变成这样:

    SELECT * FROM Customers
    WHERE 1=1 OR Country IN ('Germany', 'France', 'UK')
    

    【讨论】:

    • 几乎没有数据库具有bool 数据类型。我怀疑单个异常 Postgresql 也不允许在逻辑操作中使用返回值。你会用空值做什么?与truefalseNULL 相比可能
    【解决方案4】:

    也许这条直接的方法对你有用

    IF (@PatientID <> 0)
        BEGIN
           SELECT * FROM Customers
           WHERE Country IN ('Germany', 'France', 'UK')
        END
    

    【讨论】:

      【解决方案5】:

      解决方案:

      处理此类可选参数的最佳方法是使用动态 SQL 并动态构建查询。有点像....

      CREATE PROCEDURE myProc
       @Param1    VARCHAR(100)    = NULL
      ,@Param2    VARCHAR(100)    = NULL
      ,@Param3    VARCHAR(100)    = NULL
      ,@ListParam VARCHAR(100)    = NULL
      --, etc etc...
      AS
      BEGIN
          SET NOCOUNT ON;
          Declare @Sql NVARCHAR(MAX);
      
      SET @Sql = N'   SELECT * 
                      FROM TableName
                      WHERE 1 = 1 '
      
      -- add in where clause only if a value was passed to parameter
              +  CASE WHEN @Param1 IS NOT NULL THEN 
                 N' AND SomeColumn = @Param1 ' ELSE N'' END
      
      -- add in where clause a different variable 
      -- only if a value was passed to different parameter
      
              +  CASE WHEN @Param2 IS NOT NULL THEN 
                 N' AND SomeOtherColumn = @Param3 ' ELSE N'' END
      
      -- List Parameter used with IN clause if a value is passed
      
              +  CASE WHEN @ListParam IS NOT NULL THEN 
                 N' AND SomeOtherColumn IN (
                                           SELECT  Split.a.value(''.'', ''VARCHAR(100)'') IDs
                                            FROM (
                                                   SELECT Cast (''<X>'' 
                                                                + Replace(@ListParam, '','', ''</X><X>'') 
                                                                + ''</X>'' AS XML) AS Data
                                                    ) AS t CROSS APPLY Data.nodes (''/X'') AS Split(a)  ' 
                  ELSE N'' END
      
      Exec sp_executesql    @sql 
                          , N' @Param1 VARCHAR(100), @Param2 VARCHAR(100) ,@Param3 VARCHAR(100) ,@ListParam VARCHAR(100)'
                          , @Param1 
                          , @Param2 
                           ,@Param3 
                          , @ListParam 
      
      
      END
      

      其他方法的问题

      这种其他方法存在一个主要问题,您将 where 子句编写为...

      WHERE ( ColumnName = @Parameter  OR @Parameter IS NULL)
      

      这种方法的两个主要问题

      1) 您不能强制 SQL Server 像 if @Parameter IS NULL 那样先检查表达式的求值,Sql Server 可能会决定先求值表达式 ColumnName = @Parameter,因此即使变量值为 null,您也会对 where 子句进行求值。

      2) SQL Server 不做短路处理(如 C#),即使它决定先检查 @Parameter IS NULL 表达式,即使它的计算结果为 true,SQL Server 仍然可以继续计算 @ 中的其他表达式987654326@ 子句。

      因此,对于这样的查询,请坚持使用 Dynamic Sql。和快乐的日子。

      【讨论】:

        猜你喜欢
        • 2021-08-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-06-30
        • 2013-12-06
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多