not in和in与null值之间的差异

Lun*_*tri 2 sql t-sql sql-server null

我偶然发现我们的数据库中的一些旧代码表现得并不像预期的那样.我设法将其缩小到条款的NULL价值效果IN.

我派生出一个测试来证明它:

declare @test   nvarchar(50) = '8620M/9010';
declare @testLT nvarchar(50) = '8004/9010';
declare @testLV nvarchar(50) =  null;  --'asd'
select case when @test not in (@testLT, @testLV) then 1 else 0 end
Run Code Online (Sandbox Code Playgroud)

如果testLV为null,则NOT IN返回与IN子句相同的结果.

我想了解这种行为背后的机制.有人可以解释一下吗?

PS.我可能会用EXCEPT子句替换它

Gor*_*off 6

NOT IN通过NULL在列表中具有值来影响语义.在SQL中,NULL意思是"我不知道它的价值;它可能是任何东西."

所以,如果你这样做:

where 1 in (1, 2)
Run Code Online (Sandbox Code Playgroud)

然后它返回true.

where 1 in (3, 4)
Run Code Online (Sandbox Code Playgroud)

返回false.

到现在为止还挺好.现在考虑:

where 1 not in (1, 2, NULL)
Run Code Online (Sandbox Code Playgroud)

好吧,"1"显然在列表中.所以这会返回false.

where 1 not in (3, 4, NULL)
Run Code Online (Sandbox Code Playgroud)

好吧,"1"不是"3"或"4".但是NULL吗?我们不知道.所以,这会返回NULL而不是真实.并且NULLWHERE条件中被视为与false相同,意味着该行被过滤掉.(作为一个注释: check条件表现不同,只有明确的假失败了check.)

因此,NOT IN如果有任何值,则不返回任何内容NULL.

这种情况几乎总是出现在子查询(而不是常量)的上下文中.出于这个原因,我建议使用NOT EXISTS而不是NOT IN在所有情况下使用子查询.