【发布时间】:2010-10-13 14:22:09
【问题描述】:
为什么value 与null 的比较返回false,除非使用NOT IN,它返回true?
给定一个查询以查找所有 拥有帖子的 stackoverflow 用户:
SELECT * FROM Users
WHERE UserID IN (SELECT UserID FROM Posts)
这按预期工作;我得到了所有有帖子的用户的列表。
现在查询逆;查找所有没有有帖子的 stackoverflow 用户:
SELECT * FROM Users
WHERE UserID NOT IN (SELECT UserID FROM Posts)
这不返回任何记录,这是不正确的。
给定假设数据1
Users Posts
================ ===============================
UserID Username PostID UserID Subject
------ -------- ------- ------ ----------------
1 atkins 1 1 Welcome to stack ov...
2 joels 2 2 Welcome all!
... ... ... ...
399573 gt6989b ... ...
... ... ... ...
10592 null (deleted by nsl&fbi...
... ...
并假设 NULL 的规则:
-
NULL = NULL评估为未知 -
NULL <> NULL评估为未知 -
value = NULL评估未知
如果我们查看第二个查询,我们有兴趣在 Posts.UserID 列中找到所有 not Users.UserID 的行。我会按逻辑进行如下:
检查用户 ID 1
-
1 = 1返回真。所以我们断定该用户有一些帖子,并且不将它们包含在输出列表中
现在检查用户 ID 2:
-
2 = 1返回 false,所以我们继续寻找 -
2 = 2返回 true,因此我们断定该用户有一些帖子,并且不将它们包含在输出列表中
现在检查用户 ID 399573
-
399573 = 1返回 false,所以我们继续寻找 -
399573 = 2返回 false,所以我们继续寻找 - ...
-
399573 = null返回未知,所以我们继续寻找 - ...
我们没有找到用户 ID 399573 的帖子,因此我们会将他包含在输出列表中。
除了 SQL Server 不这样做。如果您的in 列表中有一个NULL,那么它会突然找到一个匹配项。 它突然找到了一个匹配项。突然399573 = null 评估为真。
为什么value 与null 的比较返回未知,除非它返回true?
编辑:我知道我可以通过专门排除空值来解决这个 nonsensical 行为:
SELECT * FROM Users
WHERE UserID NOT IN (
SELECT UserID FROM Posts
WHERE UserID IS NOT NULL)
但我不应该这样做,据我所知,没有它布尔逻辑应该没问题 - 因此我的问题。
脚注
- 1 假设数据;如果你不喜欢它:补上你的羽绒服。
- celko 现在有了自己的标签
【问题讨论】:
-
@Ian Boyd = 我不认为这是一个错误。还有一点要记住的是
IN使用or和NOT IN使用AND。当您针对具有不等式与已知值的NULL进行评估时,您将始终得到错误,因为无法知道它是否匹配。 -
@Ian Boyd:我不会称之为错误。
IN只不过是一系列OR子句的便捷简写。从技术上讲,考虑另一个问题中给出的扩展的正确方法是:select 'true' where NOT(3 = 1 or 3 = 2 or 3 = null),在逻辑上等同于DeMorgan's Law。在任何情况下,谬误都是假设 value=NULL 的比较返回 FALSE,而实际上结果是 UNKNOWN。 -
是的。不是错误。它也是 not 布尔逻辑。是3 valued logic。
-
@Ian Boyd - 对于你姐姐的名字问题,这是一个数据建模问题。您应该有一个子表
SISTER引用您的主表。如果您没有姐妹,您将不会被包含在结果集中。此外,NULL表示未知。如果你有 2 个人的名字你不知道,你能说他们的名字之一不是克尔斯滕吗?
标签: sql-server null celko