SQL Server 2012 和 NULL 比较

SQL Server 2012 and NULL comparison

谁能解释一下为什么这两个语句 returns 不同的结果?

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

我知道 NULL 与任何东西相比都会给出 false 并且我想使用它 属性 但我在与上面类似的命令处停止了。我的真实语句而不是 NULL 使用可以是 NULL 的变量,但我简化了它们以显示问题出在哪里。我以为它有一些操作顺序,但似乎不是。

I know that NULL compared with anything gives false

这是不正确的,NULL 与任何东西相比,计算结果都是未知的,不是假的,举个简单的例子:

SELECT CASE WHEN (NULL = NULL) THEN 'True' 
            WHEN NOT(NULL = NULL) THEN 'False'
            ELSE 'Other'
        END

会给出Other的第三个选项。

如果我们重写你的逻辑(还是一样的意思,但是变得更清晰了):

SELECT CASE WHEN (NULL <> NULL) AND (1 = 1) THEN 1 ELSE 0 END
SELECT CASE WHEN (NULL <> NULL) OR (1 = 1) THEN 1 ELSE 0 END

所以在第一个例子中你有 WHEN [Unknown] AND [True] 这是错误的,但是在第二个例子中你有 WHEN [Unknown] OR [True] 这是正确的,所以 returns 1.

如果你用变量重写查询,然后检查执行计划XML,你可以看到SQL服务器在编译期间重写了上面的表达式:

DECLARE @a INT = NULL, @b INT = NULL, @c INT = 1, @d INT = 1;

SELECT TOP 1 
        CASE WHEN NOT((@a = @b) OR (@c != @d)) THEN 1 ELSE 0 END,
        CASE WHEN NOT((@a = @b) AND (@c != @d)) THEN 1 ELSE 0 END

所以,有 2 个选项:要么你打开 ANSI_NULLS(你应该),要么你关闭 ANSI_NULLS。

在第一种情况下,任何与 NULL returns NULL 的比较(甚至是像你这样的 NULL 值之间的比较)。

在第二种情况下,sql 服务器将评估 NULL 值之间的比较(例如 NULL=NULL 将 return 为真)。

因此,在考虑查询中的不同结果之前,您必须首先考虑将 NULL 与任何内容进行比较,计算结果不是 false,而是 NULL

-- first query   
SELECT CASE WHEN NOT((NULL = NULL) AND (1 != 1)) THEN 1 ELSE 0 END
=
SELECT CASE WHEN NOT(unknown AND false) THEN 1 ELSE 0 END
=
SELECT CASE WHEN NOT(false) THEN 1 ELSE 0 END
=
SELECT CASE WHEN true THEN 1 ELSE 0 END
=
1
-- second query
SELECT CASE WHEN NOT((NULL = NULL) OR (1 != 1)) THEN 1 ELSE 0 END 
=
SELECT CASE WHEN NOT(unknown OR false) THEN 1 ELSE 0 END 
=
SELECT CASE WHEN NOT(unknown) THEN 1 ELSE 0 END 
=
SELECT CASE WHEN unknown THEN 1 ELSE 0 END 
=
else matched, so 0

以及评论中 D0dger 的问题:

It's more interesting why SELECT CASE WHEN (NULL = NULL) OR (1 != 1) THEN 1 ELSE 0 END and SELECT CASE WHEN NOT((NULL = NULL) OR (1 != 1)) THEN 1 ELSE 0 END returns 0

SELECT CASE WHEN (NULL = NULL) OR (1 != 1) THEN 1 ELSE 0 END
=
SELECT CASE WHEN unknown OR false THEN 1 ELSE 0 END
=
SELECT CASE WHEN unknown THEN 1 ELSE 0 END
= 
else matched, so 0

OR (Transact-SQL), AND (Transact-SQL)