T-SQL:什么是NOT(1 = NULL)?

时间:2012-03-14 17:39:39

标签: sql-server tsql ansi-nulls

我的sql-server上没有简单的布尔代数。根据msdn,以下语句应返回“1”,但在我的服务器上它返回“0”。 你能救我吗?

SET ANSI_NULLS ON
SELECT CASE WHEN NOT(1=NULL) THEN 1 ELSE 0 END

请查看msdn。它明确指出:“将NULL与非NULL值进行比较总是导致FALSE。” - 无论ANSI_NULLS设置是什么。因此,“1 = NULL”应为FALSE,因此NOT(FALSE)应为TRUE,语句应返回“1”。

但是在我的机器上,它返回“0”!

一种解释可能是,“1 = NULL”评估为“未知”。 NOT(UNKNOWN)仍然是UNKNOWN(msdn),它会强制CASE语句进入ELSE。

但是那时equals-operator的官方文档是错误的。我简直不敢相信!

有人可以解释这种行为吗?

非常感谢您的帮助!

编辑(2012-03-15):

我发现的一件事可能对你们中的一些人感兴趣:

CREATE TABLE #FooTest (Value INT)
ALTER TABLE #FooTest WITH CHECK ADD CONSTRAINT ccFooTestValue CHECK (Value>1)
PRINT '(NULL>1) = ' + CASE WHEN NULL>1 THEN 'True' ELSE 'False' END
INSERT INTO #FooTest (Value) VALUES (NULL)

print-Statement写入'False',但插入运行没有错误。 SQL-Server似乎否定了检查约束,以便搜索不符合约束检查的行:

IF EXISTS (SELECT * FROM inserted WHERE NOT(Value>NULL)) <Generate error>

由于check-constraint的计算结果为UNKNOWN,否则也是UNKNOWN,并且SqlServer没有找到任何违反check-constraint的行。

7 个答案:

答案 0 :(得分:6)

是的,链接错误。在Microsoft Connect上提交文档错误。

Sql使用三值逻辑而不是布尔逻辑。 truefalseunknown

涉及IS [NOT] NULL的大多数比较运算符(即不包括NULL)会导致unknown而非TrueFalse。根据真值表shown here否定未知的未知数。

答案 1 :(得分:5)

您链接到的Equals的MSDN页面肯定显示不正确。

检查SET ANSI_NULLS的MSDN页面。

  

当SET ANSI_NULLS为ON时,所有与空值的比较   评估为UNKNOWN。

要使该示例SQL语句按预期工作,您应该使用"IS NULL" or "IS NOT NULL"而不是使用equals运算符(=)进行比较。例如:

SELECT CASE WHEN NOT(1 IS NULL) THEN 1 ELSE 0 END

OR

SELECT CASE WHEN (1 IS NOT NULL) THEN 1 ELSE 0 END

答案 2 :(得分:2)

您想阅读documentation on ANSI_NULLS。 SQL实际上实现了三元逻辑,而不是布尔逻辑,其中比较操作可能导致true,false或undefined。基本上,这意味着您提供的解释是正确的。

这可以通过以下查询来证明:

SET ANSI_NULLS ON
SELECT CASE
  WHEN (1=NULL) THEN 0
  WHEN NOT(1=NULL) THEN 1    
  ELSE -1
END

这导致我的计算机上的-1(SQL Server 2005 Enterprise)。将第一行更改为SET ANSI_NULLS OFF会按预期生成1

那么,官方文档是错误的吗?我认为这有点误导。它说它导致FALSE。显然这是错误的。文档的意思是将非null与NULL进行比较总是会导致不匹配,其值也取决于ANSI_NULLS

当然,on SQL Server 2012ANSI_NULLS设置已被删除,因此以任何方式设置都不会改变结果。

答案 3 :(得分:2)

这不是布尔逻辑,它的三元逻辑:{真,假,我不知道。}以这种方式分解:

IF 1=NULL
    print 'True'
else
    print 'False'

生成False,因为1=NULL等于NULL,又名“不是真”

IF not(1=NULL)
    print 'True'
else
    print 'False'

同时生成False,因为not(1=NULL)等于not(NULL)等于NULL,又名“非真”。这可以让你

SELECT CASE WHEN NOT(1=NULL) THEN 1 ELSE 0 END

如上所述与

相同
SELECT CASE WHEN NULL THEN 1 ELSE 0 END

,由于NULL不成立,因此转而使用ELSE子句。

简而言之,就我而言,文档不正确。令人痛苦,但不是唯一的,所以并不完全令人惊讶。

答案 4 :(得分:0)

尝试在子查询中使用EXISTS,它使用2值逻辑,并为您提供正在寻找的真/假。

答案 5 :(得分:0)

从BOL(信用卡到Thomas):

  

SET ANSI_NULLS ON仅在其中一个操作数的情况下影响比较   比较是一个NULL变量或文字NULL。如果   比较的两边都是列或复合表达式   设置不会影响比较。

所以我猜NOT操作正在检查1=NULL哪个是未知的,因为这不是变量或字面值NULL假设你的比较中有ELSE部分。

答案 6 :(得分:0)

1 = NULL仅在ANSI_NULLS为OFF时才返回FALSE。否则它是不确定的。可能需要编辑msdn页面以澄清这一点。

SET ANSI_NULLS OFF
SELECT CASE WHEN (1=NULL) THEN 'true' ELSE 'false or unknown' END --returns false or unknown
, CASE WHEN NOT(1=NULL) THEN 'true' ELSE 'false or unknown' END --returns true
go

SET ANSI_NULLS ON
SELECT CASE WHEN (1=NULL) THEN 'true' ELSE 'false or unknown' END --returns false or unknown
, CASE WHEN NOT(1=NULL) THEN 'true' ELSE 'false or unknown' END --returns false or unknown
go