我偶然发现我们数据库中的某些旧代码表现异常。我设法将其范围缩小到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
如果testLV为null,则NOT IN
返回与IN
子句相同的结果。
我想了解这种行为背后的机制。有人可以解释吗?
Ps。我可能会用EXCEPT
子句代替
答案 0 :(得分:6)
列表中具有NOT IN
值会影响NULL
的语义。在SQL中,NULL
的意思是“我不知道值;它可能是任何值。”。
因此,如果您这样做:
where 1 in (1, 2)
然后返回true。
where 1 in (3, 4)
返回假。
到目前为止,太好了。现在考虑:
where 1 not in (1, 2, NULL)
好吧,“ 1”显然在列表中。所以这返回false。
where 1 not in (3, 4, NULL)
好吧,“ 1”不是“ 3”或“ 4”。但这是NULL
吗?我们不知道因此,这将返回NULL
而不是true。在NULL
条件下,WHERE
与false相同,这意味着该行被过滤掉了。 (请注意:check
条件的行为有所不同,只有{em> explicit false才使check
失败。)
因此,如果任何的值为NOT IN
,则NULL
不返回任何内容。
这种情况几乎总是在子查询(而不是常量)的上下文中出现。因此,我建议在所有情况下都将NOT EXISTS
而不是NOT IN
用于子查询。
答案 1 :(得分:3)
答案 2 :(得分:3)
NULL
表示我不知道,这是缺勤值。
在您的情况下,IN
将转换为
@test = @testLT or @test =@testLV
在您的情况下,NOT IN
将转换为
@test <> @testLT or @test <> @testLV
但是当NULL
设置为<>
时,=
不能使用ANSI_NULLS
或ON
来获取值。
答案 3 :(得分:1)
注意
子查询或表达式返回的,与test_expression比较的任何空值 使用IN或NOT IN返回UNKNOWN。将空值与IN或NOT IN一起使用会产生意外的结果。
@test和@testLV之间的比较将始终返回“ UNKNOWN”,而不是TRUE或FALSE。