空值和空值之间的区别

时间:2018-08-31 12:40:37

标签: sql sql-server tsql 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

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

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

Ps。我可能会用EXCEPT子句代替

4 个答案:

答案 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)

IN

  

注意

     

子查询或表达式返回的任何空值都将被比较   使用IN或NOT IN返回test_expression返回UNKNOWN。使用空值   值加上IN或NOT IN会产生意外结果。

未知<>是

答案 2 :(得分:3)

NULL表示我不知道,这是缺勤值。

在您的情况下,IN将转换为

@test = @testLT or @test =@testLV

在您的情况下,NOT IN将转换为

@test <> @testLT or @test <> @testLV

但是当NULL设置为<>时,=不能使用ANSI_NULLSON来获取值。

答案 3 :(得分:1)

来自documentation

  

注意

     

子查询或表达式返回的,与test_expression比较的任何空值   使用IN或NOT IN返回UNKNOWN。将空值与IN或NOT IN一起使用会产生意外的结果。

@test和@testLV之间的比较将始终返回“ UNKNOWN”,而不是TRUE或FALSE。