使用连接从 table 获取记录,其中连接中的记录不包含特定值

Get records from table with join where records in join not contain specific value

我有两个 table:

Table 用户:

create table user (
   id bigserial not null primary key,
   username varchar(256),
   active boolean not null default true
);

和table地址:

create table address (
   id bigserial not null primary key,
   user_id integer not null,
   country varchar(256),
   city varchar(256),
   street varchar(256)
);

以一些数据为例:

insert into user(id, username, active) values (1, 'john', true);
insert into user(id, username, active) values (2, 'alex', true);
insert into user(id, username, active) values (3, 'alice', true);
insert into user(id, username, active) values (4, 'tom', true);
insert into user(id, username, active) values (5, 'dave', true);

insert into address(id, user_id, country, city, street) values (1, 1, 'Germany', 'Berlin', '');
insert into address(id, user_id, country, city, street) values (2, 2, 'Germany', 'Berlin', '');
insert into address(id, user_id, country, city, street) values (3, 2, 'Great Britain', 'London', '');
insert into address(id, user_id, country, city, street) values (4, 3, 'France', 'Paris', '');
insert into address(id, user_id, country, city, street) values (5, 4, 'USA', 'New York', '');
insert into address(id, user_id, country, city, street) values (6, 5, 'South Korea', 'Seoul', '');

每个用户可以有多个地址。我需要让所有在他们的地址集中没有特定国家地址的用户,例如 'Germany'.

我尝试了什么:

select u.* from user u
left join address a on u.id=a.user_id where a.country is not like '%Germany%'

但是 returns 用户,他们有特定国家的地址但也有其他地址,哪个国家与特定国家不同,例如上面使用的数据是 alex,他有两个地址德国和英国:

id  username  active
--------------------
2   alex      True
3   alice     True
4   tom       True
5   dave      True

有什么建议可以让我做这样的查询吗?

您的代码检查每个用户是否至少有一个德国以外的地址,而您要确保他们有 none.

我会推荐 not exists:

select c.*
from client c
where not exists (
    select 1
    from address a 
    where a.user_id = c.id and a.country = 'Germany'
)

此查询将利用 address(user_id, country) 上的索引。

注意不清楚你的table叫user还是client...我用的是后者

请注意,这也 returns 根本没有地址的客户端。如果这不是您想要的,那么另一种方法是使用聚合:

select c.*
from client c
inner join address on a.user_id = c.id
group by c.id
having not bool_or(a.country = 'Germany')

这是查询:

select user_id from address where country = 'Germany'

returns 您要过滤掉的所有用户。
NOT IN:

一起使用
select u.* 
from user u
where id not in (select user_id from address where country = 'Germany')

参见demo
结果:

> id | username | active
> -: | :------- | :-----
>  3 | alice    | t     
>  4 | tom      | t     
>  5 | dave     | t