7

我的 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”的计算结果为“UNKNOWN”。NOT(UNKNOWN) 仍然是 UNKNOWN ( msdn ),这将强制 CASE-Statement 进入 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>

由于检查约束的计算结果为 UNKNOWN,否定也是 UNKNOWN 并且 SqlServer 没有找到任何违反检查约束的行。

4

7 回答 7

6

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

Sql 使用三值逻辑而不是布尔逻辑。true, false, 和unknown

IS [NOT] NULL大多数涉及NULL结果的比较运算符(即排除unknownTrueFalse根据此处显示的真值表,否定未知产生未知。

于 2012-03-14T17:57:40.620 回答
5

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

检查SET ANSI_NULLS的 MSDN 页面。

当 SET ANSI_NULLS 为 ON 时,所有针对空值的比较都会评估为 UNKNOWN。

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

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

或者

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

于 2012-03-14T18:01:27.763 回答
2

您想阅读有关ANSI_NULLS. SQL 实际上实现了三元逻辑,而不是布尔逻辑,其中比较操作可能导致真、假或未定义。基本上,这意味着您提供的解释是正确的。

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

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.

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

于 2012-03-14T18:00:42.330 回答
2

这不是布尔逻辑,而是三元逻辑:{True, False, I Don't Know.} 以这种方式分解:

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

生成False是因为1=NULLequals NULL,又名“非 True”

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

也生成False因为not(1=NULL)equals not(NULL)equals NULL,又名“非真”。这让你

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

与上述相同

SELECT CASE WHEN NULL THEN 1 ELSE 0 END

,因为NULL它不正确,所以归结为该ELSE子句。

简而言之,就我而言,文档不正确。令人痛苦,但不是独一无二的,因此并不完全令人惊讶。

于 2012-03-14T18:08:32.567 回答
0

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

于 2012-03-14T18:05:55.490 回答
0

来自 BOL(归功于Thomas):

仅当比较的操作数之一是 NULL 变量或文字 NULL 时,SET ANSI_NULLS ON 才会影响比较。如果比较的两边都是列或复合表达式,则设置不影响比较。

所以我猜这个NOT操作正在检查1=NULL哪个是未知的,因为这不是一个变量或文字 NULL 如你所假设的那样得到你比较的 ELSE 部分。

于 2012-03-14T18:17:27.970 回答
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
于 2012-03-14T18:29:14.830 回答