查找包含子查询的 GUID 的“不在”空值的查询不返回任何结果

zea*_*eal 5 null sql-server uniqueidentifier subquery

当我有一个查询来检查uniqueidentifer具有空值的表中是否不存在类型的列时,我不会得到任何结果。如果子查询不返回空值,则它工作正常,并且仅在使用not in.

我知道我可以只not null检查我的子查询,但我很好奇为什么这不起作用。

查询示例:

select a.guid from tableA a where a.guid not in (select b.guid from tableB AS b)
Run Code Online (Sandbox Code Playgroud)

工作测试:

select 1 where newid() not in (select newid())
Run Code Online (Sandbox Code Playgroud)

破碎测试:

select 1 where newid() not in (select null)
Run Code Online (Sandbox Code Playgroud)

Mar*_*ith 11

只是为了对billinkc 的回答提供一些额外的解释。

如果 null 是一张王牌,您可能想知道为什么不WHERE 2 IN (2,3, NULL)表现出相同的行为?

那个按预期工作,因为它评估为(2=2) OR (2=3) OR (2=NULL).

根据三个值逻辑 for Or-ed 条件的规则,如果它们中的任何一个评估为true表达式 is true。否则,如果它们中的任何一个评估为unknown表达式 is unknown。唯一的另一种可能性是,false在这种情况下,表达式的计算结果为false

为了在 SQL 中返回一行,WHERE子句必须计算为true而不是falseor unknown。以上就是这样做的。

该表达式的1 NOT IN (2,3, NULL)计算结果为(1 <> 2) AND (1 <> 3) AND (1 <> NULL)。当条件为AND-ed 时,所有条件都必须计算为true,以便表达式计算为true

NULL列表中的的存在保证了至少会有一个UNKNOWN并且永远不会是这种情况。因此,在这种情况下,“ NULL 全部”行为的原因。

在这里打个比方,说明为什么这种NOT IN行为是有意义的。

汤姆、迪克和哈利的三个朋友和一个完全陌生的人坐在火车车厢里,他们的名字不为他们所知。

如果有人问汤姆“你的名字和这辆马车上其他人的名字不同吗?” 那么他就不可能有把握地回答了。

即使他知道这一点Tom <> Dick并且Tom <> Harry(因此该陈述可能是真实的)该陈述的整体真实性取决于陌生人的姓名,而这是未知的。

这类似于 SQL 'Tom' NOT IN ('Dick', 'Harry', Null)


bil*_*nkc 9

用一个例子来吹嘘我的评论。无论您使用的是 GUID 还是任何其他数据类型,这都无关紧要。您的过滤器应评估为真或假条件。在 .net/python/java/etc 这就是你得到的。在 SQL 世界中,我们可以将三态内置于所有内容中。是真的,是假的,是……我不知道。

当 NULL 值进入混合时,它就是一张王牌。它会崩溃任何其他值,无论是真还是假,并说“很难,这现在是未知的”。由于它无法给出权威答案,因此它不会提供答案。无论您是否认为这是一个破碎的设计,它只是。

-- NULL pooches it all
SELECT 1 AS query1 WHERE 1 NOT IN (SELECT NULL);

-- No null, no problem
SELECT 2 AS query2 WHERE 1 NOT IN (2,3,4);

-- Null, we meet again. With the same result
SELECT 3 AS query3 WHERE 1 NOT IN (2,3,4, NULL);
Run Code Online (Sandbox Code Playgroud)

SQLFiddle


Aar*_*and 6

忽略关于 NULL 的教训(你应该观察),NOT IN即使没有涉及 NULL ,对于左反半连接也可能是一个可怕的选择。看看NOT IN与以下相比,您是否可以获得更好的性能或更好的计划NOT EXISTS

 select a.guid 
   from dbo.tableA AS a 
   where not exists
   (
     select 1 
       from tableB AS b
       where b.guid = a.guid
   );
Run Code Online (Sandbox Code Playgroud)