免责声明:我想通了这个问题(我认为),但我想添加这个问题上堆栈溢出,因为我不能(容易)在任何地方找到它。 另外,有些人可能有一个更好的答案比我好。
我有其中一个表的“共同”是由其他几个表格中引用的数据库。 我想看看在公用表什么纪录被孤立的(即有任何其他表没有引用)。
我跑这个查询:
select *
from Common
where common_id not in (select common_id from Table1)
and common_id not in (select common_id from Table2)
我知道有孤立的记录,但没有记录返回。 为什么不?
(这是SQL Server中,如果它很重要。)
Answer 1:
更新:
在我的博客这些文章将详细介绍这些方法之间的区别:
-
NOT IN
与NOT EXISTS
与LEFT JOIN / IS NULL
: SQL Server
-
NOT IN
与NOT EXISTS
与LEFT JOIN / IS NULL
: PostgreSQL
-
NOT IN
与NOT EXISTS
与LEFT JOIN / IS NULL
: Oracle
-
NOT IN
与NOT EXISTS
与LEFT JOIN / IS NULL
: MySQL
有三种方法可以做到这样的查询:
LEFT JOIN / IS NULL
:
SELECT * FROM common LEFT JOIN table1 t1 ON t1.common_id = common.common_id WHERE t1.common_id IS NULL
NOT EXISTS
:
SELECT * FROM common WHERE NOT EXISTS ( SELECT NULL FROM table1 t1 WHERE t1.common_id = common.common_id )
NOT IN
:
SELECT * FROM common WHERE common_id NOT IN ( SELECT common_id FROM table1 t1 )
当table1.common_id
不能为空,所有这些查询在语义上是相同的。
当它是空的, NOT IN
是不同的,因为IN
(因此, NOT IN
)返回NULL
当值不匹配包含列表什么NULL
。
这可能是混乱的,但如果我们回顾替代语法这可能会变得更加明显:
common_id = ANY
(
SELECT common_id
FROM table1 t1
)
这种情况的结果是列表中的所有比较的布尔产品。 当然,一个单一的NULL
值产生了NULL
这使得整个结果结果NULL
太。
我们从来不能肯定地说, common_id
不等于从该列表中任何东西,因为这些值中的至少一个为NULL
。
假设我们有以下数据:
common
--
1
3
table1
--
NULL
1
2
LEFT JOIN / IS NULL
和NOT EXISTS
将返回3
, NOT IN
将返回什么 (因为它总是求值FALSE
或NULL
)。
在MySQL
,如果在非空的列, LEFT JOIN / IS NULL
和NOT IN
是一点点(百分之几)更有效超过NOT EXISTS
。 如果列可以为空, NOT EXISTS
是最有效的(同样,没有多少)。
在Oracle
中,所有三个查询产生相同的计划(一个ANTI JOIN
)。
在SQL Server
, NOT IN
/ NOT EXISTS
更有效率,因为LEFT JOIN / IS NULL
不能被优化到ANTI JOIN
通过其优化。
在PostgreSQL
, LEFT JOIN / IS NULL
和NOT EXISTS
比更有效的NOT IN
,它们被优化为正弦Anti Join
,而NOT IN
使用hashed subplan
(或甚至一个普通的subplan
如果子查询太大散列)
Answer 2:
如果你希望世界是一个两值的布尔地方,你必须阻止空(第三值)的情况下自己。
不要写在条款,允许列表中的侧空。 筛选出来!
common_id not in
(
select common_id from Table1
where common_id is not null
)
Answer 3:
表1表2或有common_id一些空值。 使用此查询,而不是:
select *
from Common
where common_id not in (select common_id from Table1 where common_id is not null)
and common_id not in (select common_id from Table2 where common_id is not null)
Answer 4:
select *
from Common c
where not exists (select t1.commonid from table1 t1 where t1.commonid = c.commonid)
and not exists (select t2.commonid from table2 t2 where t2.commonid = c.commonid)
Answer 5:
SELECT T.common_id
FROM Common T
LEFT JOIN Table1 T1 ON T.common_id = T1.common_id
LEFT JOIN Table2 T2 ON T.common_id = T2.common_id
WHERE T1.common_id IS NULL
AND T2.common_id IS NULL
Answer 6:
只是把我的头顶部...
select c.commonID, t1.commonID, t2.commonID
from Common c
left outer join Table1 t1 on t1.commonID = c.commonID
left outer join Table2 t2 on t2.commonID = c.commonID
where t1.commonID is null
and t2.commonID is null
我跑了几个测试,这里是我的结果WRT @ patmortech答案,并@ rexem的评论。
如果任一表1表2或上没有commonID索引,你会得到一个表扫描,但@ patmortech的查询仍然快两倍(对于100K行主表)。
如果既不是在commonID索引,你得到两个表扫描,差异可以忽略不计。
如果两者都在commonID索引中,“不存在”的查询中1/3的时间耗尽。
Answer 7:
让我们假设为common_id这些值:
Common - 1
Table1 - 2
Table2 - 3, null
我们要在共同的行返回,因为它不以任何其他表的存在。 然而,空抛出猴子扳手。
有了这些值,该查询等效于:
select *
from Common
where 1 not in (2)
and 1 not in (3, null)
这相当于:
select *
from Common
where not (1=2)
and not (1=3 or 1=null)
这是问题的开始。 当空比较, 答案是未知的 。 所以查询简化为
select *
from Common
where not (false)
and not (false or unkown)
虚假的或未知的未知:
select *
from Common
where true
and not (unknown)
真正的而不是未知的,也未知:
select *
from Common
where unknown
WHERE条件不返回记录,其中的结果是未知的,所以我们没有得到记录了。
应对的方法之一是使用存在运营商,而不是。存在是因为它的行而不是列的工作永远不会返回未知。 (A行要么存在,要么不;!没有行级这个空歧义)
select *
from Common
where not exists (select common_id from Table1 where common_id = Common.common_id)
and not exists (select common_id from Table2 where common_id = Common.common_id)
Answer 8:
这个工作对我来说:)
选择通用*
哪里
common_id不是在(选择ISNULL(common_id,从表1“伪数据”))
和common_id不是在(选择从表2 ISNULL(common_id,“伪数据”))
Answer 9:
select *,
(select COUNT(ID) from ProductMaster where ProductMaster.CatID = CategoryMaster.ID) as coun
from CategoryMaster
文章来源: SQL “select where not in subquery” returns no results