mysql菜鸟教程
11.3 左连接(LEFT JOIN)
在上一节的内连接中,我们只返回了匹配成功的记录。但有时我们需要保留左表中的所有记录,即使右表中没有匹配项。例如,查询所有学生及其班级信息,即使有些学生尚未分配班级,我们仍然希望看到这些学生的名字,班级名称显示为空。这正是 左连接(LEFT JOIN) 的典型应用场景。
一、什么是左连接?
左连接返回左表中的所有记录,以及右表中满足连接条件的记录。如果右表中没有匹配,则右表对应的列填充为 NULL。
用集合来理解:
左表(LEFT JOIN 左边的表)的所有行都会保留。
右表只保留匹配的行,不匹配的部分用 NULL 补齐。
二、基本语法
SELECT 列名 FROM 左表 LEFT [OUTER] JOIN 右表 ON 连接条件;
其中 OUTER 可以省略,通常直接写 LEFT JOIN。
三、基础示例:所有学生及其班级
继续使用之前的 students 和 classes 表:
students(左表)
classes(右表)
左连接查询
SELECT s.name, c.class_name FROM students s LEFT JOIN classes c ON s.class_id = c.class_id;
结果:
可以看到,学生“赵六”(class_id 为 NULL)虽然没有匹配的班级,但仍然出现在结果中,班级名称显示为 NULL。这正是左连接与内连接的根本区别。
四、左连接 vs 内连接
为了更直观地对比,我们把内连接的结果并列展示:
左连接保证了左表记录完整,适用于:
报表中需要显示所有主表记录,即使关联信息缺失。
数据检查时发现未匹配的数据(例如通过 WHERE 条件筛选右表列为 NULL 的记录,找出孤儿数据)。
五、多表左连接
左连接也可以连续使用。例如,除了班级信息,我们还想显示学生的成绩(来自 scores 表),但希望保留所有学生,包括没有成绩的学生。
scores 表(成绩表)
SELECT s.name, c.class_name, sc.course_name, sc.score FROM students s LEFT JOIN classes c ON s.class_id = c.class_id LEFT JOIN scores sc ON s.student_id = sc.student_id;
结果解读:
先左连接 students 和 classes,得到包含赵六在内的所有学生及其班级(可能为 NULL)。
再左连接 scores,保留所有学生,即使没有成绩(如王五、赵六)。
由于左连接的逐层保留特性,最终结果会包含所有学生,但可能有重复行(因为一个学生可能有多个成绩)。
六、ON 与 WHERE 的微妙区别
在外连接(包括左连接)中,ON 中的条件在连接阶段使用,WHERE 中的条件在连接完成后应用。这一点非常重要,直接影响结果。
错误示例:将右表的过滤条件写在 WHERE 中
假设我们只想查看学生及其班级,但只显示班级是“计算机1班”的班级信息,但仍然要保留所有学生(班级不匹配的显示 NULL)。如果写成:
SELECT s.name, c.class_name FROM students s LEFT JOIN classes c ON s.class_id = c.class_id WHERE c.class_name = '计算机1班';
结果会怎样?让我们推理一下:
左连接先将所有学生与班级连接,生成中间结果(包含赵六等)。
然后应用 WHERE 条件 c.class_name = '计算机1班',这会过滤掉班级名称不是“计算机1班”的行,包括班级为 NULL 的赵六(因为 NULL 不等于任何值)。
最终结果只包含班级匹配“计算机1班”的学生(张三和王五),而李四和赵六被过滤掉了,这违背了我们“保留所有学生”的初衷。
正确做法:将条件放在 ON 中
如果希望保留所有学生,但只匹配符合条件的班级(不匹配的显示 NULL),则应将条件放在 ON 中:
SELECT s.name, c.class_name FROM students s LEFT JOIN classes c ON s.class_id = c.class_id AND c.class_name = '计算机1班';
结果:
现在,所有学生都保留,但班级信息只显示“计算机1班”的班级名称(对李四来说,虽然 class_id=102,但 class_name 不是‘计算机1班’,所以匹配失败,班级显示 NULL)。这正是我们想要的。
因此,在外连接中,如果需要基于右表的条件进行筛选,务必考虑是将条件放在 ON 中还是 WHERE 中,明确你的业务需求。
七、右连接(RIGHT JOIN)
右连接与左连接对称,返回右表中的所有记录,左表没有匹配时补 NULL。其语法为:
SELECT 列名 FROM 左表 RIGHT JOIN 右表 ON 连接条件;
由于我们可以通过交换表顺序用左连接实现同样的效果,实际开发中右连接使用较少。例如,上面查询所有班级及其学生(即使班级无学生)可以写成:
SELECT c.class_name, s.name FROM students s RIGHT JOIN classes c ON s.class_id = c.class_id;
但更常见的写法是调换顺序使用左连接:
SELECT c.class_name, s.name FROM classes c LEFT JOIN students s ON c.class_id = s.class_id;
因此,通常推荐统一使用左连接,保持代码可读性。
八、左连接的常见应用
1、主表全保留:如所有用户及其订单信息,即使某些用户从未下单。
2、数据补全:将基础表与补充表连接,补充表可能没有对应项。
3、查找缺失数据:通过左连接后,筛选右表列 IS NULL 来找出左表中没有关联的记录。例如,找出从未下过单的用户:
SELECT u.* FROM users u LEFT JOIN orders o ON u.user_id = o.user_id WHERE o.order_id IS NULL;
4、填充默认值:结合 COALESCE 函数将 NULL 替换为默认值,如“未分配”。
九、性能考虑
左连接同样要求为连接列建立索引,以提高匹配速度。
尽量避免在大表上左连接后对右表列使用函数或复杂计算,可能导致无法使用索引。
如果左表非常大,而右表匹配率很低,左连接会产生大量 NULL 填充行,结果集大小仍等于左表行数,通常可以接受。
十、练习与思考
1、基于以下 employees 和 departments 表,写出左连接查询显示所有员工及其部门名称(即使部门不存在)。
employees:emp_id, emp_name, dept_id
departments:dept_id, dept_name
2、找出所有没有分配部门的员工(即 dept_id 在 departments 表中无匹配)。
3、如果要在左连接中同时限制部门名称为“技术部”,但依然显示所有员工,条件应写在 ON 还是 WHERE?
答案:
-- 1. 所有员工及其部门名称 SELECT e.emp_name, d.dept_name FROM employees e LEFT JOIN departments d ON e.dept_id = d.dept_id; -- 2. 未分配部门的员工 SELECT e.emp_name FROM employees e LEFT JOIN departments d ON e.dept_id = d.dept_id WHERE d.dept_id IS NULL; -- 3. 保留所有员工,只匹配技术部 SELECT e.emp_name, d.dept_name FROM employees e LEFT JOIN departments d ON e.dept_id = d.dept_id AND d.dept_name = '技术部';
小结
左连接是日常开发中与内连接并列的两大主力连接类型,熟练掌握它将使你能够灵活应对各种关联查询需求。

发表评论
所有评论