【问题标题】:SQL: Why are NULL values filtered out within this where clause?SQL:为什么在这个 where 子句中过滤掉 NULL 值?
【发布时间】:2009-03-25 21:49:11
【问题描述】:

在我的表中,我有一个可为空的位列(旧系统...),另一位开发人员最近对存储过程进行了更改,以仅显示位列不正确的值 (1)。因为这是一个可以为空的列,我们注意到如果该列是 NULL,则记录没有被拾取。为什么是这样?

我和其他开发人员都同意 NULL 1... 这是 SQL 中的错误还是这样设计的?似乎是设计缺陷。

当前代码:

(VoidedIndicator <> 1)

建议的修复:

(VoidedIndicator <> 1 OR VoidedIndicator IS NULL)

澄清(乔恩·埃里克森)

VoidedIndicator 是一个可为空的位字段,因此它可以具有以下值:NULL、0 或 1

当使用 (VoidedIndicator 1) 等 where 子句创建 SQL 语句时,我们只会返回 VoidedIndicator == 0 的记录,但我们期望 VoidedIndicator == 0 和 VoidedIndicator IS NULL。这是为什么呢?

【问题讨论】:

    标签: sql sql-server-2005 tsql


    【解决方案1】:

    很多很好的答案,但让我给你一个非常简洁的版本。

    对于 SQL,Null 并不意味着“无值”它意味着“未知值”

    考虑到这一点,请考虑用简单的英语回答您所问 SQL 的问题。

    Q: Is this unknown value not equal to 1? 
    A: I don't know, there is no way to tell without knowing the value.
    
    Hence Null<>1 = Null
    

    【讨论】:

      【解决方案2】:

      来自Wikipedia entry on NULL

      例如,WHERE 子句或 条件语句可能会比较 具有常数的列的值。这是 经常错误地假设一个 缺失值将是“小于”或 “不等于”一个常数,如果 字段包含 Null,但实际上, 此类表达式返回未知。一个 示例如下:

      -- Rows where num is NULL will not be returned,
      -- contrary to many users' expectations.
      SELECT * FROM sometable WHERE num <> 1;   
                   
      

      基本上,any NULL 和其他东西之间的比较,无论是用 = 还是 都不会是真的。

      作为另一个参考,MSDN T-SQL page on &lt;&gt; 声明:

      比较两个表达式(比较 操作员)。当您比较非空时 表达式,如果 左操作数不等于右操作数 操作数;否则,结果是 错误的。如果一个或两个操作数是 NULL,见 SET ANSI_NULLS (Transact-SQL)。

      SET ANSI_NULLS 页面然后声明:

      当 SET ANSI_NULLS 为 ON 时,SELECT 使用 WHERE column_name 的语句 = NULL 即使 ​​column_name 中有空值,也会返回零行。一种 使用 WHERE 的 SELECT 语句 column_name NULL 返回零行 即使有非空值 列名。

      ...

      当 SET ANSI_NULLS 为 ON 时,所有 与空值的比较 评估为未知。当设置 ANSI_NULLS 为 OFF,所有比较 针对空值的数据评估为 如果数据值为 NULL,则为 TRUE。

      【讨论】:

        【解决方案3】:

        这不是错误。

        NULL 不等于任何东西,甚至不等于 NULL(NULL = NULL 返回 FALSE)。

        通常 NULL 值也不会被索引。依赖特定值或 NULL 通常是个坏主意。根据您在列中存储的内容,您最好放入一个虚拟值或哨兵值,而不是使用 NULL 来表示某些含义。

        【讨论】:

        • 因此,如果 NULL 不等于您所说的任何内容,那么 NULL 如何不包含在其中?列 1... NULL 不等于 1?对吗?
        • 任何涉及 NULL 的比较都返回 false,所以是 NULL 1 为 false。这就是 IS NULL 或 IS NOT NULL 的用途。
        • 我发现在数据库术语中思考空值的最佳方式,正确或错误,是空值是“未知的”,因此不能与另一个空值进行比较,也不能与具体值进行比较
        • @cletus:说 NULL1 是“未知的”更准确,因为如果它是假的,那么 NOT(NULL1) 就是真的。相反,对未知应用 NOT 仍然是未知的。
        【解决方案4】:

        其他人是正确的,NULL &lt;&gt; 1 不评估为真,因此它不满足 WHERE 子句。

        您描述的建议修复是处理它的最佳方法:

        (VoidedIndicator <> 1 OR VoidedIndicator IS NULL)
        

        SQL-99 确实有一个谓词在这种情况下会有所帮助,称为 IS DISTINCT FROM

        (VoidedIndicator IS DISTINCT FROM 1)
        

        此谓词的行为与您建议的修复完全相同。不幸的是,Microsoft SQL Server 还不支持IS DISTINCT FROM

        【讨论】:

        • 感谢您的洞察力,我以前没有遇到过 IS DISTINCT FROM。所以这还没有在 SQL Server 2008 中实现?
        • 对。我在 MS SQL Server 2008 在线文档中找不到 IS DISTINCT FROM,但我确实找到了 IS NULL 谓词和 ISNULL() 函数。
        • PostgreSQL、IBM DB2 和 Firebird 支持与此不同。甲骨文和微软没有。 MySQL 支持运算符“”。
        【解决方案5】:

        你也可以:isnull(VoidedIndicator,1) 1

        【讨论】:

        • 性能不好,除非你有这类事情的功能索引。
        • @cletus 正在考虑他们有一个实际需要优化的场景。我同意在可能/适当的情况下使用默认值。
        【解决方案6】:

        因为 WHERE 子句仅在条件为真时选择行。

        当其中一个操作数为 NULL 时,条件的计算结果通常为 UNKNOWN(约等于 NULL),因此不成立。它适用于“column = 1”和“column &lt;&gt; 1”;如果 column 为 NULL,则搜索条件失败。

        这就是为什么你被告知要尽可能避免使用 NULL 列。

        【讨论】:

        • 您是否也避免使用整数值零,因为除以零会导致错误?
        • 它可能取决于服务器,但是如果你写'column / 0'并且column为null,那么除法代码会查看是否有一个操作数为null并在之前返回null产生“除以零”错误。但是,如果你知道 'column' 是空的,你为什么要分割它?
        • 你为什么要除以零呢?我认为依靠空值来防止除以零错误是不明智的,但是如果您“意外地”将空值除以零,那么您可能不会收到错误。
        • 我想你误解了我的意思……你说要避免 NULL,因为 NULL 有一些你必须处理的特殊逻辑。但这就像禁止零一样,只是因为您必须在除法运算中专门处理零。把它吸起来然后做检查!
        • 是的;我完全误解了这个问题。不,我不避免零;我只是避免被零除。我尽可能避免 null,这是大多数(但不是全部)时间。
        【解决方案7】:

        NULL 1 评估(理论上)为“可能”,这意味着不会返回记录。

        【讨论】:

          猜你喜欢
          • 2014-09-19
          • 1970-01-01
          • 1970-01-01
          • 2011-02-27
          • 1970-01-01
          • 1970-01-01
          • 2021-11-16
          • 1970-01-01
          相关资源
          最近更新 更多