Skip to content

外连接退化为内连接


在外连接(LEFT JOIN / RIGHT JOIN)查询中,ONWHERE 的作用有所不同。ON 子句用于指定表之间的连接条件,确定主表和从表的匹配规则,同时也可以对从表的数据进行提前过滤,即在连接时就排除不符合条件的从表记录。对于外连接而言,ON 过滤不会丢掉主表记录,未匹配的从表字段会显示为 NULL。而 WHERE 子句用于对整个连接结果集进行过滤,如果在 WHERE 中对从表字段加上条件,可能会把原本保留的主表记录过滤掉,从而破坏外连接的意义。也就是说,条件放在 WHERE 子句中不当时,有可能使外连接的效果退化为内连接

假设有两张表:学生表成绩表,以学生表作为主表、成绩表作为从表来举例说明外连接的作用。

  • 学生表(主表)
学号姓名
1张三
2李四
3王五
  • 成绩表(从表)
学号课程分数
1数学90
1英语85
2数学70

注意:王五(学号3)没有成绩记录


SELECT 学生表.姓名, 成绩表.课程
FROM 学生表
LEFT JOIN 成绩表
ON 学生表.学号 = 成绩表.学号
AND 成绩表.课程 = '数学'; -- 条件在 ON

结果:

姓名课程
张三数学
李四数学
王五NULL

这才是 LEFT JOIN 的本意:所有学生都要出现,没数学成绩就显示 NULL


SELECT 学生表.姓名, 成绩表.课程
FROM 学生表
LEFT JOIN 成绩表 ON 学生表.学号 = 成绩表.学号
WHERE 成绩表.课程 = '数学'; -- 条件在 WHERE

结果:

姓名课程
张三数学
李四数学
王五消失了!

  1. 第一步:执行 LEFT JOIN,先得到这个中间结果。
姓名课程
张三数学
张三英语
李四数学
王五NULL
  1. 第二步:执行 WHERE 过滤

    • WHERE 成绩表.课程 = '数学'
    • 要求 课程 字段必须等于 '数学'
    • 但王五的 课程NULLNULL = '数学' 的结果是 UNKNOWN(不是 true)
    • 所以王五这行被 过滤掉了

  • 内连接(INNER JOIN) 的结果就是:只返回两表都匹配的记录
  • 上面错误写法的结果,和下面这个 INNER JOIN 完全一样
SELECT 学生表.姓名, 成绩表.课程
FROM 学生表
INNER JOIN 成绩表
ON 学生表.学号 = 成绩表.学号
WHERE 成绩表.课程 = '数学';

虽然使用了 LEFT JOIN(本应保留主表所有记录,从表无匹配时填充 NULL),但如果将从表的过滤条件写在 WHERE 子句中(WHERE 是对连接后的完整结果集进行过滤),就会把那些从表为 NULL 的行排除掉。这样一来,最终结果与 INNER JOIN 完全一致,这种现象就称为 “外连接退化为内连接


过滤目标推荐写法说明
主表字段(如学生姓名、学号)WHEREON 均可不影响主表记录的完整性
从表字段(如课程、分数)必须写在 ON若写在 WHERE,会导致无匹配的主表行被过滤,使 LEFT JOIN 退化为 INNER JOIN

“想保留主表全部记录,从表的条件千万别放 WHERE 里!”