在我的表中,我有一个可为空的bit列(旧系统…),另一位开发人员最近对存储过程进行了更改,以仅显示bit列不为真的值(1)。因为这是一个可为空的列,所以我们注意到,如果该列为NULL,则不会选择该记录。为什么是这样?
我和其他开发人员都同意NULL <> 1 …这是SQL中的错误还是设计这种方式?似乎是设计缺陷。
当前代码:
(VoidedIndicator <> 1)
建议的修复:
(VoidedIndicator <> 1 OR VoidedIndicator IS NULL)
澄清(由乔恩·埃里克森(Jon Erickson))
VoidedIndicator是一个可为空的位字段,因此它可以具有以下值:NULL,0或1
当使用诸如(VoidedIndicator <> 1)之类的where子句创建SQL语句时,我们仅返回具有VoidedIndicator == 0的记录,但是我们期望VoidedIndicator == 0和VoidedIndicator IS NULL。为什么是这样?
从Wikipedia条目上的NULL:
例如,WHERE子句或条件语句可能会将列的值与常量进行比较。通常错误地认为,如果该字段包含Null,则缺失值将“小于”或“不等于”常量,但实际上,此类表达式返回Unknown。下面是一个示例: -- Rows where num is NULL will not be returned, -- contrary to many users' expectations. SELECT * FROM sometable WHERE num <> 1;
例如,WHERE子句或条件语句可能会将列的值与常量进行比较。通常错误地认为,如果该字段包含Null,则缺失值将“小于”或“不等于”常量,但实际上,此类表达式返回Unknown。下面是一个示例:
-- Rows where num is NULL will not be returned, -- contrary to many users' expectations. SELECT * FROM sometable WHERE num <> 1;
基本上,NULL和其他 任何 东西之间的 任何 比较(无论是=还是<>)都将是不正确的。
作为另一参考,MSDN T-SQL页面上<>指出:
<>
比较两个表达式(比较运算符)。比较非空表达式时,如果左操作数不等于右操作数,则结果为TRUE;否则,结果为TRUE。否则,结果为FALSE。如果一个或两个操作数均为NULL,请参见SET ANSI_NULLS(Transact-SQL)。
该SET ANSI_NULLS然后页指出:
当SET ANSI_NULLS为ON时,即使column_name中包含空值,使用WHERE column_name = NULL的SELECT语句也将返回零行。即使column_name中包含非空值,使用WHERE column_name <> NULL的SELECT语句也将返回零行。 … 当SET ANSI_NULLS设置为ON时,所有与空值的比较都将得出UNKNOWN。当SET ANSI_NULLS为OFF时,如果数据值为NULL,则将所有数据与null值的比较评估为TRUE。
当SET ANSI_NULLS为ON时,即使column_name中包含空值,使用WHERE column_name = NULL的SELECT语句也将返回零行。即使column_name中包含非空值,使用WHERE column_name <> NULL的SELECT语句也将返回零行。
…
当SET ANSI_NULLS设置为ON时,所有与空值的比较都将得出UNKNOWN。当SET ANSI_NULLS为OFF时,如果数据值为NULL,则将所有数据与null值的比较评估为TRUE。