为什么在查询结果中忽略 Null

Bel*_*igh 4 null sql-server sql-server-2008-r2

我有一个与下面结构相似的表,一个字段中有一个NULL值。当我查询表时,这条记录没有返回,它被省略了。应如何更改查询以返回此记录?

Declare @Fiesty Table
(  
  numberfour varchar(100)
  ,valid varchar(20)
)

Insert Into @Fiesty (numberfour, valid) Values
('1ACRELBS', NULL), ('4ACRELBS', 'Green'), ('17ACRELBS', 'White')

Select * FROM @Fiesty WHERE valid NOT IN ('Green', 'Blue', 'White')
Run Code Online (Sandbox Code Playgroud)

我预期的返回结果将是 numberfour = 1ACRELBS

ype*_*eᵀᴹ 19

SQL 使用三元(三值)逻辑,与 的比较NULL很棘手,违反直觉。关于条件:

WHERE valid NOT IN ('Green', 'Blue', 'White')
Run Code Online (Sandbox Code Playgroud)

它扩展为:

WHERE valid <> 'Green' AND valid <> 'Blue' AND valid <> 'White'
Run Code Online (Sandbox Code Playgroud)

valid是 时NULL,所有这 3 个子条件的计算结果都为UNKNOWN(既不是TRUE也不是FALSE)。整个条件也评估UNKNOWN为,因此行被拒绝(WHERE仅保留条件评估为的行TRUE)。

在比较空值时,您可以这样想。我不知道的确切值,valid所以我不能确定它是否会有所不同'Green'。它可能是,也可能不是。结果是UNKNOWN


如果目的是获取结果中的行 where valid IS NULL,您可以使用:

SELECT * FROM @Fiesty 
WHERE valid IS NULL
   OR valid NOT IN ('Green', 'Blue', 'White') ;
Run Code Online (Sandbox Code Playgroud)

EXISTS / EXCEPT(或NOT EXISTS / INTERSECT):

SELECT f.* FROM @Fiesty AS f 
WHERE EXISTS
      ( SELECT f.valid 
      EXCEPT 
        SELECT v.valid 
        FROM
            ( VALUES ('Green'), ('Blue'), ('White') )
            AS v (valid)
      ) ;
Run Code Online (Sandbox Code Playgroud)

还有一种NOT EXISTS我认为比 更喜欢的方法NOT IN,特别是因为有关空值的行为更直观。(还要注意与INTERSECT版本的相似性):

SELECT f.* FROM Fiesty AS f
WHERE NOT EXISTS
      ( SELECT *
        FROM
            ( VALUES ('Green'), ('Blue'), ('White') )
            AS v (valid)
        WHERE v.valid = f.valid
      ) ;
Run Code Online (Sandbox Code Playgroud)

dbfiddle.uk测试。