文章目录
- 文章导图
- 前言
- 初始化数据-建表
- 两个表left jion
- 多表-left jion on c.bid=b.bid分析|
- 执行步骤和结果
- 理解
 
- 变形-修改c表数据
- 变形1
- 变形2
 
- 总结
 
- 多表-left jion on c.aid=a.aid分析
- 执行步骤和结果
- 理解
 
- 变形-修改c表数据
- 变形1
- 变形2
 
 
- 解答开头
- 总结
| Left join on系列文章 | 
|---|
| 测试一下你真的理解数据库左连接了吗? | 
| SQL连接与筛选:解析left join on和where的区别及典型案例分析 | 
| 深入剖析多个表left join on的执行步骤原理:实战案例解析与原理探讨 | 
文章导图

前言
日常工作中写SQL,我们会经常left join一堆表,我最多见过的有20多张的。。。(在一家外企,然后还用了一堆存储过程有几千行的,吐了。。。)那么对于left join on和前面表关联条件的时候,有的时候是紧挨着的表,有的是隔开的,有啥区别呢?具体看看这个
SELECT *
FROM a
LEFT JOIN b ON a.aid = b.aid
LEFT JOIN c ON b.bid = c.bid
LEFT JOIN d ON c.cid = d.cid
LEFT JOIN e ON d.did = e.did
LEFT JOIN f ON e.eid = f.eid
上面这种我们更好理解一点,就是一步步的去关联join on紧挨着的前面表,我们来看下面这种有啥区别?
SELECT *
FROM a
LEFT JOIN b ON a.aid = b.aid
LEFT JOIN c ON a.cid = c.cid
LEFT JOIN d ON a.did = d.did
LEFT JOIN e ON d.eid = e.eid
LEFT JOIN f ON c.fid = f.fid
这种关联关系是不是会看的眼花缭乱,一开始a和b是正常通过a.aid=b.aid,一下子join c的时候又是a.cid=c.cid,join f的时候条件又是c.fid=f.fid…
现在我们来简化一下上面的SQL,a 表主键是aid,b表是bid,c表是cid,两个语句有什么区别?如何理解?
select * from  a left join b on a.aid=b.aid  left join c on b.bid=c.bidselect * from  a left join b on a.aid=b.aid  left join c on a.aid=c.aid
这就是我们本篇文章的重点,相信理解了这两种,上面那种花里胡哨的各种left join 关联关系我们也能够手到擒来!
初始化数据-建表
这里我们把表的结构建的尽量足够简单,主要是为了理解我们的left join的整个过程
create table a
(aid    int          not nullprimary key,a_name varchar(100) null
);create table b
(bid int not nullprimary key,aid int null);create table c
(cid    int          not nullprimary key,bid    int          null,aid    int          null,c_name varchar(100) null
);
插入一些初始化数据
INSERT INTO bank.a (aid, a_name) VALUES (1, 'a1');
INSERT INTO bank.a (aid, a_name) VALUES (2, 'a2');
INSERT INTO bank.a (aid, a_name) VALUES (3, 'a3');INSERT INTO bank.b (bid, aid, b_name) VALUES (1, 1, 'b1');
INSERT INTO bank.b (bid, aid, b_name) VALUES (2, 2, 'b2');INSERT INTO bank.c (cid, bid, aid, c_name) VALUES (1, 1, 1, 'c1');
INSERT INTO bank.c (cid, bid, aid, c_name) VALUES (2, 2, 2, 'c2');a表数据
| aid | a_name | 
|---|---|
| 1 | a1 | 
| 2 | a2 | 
| 3 | a3 | 
b表数据
| bid | aid | b_name | 
|---|---|---|
| 1 | 1 | b1 | 
| 2 | 2 | b2 | 
c表数据
| cid | bid | aid | c_name | 
|---|---|---|---|
| 1 | 1 | 1 | c1 | 
| 2 | 2 | 2 | c2 | 
两个表left jion
如果只是2个表连接,我在之前的文章已经分析的很清楚了SQL连接与筛选:解析left join on和where的区别及典型案例分析
SELECT * FROM a LEFT JOIN b ON a.aid = b.aid
执行结果应该是下面这个样子,这里就不过多解释,不理解可以看我之前的文章
| aid | a_name | bid | aid | b_name | 
|---|---|---|---|---|
| 1 | a1 | 1 | 1 | b1 | 
| 2 | a2 | 2 | 2 | b2 | 
| 3 | a3 | 
那么现在再多left jion 一张表(或者多张表),原理是类似的,但是会分为2种前情况,
- 一种是left join紧挨着的这张表,也就是在原有2表关联的基础上加上left jion on c.bid=b.bid,但是它的left join是紧挨着的b表
- 一种是left join非紧挨着的表,也就是在原有2表关联的基础上加上left jion on c.aid=a.aid,但是它的left join是非紧挨着的a表
接下来我们分别解析这两种情况
多表-left jion on c.bid=b.bid分析|
这种查询适用于你想要根据表
b的某些条件或关系来过滤或连接表c的情况。这种情况下,表c与表a的关联是间接的,通过表b实现。
SQL语句如下:
SELECT *
FROM aLEFT JOIN b ON a.aid = b.aidLEFT JOIN c ON b.bid = c.bid
执行步骤和结果
-  第一步: 执行 a LEFT JOIN b ON a.aid = b.aid:- 这会将表 a中的每一行与表b中的行进行连接,条件是a.aid = b.aid。
- 如果表 b中没有对应的aid,则结果中b的列将填充NULL。
 
