You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何Inner Join会覆盖之前的Outer Join?SQL执行逻辑解析

为什么左连后接内连会变成全内连?SQL连接的执行逻辑拆解

嘿,这个问题真的问到点子上了——很多人刚接触多表连接时都会踩这个坑,核心是没搞懂SQL引擎组合连接时的逻辑执行顺序,我给你一步步拆解清楚:

第一步:先执行A LEFT OUTER JOIN B

SQL里FROM子句的连接是按从左到右的逻辑顺序依次生成中间结果集的(虽然数据库优化器可能调整物理执行顺序,但逻辑上是这个流程)。
当你执行A LEFT OUTER JOIN B ON B.ID = A.ID时,得到的中间结果集包含:

  • A表的所有行
  • 匹配上B表的行,会带上对应的B列值
  • 没匹配上B表的A行,B列全为NULL

举个简单例子:
假设A有ID 1、2、3;B有ID 1、2
这一步的结果是:

A.IDB.ID
11
22
3NULL

第二步:用中间结果集执行INNER JOIN C

接下来,SQL引擎会拿上面这个中间结果集,去和C表做INNER JOIN C ON C.ID = B.ID。
这里的关键是:内连(INNER JOIN)要求两边的匹配条件必须成立,而NULL和任何值的比较结果都是不成立的(包括NULL和NULL比较)。
所以刚才中间结果里的第三行(A.ID=3,B.ID=NULL),因为C.ID = NULL永远不成立,会被内连直接过滤掉;而第二行(B.ID=2)如果C表里没有ID=2的行,也会被过滤。

还是用上面的例子,假设C只有ID=1:
这一步内连后的结果就只剩:

A.IDB.IDC.ID
111

最后你选A.*,就只能拿到A.ID=1的行——这看起来就像三个表全做了内连,但本质是左连后的NULL行被后续的内连过滤了。

怎么保留A的所有行?

如果你的需求是保留A的所有行,同时仅在B存在时关联C,有两种写法:

  1. 把第二个内连改成左连:

    SELECT A.* FROM A LEFT OUTER JOIN B ON B.ID = A.ID LEFT OUTER JOIN C ON C.ID = B.ID
    

    这样即使B.ID是NULL,或者C没有匹配的行,A的行都会保留。

  2. 先让B和C做内连,再和A左连(用括号明确优先级):

    SELECT A.* FROM A LEFT OUTER JOIN (B INNER JOIN C ON C.ID = B.ID) ON B.ID = A.ID
    

    这种写法会先得到B和C的内连结果,再让A左连这个结果,同样能保留A的所有行。

内容的提问来源于stack exchange,提问作者ismetguzelgun

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:11:20