深入剖析多个表left join on的执行步骤原理:实战案例解析与原理探讨

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.bid

select * 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 null
        primary key,
    a_name varchar(100) null
);

create table b
(
    bid int not null
        primary key,
    aid int null
   
);

create table c
(
    cid    int          not null
        primary 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 a
         LEFT JOIN b ON a.aid = b.aid
         LEFT JOIN c ON b.bid = c.bid

执行步骤和结果

  1. 第一步: 执行 a LEFT JOIN b ON a.aid = b.aid

    • 这会将表 a 中的每一行与表 b 中的行进行连接,条件是 a.aid = b.aid
    • 如果表 b 中没有对应的 aid,则结果中 b 的列将填充 NULL
  2. 第二步: 对第一步的结果再进行 LEFT JOIN c ON b.bid = c.bid

    • 这会将第一步的结果与表 c 中的行进行连接,条件是 b.bid = c.bid
    • 如果表 c 中没有对应的 bid,则结果中 c 的列将填充 NULL

image-20240713122236470

理解

  • 如果表 b 中没有匹配 a.aid 的行,那么 bc 的所有列都会是 NULL
  • 即使 ab 有匹配,但 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

image-20240713121812692

变形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条不一样的数据

image-20240713124021452

总结

以上这种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 a
         LEFT JOIN b ON a.aid = b.aid
         LEFT JOIN c ON a.aid = c.aid;

执行步骤和结果

  1. 第一步: 执行 a LEFT JOIN b ON a.aid = b.aid

    • 这部分和第一个查询是相同的,将表 a 和表 b 进行连接,条件是 a.aid = b.aid
    • 如果没有匹配的 aid,则 b 的列将填充 NULL
  2. 第二步: 对第一步的结果再进行 LEFT JOIN c ON a.aid = c.aid

    • 这会将第一步的结果与表 c 中的行进行连接,条件是 a.aid = c.aid
    • 如果表 c 中没有对应的 aid,则结果中 c 的列将填充 NULL

image-20240713130424223

结果分析:

  • 忽略b表数据,只看当前关联的a和c表即可
  • 可以发现a表的aid=1,2都能在c表找到数据,所以c表数据也是全的

理解

简单来说,我们其实在每一次关联的时候,只看关联的两个表的数据,中间的别的表不管有多少个,都不用管,即可

  • 不论表 b 是否有匹配的行,ac 都是直接连接在一起的,条件是 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,结果如下

image-20240713131833810

  • 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条不一样的数据

image-20240713132249605

解答开头

那么我们再来看下最开头的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

让我们逐步解析这个查询:

  1. 从表 a 开始

    SELECT *
    FROM a
    
  2. 左连接表 b

    LEFT JOIN b ON a.aid = b.aid
    

    这意味着表 a 中的每一行都会与表 baid 相等的行进行匹配。如果表 b 中没有匹配的行,结果中对应表 b 的列将包含 NULL 值。

  3. 左连接表 c

    LEFT JOIN c ON a.cid = c.cid
    

    类似地,表 a 中的每一行会与表 ccid 相等的行进行匹配。

  4. 左连接表 d

    LEFT JOIN d ON a.did = d.did
    

    a 中的每一行会与表 ddid 相等的行进行匹配。

  5. 左连接表 e

    LEFT JOIN e ON d.eid = e.eid
    

    这里需要注意的是,表 e 是通过表 d 连接的,而不是直接通过表 a。这意味着表 d 中的每一行会与表 eeid 相等的行进行匹配。

  6. 左连接表 f

    LEFT JOIN f ON c.fid = f.fid
    

    类似地,表 f 是通过表 c 连接的,而不是直接通过表 a。表 c 中的每一行会与表 ffid 相等的行进行匹配。

总结一下,这个查询的结果将包含表 a 中的所有行,以及与表 bcdef 中匹配的行。如果某个表中没有匹配的行,结果中对应该表的列将包含 NULL 值。

总结

这两条SQL其实理解了以后,我们会发现其他类似的SQL执行步骤和原理都是一样的

select * from a left join b on a.aid=b.aid left join c on b.bid=c.bid

select * from a left join b on a.aid=b.aid left join c on a.aid=c.aid

其实大的前提就是我们要记住:

  1. 我们在每一次关联的时候,只看当前执行到的关联的两个表的数据,中间的别的表不管有多少个,都不用管即可
  2. 比如当前执行left join on a.aid=b.bid,那么我们主要关注a表和b表之间的数据
  3. 然后继续执行到left join on a.aid=b.bid left join a.aid=c.aid时,就是在前面数据的基础上 (也就是执行完SELECT * FROM a LEFT JOIN b ON a.aid = b.aid,然后把这个数据当做一个整体) ,再去看我们关联的表即可

相关推荐

  1. 深入剖析:MySQL Innodb事务实现原理

    2024-07-13 17:48:02       48 阅读
  2. 深入探索Spring Boot:原理实践

    2024-07-13 17:48:02       23 阅读
  3. springboot线程原理剖析

    2024-07-13 17:48:02       72 阅读
  4. 深入探讨YUV图像处理:理论原理OpenCV实践

    2024-07-13 17:48:02       37 阅读
  5. 深入探讨YUV图像处理:理论原理OpenCV实践

    2024-07-13 17:48:02       38 阅读
  6. 深入解析语言模型:原理实战评估

    2024-07-13 17:48:02       38 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-13 17:48:02       70 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-13 17:48:02       74 阅读
  3. 在Django里面运行非项目文件

    2024-07-13 17:48:02       62 阅读
  4. Python语言-面向对象

    2024-07-13 17:48:02       72 阅读

热门阅读

  1. 【车载开发系列】汽车开发常见概念理解

    2024-07-13 17:48:02       21 阅读
  2. 深入理解Spring Boot中的定时任务调度

    2024-07-13 17:48:02       20 阅读
  3. 大数据平台建设概要

    2024-07-13 17:48:02       21 阅读
  4. python文件

    2024-07-13 17:48:02       23 阅读
  5. python运行环境在新旧电脑间迁移

    2024-07-13 17:48:02       21 阅读
  6. LeetCode题练习与总结:最小栈--155

    2024-07-13 17:48:02       19 阅读
  7. C++catch (...)陈述

    2024-07-13 17:48:02       17 阅读
  8. git切换远程仓库地址

    2024-07-13 17:48:02       24 阅读
  9. 自动发送每日电子邮件报告的 Python 脚本

    2024-07-13 17:48:02       18 阅读
  10. 使用Spring Boot集成Zipkin分布式追踪

    2024-07-13 17:48:02       20 阅读