【问题标题】:WHERE IS NULL, IS NOT NULL or NO WHERE clause depending on SQL Server parameter valueWHERE IS NULL、IS NOT NULL 或 NO WHERE 子句取决于 SQL Server 参数值
【发布时间】:2010-10-23 01:57:29
【问题描述】:

我在 SQL Server 2000 中有一个基于参数值执行搜索的存储过程。对于传入的参数之一,我需要一个不同的 WHERE 子句,具体取决于它的值 - 问题是这 3 个值将是 MyColumn

  1. IS NULL
  2. IS NOT NULL
  3. ANY VALUE (NULL AND NOT NULL)(基本上没有WHERE 子句)

我在想出正确的语法时遇到了一些心理障碍。这是否可以在一个选择语句中完成而不执行一些IF @parameter BEGIN ... END 分支?

【问题讨论】:

    标签: sql sql-server sql-server-2000


    【解决方案1】:

    以下是使用单个 WHERE 子句解决此问题的方法:

    WHERE (@myParm = value1 AND MyColumn IS NULL)
    OR  (@myParm = value2 AND MyColumn IS NOT NULL)
    OR  (@myParm = value3)
    

    CASE 语句的幼稚用法不起作用,我的意思是:

    SELECT Field1, Field2 FROM MyTable
    WHERE CASE @myParam
        WHEN value1 THEN MyColumn IS NULL
        WHEN value2 THEN MyColumn IS NOT NULL
        WHEN value3 THEN TRUE
    END
    

    可以使用 case 语句解决此问题,请参阅 onedaywhen 的 answer

    【讨论】:

    • 你的想法和我一样。但是,您确实需要括号。
    • 我不确定您是否需要括号,但我非常支持在复杂的布尔表达式中使用括号。如果你问我,没有它们让编译器来执行操作顺序,这相当可怕。
    • 我已经尝试过 CASE 语句,但 CASE 计算为一个结果表达式,因此计算为 'IS NULL'、'IS NOT NULL'、'myColumn IS NULL' 等不起作用。现在只是测试你的第一个答案
    • 我也试过了,CASE 不能这样工作。因此,我建议使用 CASE 语句来解决这个问题(见我的回答)是错误的。
    • 我没想过这样做。现在我需要去修复我的一些存储过程...谢谢
    【解决方案2】:

    你可以这样做:

    SELECT *
    FROM foo
    WHERE (@param = 0 AND MyColumn IS NULL)
    OR (@param = 1 AND MyColumn IS NOT NULL)
    OR (@param = 2)
    

    类似的东西。

    【讨论】:

    • 假设我需要按字符串过滤。如果字符串为空,我应该返回表中的所有记录,如果它不为空,我应该返回与字符串或部分字符串匹配的所有记录(LIKE 运算符)。你会怎么解决这个问题?
    【解决方案3】:

    这就是使用CASE 的方法:

    DECLARE @myParam INT;
    SET @myParam = 1;
    
    SELECT * 
      FROM MyTable
     WHERE 'T' = CASE @myParam
                 WHEN 1 THEN 
                    CASE WHEN MyColumn IS NULL THEN 'T' END
                 WHEN 2 THEN
                    CASE WHEN MyColumn IS NOT NULL THEN 'T' END
                 WHEN 3 THEN 'T' END;
    

    【讨论】:

      【解决方案4】:
      WHERE MyColumn = COALESCE(@value,MyColumn) 
      
      • 如果@valueNULL,它将比较MyColumn 与自己,忽略 @value = no where 子句。

      • 如果 @value 有一个值 (NOT NULL),它会将 MyColumn@value

      参考: COALESCE (Transact-SQL)

      【讨论】:

      • 我不相信您可以在这种情况下使用 CASE 语句,因为 CASE 评估为一个结果表达式。 COALESCE 甚至 ISNULL 我也不相信会起作用。
      • 请查看我的编辑,我是否完全遗漏了您的问题中的某些内容?
      • @Deviant - 我认为您稍微错过了这个问题。 MyColumn 上的 WHERE 子句需要由另一个值设置,因为它与参数值不直接相关,即如果传递 NULL,则 WHERE 子句被否定。如果传递了任何其他值,则结果集将仅用于 WHERE MyColumn 等于该值,而不是具有已知值的 MyColumn。未解决具有 NULL 值的 MyColumn 的 WHERE 子句。
      • 这就是使用 COALESCE 的工作方式,这不是我需要的
      • 假设我需要按字符串过滤。如果字符串为空,我应该返回表中的所有记录,如果它不为空,我应该返回与字符串或部分字符串匹配的所有记录(LIKE 运算符)。你会怎么解决这个问题?
      【解决方案5】:

      CASE的另一种方式:

      SELECT *  
      FROM MyTable
      WHERE 1 = CASE WHEN @myParm = value1 AND MyColumn IS NULL     THEN 1 
                     WHEN @myParm = value2 AND MyColumn IS NOT NULL THEN 1 
                     WHEN @myParm = value3                          THEN 1 
                END
      

      【讨论】:

        【解决方案6】:

        我在这个解决方案上取得了成功。这几乎就像帕特里克的,有点扭曲。您可以单独或按顺序使用这些表达式。如果参数为空,它将被忽略并显示您搜索的列的所有值,包括 NULLS。

        SELECT * FROM MyTable
        WHERE 
            --check to see if @param1 exists, if @param1 is blank, return all
            --records excluding filters below
        (Col1 LIKE '%' + @param1 + '%' OR @param1 = '')
        AND
            --where you want to search multiple columns using the same parameter
            --enclose the first 'OR' expression in braces and enclose the entire 
            --expression 
        ((Col2 LIKE '%' + @searchString + '%' OR Col3 LIKE '%' + @searchString + '%') OR @searchString = '')
        AND
            --if your search requires a date you could do the following
        (Cast(DateCol AS DATE) BETWEEN CAST(@dateParam AS Date) AND CAST(GETDATE() AS DATE) OR @dateParam = '')
        

        【讨论】:

          【解决方案7】:

          这种逻辑可以使用EXISTS实现:

          CREATE TABLE tab(a INT, b VARCHAR(10));
          INSERT INTO tab(a,b) VALUES(1,'a'),(1, NULL),(NULL, 'a'),(2,'b');
          

          查询:

          DECLARE @a INT;
          
          --SET @a = 1;    -- specific NOT NULL value
          --SET @a = NULL; -- NULL value
          --SET @a = -1;   -- all values
          
          SELECT *
          FROM tab t
          WHERE EXISTS(SELECT t.a INTERSECT SELECT @a UNION SELECT @a WHERE @a = '-1');
          

          db<>fiddle demo

          它可以扩展为包含多个参数:

          SELECT *
          FROM tab t
          WHERE EXISTS(SELECT t.a INTERSECT SELECT @a UNION SELECT @a WHERE @a = '-1')
            AND EXISTS(SELECT t.b INTERSECT SELECT @b UNION SELECT @a WHERE @b = '-1');
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2011-11-17
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-12-08
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多