2008-09-29 58 views
23

我有两个表连接在一起。如何查找未加入的记录?

A有里许多

通常你会用:

select * from a,b where b.a_id = a.id 

要从已在B A记录获取所有的记录。

我该如何得到一个在b中没有任何内容的记录?

回答

42
select * from a where id not in (select a_id from b) 

或者像其他一些人对这个主题说:

select a.* from a 
left outer join b on a.id = b.a_id 
where b.a_id is null 
2

选择*从其中id不是(从B选择A_ID)

+1

这将是非常昂贵的,因为引擎必须在完全生成子查询之后才能开始消除元组中的元组。一般来说不是一个好主意。 – dland 2008-09-30 11:07:04

10
select * from a 
left outer join b on a.id = b.a_id 
where b.a_id is null 
+0

我认为这个左外连接将比'in'子句执行得更好,除非查询优化器将它们视为相同... – Codewerks 2008-09-29 23:09:25

+0

它几乎可以做到。一探究竟。 – 2008-09-29 23:12:16

+0

是的,有趣的是,查询计划有一个额外的strep(Filter)用于左连接,'where in'被解析为'right anti semi join'...无论如何... – Codewerks 2008-09-29 23:14:36

5

另一种方法:

select * from a where not exists (select * from b where b.a_id = a.id) 

“存在”的方法是有用的,如果th ere是您需要附加到内部查询的其他一些“where”子句。

1

你可能会得到很多更好的性能(比使用“不”),如果你使用一个外连接:

select * from a left outer join b on a.id = b.a_id where b.a_id is null; 
0

写它

select a.* from a left outer join b on a.id = b.id where b.id is null

哎哟的另一种方法,殴打Nathan :)

0

这将保护您免受IN子句中的空值,这可能会导致意外的行为。

选择*从其中id不是(从B选择[一ID]其中[一ID]不为空

3
SELECT id FROM a 
EXCEPT 
SELECT a_id FROM b; 
0

在案件的一个连接是相当快的,但是当我们从数据库中删除了由于外键导致的大约5000万条记录和4个以上连接的记录,这需要几分钟的时间。 更快捷地使用WHERE NOT IN条件是这样的:

select a.* from a 
where a.id NOT IN(SELECT DISTINCT a_id FROM b where a_id IS NOT NULL) 
//And for more joins 
AND a.id NOT IN(SELECT DISTINCT a_id FROM c where a_id IS NOT NULL) 

我也可以推荐使用这种方法删除的情况下,我们没有配置级联删除。 此查询只需要几秒钟。

0

第一种方法是

select a.* from a where a.id not in (select b.ida from b) 

第二种方法是

select a.* 
    from a left outer join b on a.id = b.ida 
    where b.ida is null 

第一种方法是非常昂贵的。第二种方法更好。

使用PostgreSql 9.4,我做了“解释查询”功能和第一个查询,成本为cost = 0.00 ..1982043603.32。 相反联接查询作为成本费用= 45946.77..45946.78

比如我搜索不与任何车辆兼容的所有产品。我有100k产品和超过100万的兼容性。

select count(*) from product a left outer join compatible c on a.id=c.idprod where c.idprod is null 

连接查询花费了大约5秒钟,而在3分钟后子查询版本从未结束。