- 这会将表 
-  第二步: 对第一步的结果再进行 LEFT JOIN c ON b.bid = c.bid:- 这会将第一步的结果与表 c中的行进行连接,条件是b.bid = c.bid。
- 如果表 c中没有对应的bid,则结果中c的列将填充NULL。
 
- 这会将第一步的结果与表 

理解
- 如果表 b中没有匹配a.aid的行,那么b和c的所有列都会是NULL。
- 即使 a和b有匹配,但b.bid在表c中没有匹配的行,c的列也会是NULL。
变形-修改c表数据
变形1
第一种情况,我们来修改C表数据,将bid由原来的2,修改成了3
| cid | bid | aid | c_name | 
|---|---|---|---|
| 1 | 1 | 1 | c1 | 
| 2 | 3(由2修改成了3) | 3 | c2 | 
而原来的b表是没有bid=3的数据,那么继续执行原来的SQL,结果如下
- c表通过bid与b表关联,对于b表的bid=1能找到,所以正常显示了c表的数据
- 对于b表的bid=2,在c表找不到关联数据,就显示NULL

变形2
第二种情况,我们来修改C表数据,将bid由原来的2,修改成了1
| cid | bid | aid | c_name | 
|---|---|---|---|
| 1 | 1 | 1 | c1 | 
| 2 | 1(由2修改成了1) | 3 | c2 | 
对于b表的bid=1,会再c表中找到2条数据,所以b表bid=1数据显示2遍一样的,然后再对应上c表的2条不一样的数据

总结
以上这种left jion on c.bid=b.bid再多关联一张表c,分析起来和2张表关联a和b是一样的,我们这里只是多举几种例子让大家更深刻理解一下
接下来的left jion on c.aid=a.aid才是我们的重点,也就是关联的表是前面的表,也就是不是挨着的。
多表-left jion on c.aid=a.aid分析
这种查询适用于当你直接在表
a和表c之间建立关系时。这里表b的加入不影响表a与表c之间的连接。
SELECT *
FROM aLEFT JOIN b ON a.aid = b.aidLEFT JOIN c ON a.aid = c.aid;
执行步骤和结果
-  第一步: 执行 a LEFT JOIN b ON a.aid = b.aid:- 这部分和第一个查询是相同的,将表 a和表b进行连接,条件是a.aid = b.aid。
- 如果没有匹配的 aid,则b的列将填充NULL。
 
- 这部分和第一个查询是相同的,将表 
-  第二步: 对第一步的结果再进行 LEFT JOIN c ON a.aid = c.aid:- 这会将第一步的结果与表 c中的行进行连接,条件是a.aid = c.aid。
- 如果表 c中没有对应的aid,则结果中c的列将填充NULL。
 
