我如何做一些与加入相反的事情?例如,从这两个表中选择表 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
答案 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”是一个虚构的名字,而不是你桌子的真实姓名。