我正在阅读一篇文章,解释了join和in和exists子句之间的区别,但是在使用NOT IN vs. NOT EXISTS子句时,我对使用不同结果的解释感到困惑。有人可以澄清为什么NOT EXISTS子句与NOT IN子句的输出之间存在差异吗?我在从表t2中删除NULL行(t2.id = 8)后尝试了,但仍然得到了相同的结果。
以下是文章中的SQL脚本:
CREATE TABLE t1 (id INT, title VARCHAR(20), someIntCol INT)
GO
CREATE TABLE t2 (id INT, t1Id INT, someData VARCHAR(20))
GO
INSERT INTO t1
SELECT 1, 'title 1', 5 UNION ALL
SELECT 2, 'title 2', 5 UNION ALL
SELECT 3, 'title 3', 5 UNION ALL
SELECT 4, 'title 4', 5 UNION ALL
SELECT null, 'title 5', 5 UNION ALL
SELECT null, 'title 6', 5
INSERT INTO t2
SELECT 1, 1, 'data 1' UNION ALL
SELECT 2, 1, 'data 2' UNION ALL
SELECT 3, 2, 'data 3' UNION ALL
SELECT 4, 3, 'data 4' UNION ALL
SELECT 5, 3, 'data 5' UNION ALL
SELECT 6, 3, 'data 6' UNION ALL
SELECT 7, 4, 'data 7' UNION ALL
SELECT 8, null, 'data 8' UNION ALL
SELECT 9, 6, 'data 9' UNION ALL
SELECT 10, 6, 'data 10' UNION ALL
SELECT 11, 8, 'data 11'
这是SQL查询及其解释:
- IN无法获得正确的结果。 - 这是因为IN如何处理NULL和三值逻辑 - NULL被视为未知,因此如果t2.t1id中存在null - NOT IN将返回NOT TRUE或NOT UNKNOWN。而且都不是真的。 - 当t2表的t1id列中有NULL时,NOT IN查询将始终返回空集。
SELECT t1.*
FROM t1
WHERE t1.id NOT IN (SELECT t1id FROM t2)
- NOT EXISTS获得正确的结果
SELECT t1.*
FROM t1
WHERE NOT EXISTS (SELECT * FROM t2 WHERE t1.id = t2.t1id)
GO
DROP TABLE t2
DROP TABLE t1
以下是该文章的链接:http://weblogs.sqlteam.com/mladenp/archive/2007/05/18/60210.aspx
谢谢!
答案 0 :(得分:0)
正如我所看到的,在很多情况下你可以将它们用作同样的东西,但你不能忘记它们背后的细节。
您可以同时应用NOT IN
和NOT EXISTS
获得相同的结果,但您可以看到查询中涉及NULL
值的差异。因为NOT EXISTS
是获取NULL
值的行的唯一方法。
在这个例子中你可以更好地看到它:
update cars set c_owner = NULL where c_id = BMW03444
嗯......我们试着看看我们是否有任何尚未售出的车库存。
select count(*) from cars where c_owner not it (select c_name from customers);
输出:
COUNT(*):0
失败在哪里?非常简单。您没有要求一组其买家未包含在列表中的汽车。你只是要求一辆没有车主的车。任何人,即使他不在名单中。正确的形式是:
select count(*)
from cars c1
where not exists (
select c_owner
from customers c2
where c1.c_owner=c2.customer_id
);
COUNT(*):1
这是因为NOT IN
需要特定值来检入。因此NULL
值设置为FALSE
而不计算在内。
NOT EXISTS
检查集合中是否存在元素,因此NULL
值设置为TRUE并包含在内。