SQL“选择哪里都不在子查询”不返回任何结果(SQL “select where not in su

2019-07-17 15:24发布

免责声明:我想通了这个问题(我认为),但我想添加这个问题上堆栈溢出,因为我不能(容易)在任何地方找到它。 另外,有些人可能有一个更好的答案比我好。

我有其中一个表的“共同”是由其他几个表格中引用的数据库。 我想看看在公用表什么纪录被孤立的(即有任何其他表没有引用)。

我跑这个查询:

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 INNOT EXISTSLEFT JOIN / IS NULLSQL Server
  • NOT INNOT EXISTSLEFT JOIN / IS NULLPostgreSQL
  • NOT INNOT EXISTSLEFT JOIN / IS NULLOracle
  • NOT INNOT EXISTSLEFT JOIN / IS NULLMySQL

有三种方法可以做到这样的查询:

  • 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 NULLNOT EXISTS将返回3NOT IN将返回什么 (因为它总是求值FALSENULL )。

MySQL ,如果在非空的列, LEFT JOIN / IS NULLNOT IN是一点点(百分之几)更有效超过NOT EXISTS 。 如果列可以为空, NOT EXISTS是最有效的(同样,没有多少)。

Oracle中,所有三个查询产生相同的计划(一个ANTI JOIN )。

SQL ServerNOT IN / NOT EXISTS更有效率,因为LEFT JOIN / IS NULL不能被优化到ANTI JOIN通过其优化。

PostgreSQLLEFT JOIN / IS NULLNOT 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