- 这会将第一步的结果与表 

结果分析:
- 忽略b表数据,只看当前关联的a和c表即可
- 可以发现a表的aid=1,2都能在c表找到数据,所以c表数据也是全的
理解
简单来说,我们其实在每一次关联的时候,只看关联的两个表的数据,中间的别的表不管有多少个,都不用管,即可
- 不论表 b是否有匹配的行,a和c都是直接连接在一起的,条件是a.aid = c.aid。
- 如果 a.aid在表c中没有匹配的行,c的列将会是NULL,无论b是否有匹配的bid。
变形-修改c表数据
变形1
第一种情况,我们同样来修改C表数据,将aid由原来的2,修改成了4
| cid | bid | aid | c_name | 
|---|---|---|---|
| 1 | 1 | 1 | c1 | 
| 2 | 2 | 4(由2修改成了4) | c2 | 
而原来的a表是没有aid=4的数据,那么继续执行原来的SQL,结果如下

- c表通过aid与a表关联,对于a表的aid=1能找到,所以正常显示了c表的数据
- 对于c表的aid=4,在a表找不到关联数据,就显示NULL
变形2
第二种情况,我们来修改c表数据,将aid由原来的2,修改成了1
| cid | bid | aid | c_name | 
|---|---|---|---|
| 1 | 1 | 1 | c1 | 
| 2 | 2 | 1(由2修改成了1) | c2 | 
对于a表的aid=1,会再c表中找到2条数据,所以a表aid=1数据显示2遍一样的,然后再对应上c表的2条不一样的数据

解答开头
那么我们再来看下最开头的SQL
SELECT *
FROM a
LEFT JOIN b ON a.aid = b.aid
LEFT JOIN c ON a.cid = c.cid
LEFT JOIN d ON a.did = d.did
LEFT JOIN e ON d.eid = e.eid
LEFT JOIN f ON c.fid = f.fid
让我们逐步解析这个查询:
-  从表 a开始:SELECT * FROM a
-  左连接表 b:LEFT JOIN b ON a.aid = b.aid这意味着表 a中的每一行都会与表b中aid相等的行进行匹配。如果表b中没有匹配的行,结果中对应表b的列将包含NULL值。
-  左连接表 c:LEFT JOIN c ON a.cid = c.cid类似地,表 a中的每一行会与表c中cid相等的行进行匹配。
-  左连接表 d:LEFT JOIN d ON a.did = d.did表 a中的每一行会与表d中did相等的行进行匹配。
-  左连接表 e:LEFT JOIN e ON d.eid = e.eid这里需要注意的是,表 e是通过表d连接的,而不是直接通过表a。这意味着表d中的每一行会与表e中eid相等的行进行匹配。
-  左连接表 f:LEFT JOIN f ON c.fid = f.fid类似地,表 f是通过表c连接的,而不是直接通过表a。表c中的每一行会与表f中fid相等的行进行匹配。
总结一下,这个查询的结果将包含表 a 中的所有行,以及与表 b、c、d、e 和 f 中匹配的行。如果某个表中没有匹配的行,结果中对应该表的列将包含 NULL 值。
总结
这两条SQL其实理解了以后,我们会发现其他类似的SQL执行步骤和原理都是一样的
select * from a left join b on a.aid=b.aid left join c on b.bid=c.bidselect * from a left join b on a.aid=b.aid left join c on a.aid=c.aid
其实大的前提就是我们要记住:
- 我们在每一次关联的时候,只看当前执行到的关联的两个表的数据,中间的别的表不管有多少个,都不用管即可
- 比如当前执行left join on a.aid=b.bid,那么我们主要关注a表和b表之间的数据
- 然后继续执行到left join on a.aid=b.bid left join a.aid=c.aid时,就是在前面数据的基础上 (也就是执行完SELECT * FROM a LEFT JOIN b ON a.aid = b.aid,然后把这个数据当做一个整体) ,再去看我们关联的表即可