多表联结是两个或多个表的列合并到一个结果集中。Databend 中支持的连接类型有 inner join 、cross join 、natural join 、left join 、right join 、left anti join 、right anti join 、full outer join。
在这里我们只讲最常见的几种,其中 inner join 、left join 、right join 最常用。
数据准备:
drop table if exists vip_info;
create table if not exists vip_info (
client_id int,
region varchar
);
drop table if exists purchase_records;
create table if not exists purchase_records (
client_id int,
item varchar,
qty int
);
drop table if exists gift;
create table if not exists gift (
gift varchar
);
insert into vip_info values
(101, 'Toronto'),
(102, 'Quebec'),
(103, 'Vancouver');
insert into purchase_records values
(100, 'Croissant', 2000),
(102, 'Donut', 3000),
(103, 'Coffee', 6000),
(106, 'Soda', 4000);
insert into gift values
('Croissant'),
('Donut'),
('Coffee'),
('Soda');
内连接使用 inner join 语法,其中 inner 可以省略,返回满足结果集中连接条件的行。当列相同时,可以将 on 转化成 using 来简化语法。
需求:根据准备的数据,返回VIP客户的购买记录。
select t2.client_id
, t2.item
, t2.qty
from vip_info as t1
join purchase_records as t2
using (client_id);
交叉连接使用 cross join 语法,也可以使用 inner join 不加连接条件实现,返回一个结果集,该结果集包括第一个表中的每一行,与第二个表中的每一行连接。
需求:将每个礼品选项分配给每个VIP客户。
-- 方法一:使用 cross join
select t1.*,t2.*
from vip_info as t1
cross join gift as t2;
-- 方法二:使用 inner join 但是没有加匹配条件
select t1.*,t2.*
from vip_info as t1
join gift as t2;
左连接使用 left join 语法,返回左表中的所有记录,以及右表中的匹配记录。如果没有匹配,结果是右侧的 NULL 记录。
需求:返回所有VIP客户的购买记录,如果VIP客户没有购买,购买记录将为 NULL。
select t1.*,t2.*
from vip_info as t1
left join purchase_records as t2
using (client_id);
左连接使用 right join 语法,返回右表中的所有记录,以及左表中匹配的记录。如果没有匹配,结果是左侧的 NULL 记录。
需求:返回所有客户的购买记录,如果不是VIP客户,VIP客户信息将为 NULL。
select t1.*,t2.*
from vip_info as t1
right join purchase_records as t2
on t1.client_id = t2.client_id;
左侧反连接使用 left anti join 语法,从左侧表中返回右侧表中没有匹配行的行。这是 Databend 的语法,建议使用 left join 配合 where 实现。
-- 方法一:使用 left anti join 实现,只能返回 t1 表的信息
select *
from vip_info as t1
left anti join purchase_records as t2
on t1.client_id = t2.client_id;
-- 方法二:使用 left join 配合 where 实现
select t1.*, t2.*
from vip_info as t1
left join purchase_records as t2
on t1.client_id = t2.client_id
where t2.client_id is null;
+-----------+---------+-----------+------+-----+
| client_id | region | client_id | item | qty |
+-----------+---------+-----------+------+-----+
| 101 | Toronto | NULL | NULL | NULL|
+-----------+---------+-----------+------+-----+
右反连接使用 right anti join 语法,从右表返回左表中没有匹配行的行。这是 Databend 的语法,建议使用 left join 配合 where 实现。
-- 方法一:使用 left anti join 实现,只能返回 t1 表的信息
select *
from vip_info as t1
right anti join purchase_records as t2
on t1.client_id = t2.client_id;
-- 方法二:使用 left join 配合 where 实现
select t1.*, t2.*
from vip_info as t1
right join purchase_records as t2
on t1.client_id = t2.client_id
where t1.client_id is null;
+-----------+---------+-----------+-----------+-----+
| client_id | region | client_id | item | qty |
+-----------+---------+-----------+-----------+-----+
| NULL | NULL | 100 | Croissant | 2000|
+-----------+---------+-----------+-----------+-----+
| NULL | NULL | 106 | Soda | 4000|
+-----------+---------+-----------+-----------+-----+
全连接使用 full outer join 返回两个表中的所有行,在可以匹配的地方匹配行,并在不存在匹配行的地方放置NULL。
-- 方法一:使用 full outer join 语法
select t1.*, t2.*
from vip_info as t1
full outer join purchase_records as t2
on t1.client_id = t2.client_id;
-- 方法二:使用 left join、right join 和 union 实现
select t1.*, t2.*
from vip_info as t1
left join purchase_records as t2
on t1.client_id = t2.client_id
union
select t1.*, t2.*
from vip_info as t1
right join purchase_records as t2
on t1.client_id = t2.client_id;
多表联结语法很简单,不同数据库可能语法不一样,但只要掌握 inner join、left join 、right join 三种语法,配合 where 或者 union 基本上可以解决所有相关的多表连接问题,赶紧实践动起来。
参考资料: