我有两个非常相似的查询,但是它们会返回不同的结果。
第一个:
select * from products p
where p.val >= 999999 and
not exists
(select * from products p2 where p2.val < 999999 and p.user_id = p2.user_id);
第二个:
select * from products p
where p.val >= 999999 and
p.user_id not in (select user_id from products p2 where p2.val < 999999);
第一个给了我正确答案,而第二个给了我没有(零)结果。这可能是因为第二个查询中的子查询产生了太多结果吗?
答案 0 :(得分:3)
小心无效!
如果子查询中有NULL,则NOT IN将无法像大多数人期望的那样工作。
如果您将NOT IN (...)
翻译为NOT (... OR ...)
或NOT ... AND NOT ...
并将three-valued logic应用于生成的表达式,则问题会更加明确。
为了用一个例子来说明这一点,让我们说条件是NOT IN (1, 2, NULL)
,而被检查的行的值是3。
使用NOT (... OR ...)
即可获得此信息:
NOT (3=1 OR 3=2 OR 3=NULL)
括号中的前两个条件为false,最后一个条件未知。基于三值逻辑,析取的结果将是未知的。根据同样的逻辑,未知的倒置也是未知的。 WHERE子句中未知的结果与false的结果相同,即不匹配。所以,你在这里。
现在,如果你用NOT ... AND NOT ...
重写NOT IN,这就是你得到的:
NOT 3=1 AND NOT 3=2 AND NOT 3=NULL
前两个术语是真的,最后一个是未知的(3=NULL
未知,其反转也是未知的)。同样,三值逻辑表明在这种情况下最终结果是未知的。你又来了。
因此,当一行的值不在子集中但子集也包含空值时,要么不使用NOT IN,要么过滤掉空值。