SQL:为什么在这个where子句中过滤掉NULL值?

时间:2009-03-25 21:49:12

标签: sql sql-server-2005 tsql

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

其他开发者和我同意NULL<> 1 ...这是SQL中的错误还是这样设计的?看起来像是一个设计缺陷。

当前代码:

(VoidedIndicator <> 1)

建议修复:

(VoidedIndicator <> 1 OR VoidedIndicator IS NULL)

澄清(作者Jon Erickson)

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

当使用诸如(VoidedIndicator&lt;&gt; 1)之类的where子句创建SQL语句时,我们只获得返回的具有VoidedIndicator == 0的记录,但我们期望VoidedIndicator == 0和VoidedIndicator IS为NULL。这是为什么?

7 个答案:

答案 0 :(得分:12)

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

对于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

答案 1 :(得分:11)

来自Wikipedia entry on NULL

  

例如,WHERE子句或   条件语句可能会比较一个   列的值带有常量。它是   经常错误地认为a   缺失值将是“小于”或   “不等于”如果那是一个常数   字段包含Null,但事实上,   这样的表达式返回Unknown。一个   示例如下:

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

基本上,在NULL和其他东西之间的任何比较,无论是使用=还是&lt;&gt;不会是真的。

作为另一个参考,MSDN T-SQL page on <>州:

  

比较两个表达式(比较   运营商)。当你比较nonnull   表达式,如果是,则结果为TRUE   左操作数不等于右边   操作数;否则,结果是   假。如果是其中一个或两个操作数   NULL,请参阅SET ANSI_NULLS   (处理SQL)。

SET ANSI_NULLS页面然后声明:

  

当SET ANSI_NULLS为ON时,为SELECT   使用WHERE column_name的语句   = NULL返回零行,即使column_name中有空值也是如此。一个   使用WHERE的SELECT语句   column_name&lt;&gt; NULL返回零行   即使有非空值   列名。

     

...

     

当SET ANSI_NULLS为ON时,全部   与空值进行比较   评估为UNKNOWN。当SET   ANSI_NULLS为OFF,比较所有   针对空值的数据评估为   如果数据值为NULL,则为TRUE。

答案 2 :(得分:3)

这不是一个错误。

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

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

答案 3 :(得分:1)

其他人都认为NULL <> 1没有评估为真,因此它不符合WHERE条款。

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

(VoidedIndicator <> 1 OR VoidedIndicator IS NULL)

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

(VoidedIndicator IS DISTINCT FROM 1)

此谓词的行为与您提出的修复完全相同。遗憾的是,Microsoft SQL Server尚不支持IS DISTINCT FROM

答案 4 :(得分:0)

您还可以:isnull(VoidedIndicator,1)&lt;&gt; 1

答案 5 :(得分:0)

因为WHERE子句仅在条件计算结果为true时选择行。

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

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

答案 6 :(得分:0)

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