SQL选择没有连接对的行

时间:2014-04-07 16:34:22

标签: sql postgresql join

我如何做一些与加入相反的事情?例如,从这两个表中选择表 alice 中不在表 bob 中的值:

alice:
id|name
--+----
1 |one
2 |two
3 |three
6 |six
7 |seven

bob:
id|a_id
--+----
15|1
16|2
17|3

得到这个:

result:
name
----
six 
seven

3 个答案:

答案 0 :(得分:5)

这称为anti-join

一般的想法是进行左,右或全外连接,并过滤以仅查找外侧为空的行。

对于您的示例案例,这是一个左反半连接:

select a.id, a.name
from alice a
left outer join bob b on (a.id = b.a_id)
where b.id is null;

但是也可以通过完全外连接找到两侧的不匹配:

select a.id, a.name
from alice a
full outer join bob b on (a.id = b.a_id)
where b.id is null
   or a.id is null;

对于左反连接方法,您可以使用not exists

select a.id, a.name
from alice a
where not exists (select 1 from bob b where b.a_id = a.id);

虽然在实践中,PostgreSQL仍会将其转换为连接形式。

可以改为使用not in

select a.id, a.name
from alice a
where a.id not in (select b.a_id from bob);

但:

  • 您必须确保子查询结果中没有空值,因为1 not in (2, null) null不是true;

  • 效率低得多

所以通常使用反连接或存在子查询是非常优选的。

答案 1 :(得分:4)

第一直觉是使用子查询,并结合NOT IN

SELECT name 
  FROM alice 
 WHERE id NOT IN (SELECT a_id 
                    FROM bob);

但是,a little more efficient方式是使用LEFT JOIN

SELECT a.name
  FROM alice a
       LEFT JOIN bob b
            ON a.id = b.a_id
 WHERE b.a_id IS NULL;

答案 2 :(得分:2)

SELECT name FROM alice WHERE id NOT IN
    (SELECT a_id FROM bob)

我希望“table a”是一个虚构的名字,而不是你桌子的真实姓名。