文章目录
- 文章导图
- 前言
- 初始化数据-建表
- 两个表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
,然后把这个数据当做一个整体) ,再去看我们关联的表即可