SQL选择没有连接对的行

use*_*976 1 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
Run Code Online (Sandbox Code Playgroud)

得到这个:

result:
name
----
six 
seven
Run Code Online (Sandbox Code Playgroud)

Cra*_*ger 5

这称为反连接.

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

对于你的例子,这是一个左反半连接:

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

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

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;
Run Code Online (Sandbox Code Playgroud)

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

select a.id, a.name
from alice a
where not exists (select 1 from bob b where b.a_id = a.id);
Run Code Online (Sandbox Code Playgroud)

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

可以使用not in:

select a.id, a.name
from alice a
where a.id not in (select b.a_id from bob);
Run Code Online (Sandbox Code Playgroud)

但:

  • 你必须确保有可以在子查询结果没有空,因为1 not in (2, null)null没有true;

  • 效率低得多

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