我今天遇到了一个我不太了解的问题,所以我希望获得一些外部知识。我试图在一个表中查找没有在另一个表中引用其ID的项数。我运行了两个不同的查询,结果似乎有冲突。
select count(*)
from TableA
where ID not in (select aID from TableB)
返回0
select count(*)
from TableA a
left join TableB b on b.aID = a.ID
where b.aID is null
返回几千。
TableA和TableB中的所有ID都是唯一的。来自TableA的ID不会多次出现在来自TableB的aID列中。对我来说,似乎我在查询同一件事,但收到不同的结果。我要去哪里错了?
答案 0 :(得分:2)
请勿将not in
与子查询一起使用。如果子查询中的 any 值为NULL
,则将过滤掉所有行。这些是如何在SQL中定义NULL
的规则。 LEFT JOIN
是正确的。
原因是NULL
表示未知值。几乎所有与NULL
的比较都会返回NULL
,这被视为false。因此,将NOT IN
与NULL
一起使用的唯一可能性是,一个元素与您要查找的内容相匹配-表达式返回false
-或元素为NULL
- -并且表达式返回NULL
,它被视为false
。
我通常建议将NOT IN
替换为NOT EXISTS
:
select count(*)
from TableA a
where not exists (select 1 from TableB b where b.aID = a.ID);
LEFT JOIN
的性能正常,并且通常具有良好的性能。
答案 1 :(得分:0)
如果涉及的列为可为空,则应始终使用EXISTS运算符。另外,Exist比In子句快。
使用IN / Not IN运算符可能会产生较差的计划,并且如果像您一样在表中插入空值,也会导致误导结果。