前言
在MySQL数据库的多表查询中,连接查询(JOIN) 是一项至关重要的核心技能。它能够将两张甚至多张表中的数据,按照指定的关联关系进行整合,形成一张完整的虚拟结果集。本文将以一张核心知识图谱为主线,从语法结构、适用场景、代码示例三个维度,全面解析MySQL连接查询的各类操作。

一、核心知识点总览
在动手编写SQL语句之前,我们先梳理清楚几种连接类型的基本概念。下表归纳了它们的关键逻辑和语法特点:
| 连接类型 | 语法 | 核心逻辑 | 结果特点 |
|---|---|---|---|
| 内连接(INNER JOIN) | A INNER JOIN B ON 关联条件 | 仅返回两张表中匹配成功的记录 | 无匹配数据不显示 |
| 左连接(LEFT JOIN) | A LEFT JOIN B ON 关联条件 | 以左表 A 为主,匹配右表 B;左表全部显示,右表无匹配则填充 NULL | 左表数据完整,右表按需补空 |
| 右连接(RIGHT JOIN) | A RIGHT JOIN B ON 关联条件 | 以右表 B 为主,匹配左表 A;右表全部显示,左表无匹配则填充 NULL | 右表数据完整,左表按需补空 |
| 复合条件连接 | 连接查询 + 多条件过滤 | 在连接基础上,追加 WHERE/ON 多条件筛选 | 精准过滤关联数据 |
二、准备测试数据
理论知识需要结合实践才能深入理解,接下来我们创建两张表,将所有示例完整执行一遍。
1. 学生表student(左表)
CREATE TABLE score ( score_id INT PRIMARY KEY AUTO_INCREMENT, stu_id INT NOT NULL, subject VARCHAR(20) NOT NULL, score INT NOT NULL, FOREIGN KEY (stu_id) REFERENCES student(stu_id));INSERT INTO score (stu_id, subject, score) VALUES(1, '语文', 85),(1, '数学', 92),(2, '语文', 78),(3, '数学', 88); -- 赵六(stu_id=4)无成绩
2. 成绩表score(右表)
CREATE TABLE score ( score_id INT PRIMARY KEY AUTO_INCREMENT, stu_id INT NOT NULL, subject VARCHAR(20) NOT NULL, score INT NOT NULL, FOREIGN KEY (stu_id) REFERENCES student(stu_id));INSERT INTO score (stu_id, subject, score) VALUES(1, '语文', 85),(1, '数学', 92),(2, '语文', 78),(3, '数学', 88); -- 赵六(stu_id=4)无成绩
三、各连接类型详解 + 代码示例
1. 内连接查询(INNER JOIN)
核心逻辑
内连接是日常开发中使用频率最高的连接方式,仅返回两张表中满足关联条件的记录,可以理解为“取两张表的交集”。
- 等价语法:
SELECT * FROM A,B WHERE A.id = B.id(隐式内连接) - 标准语法:
SELECT * FROM A INNER JOIN B ON A.id = B.id(显式内连接,推荐使用)
代码示例
-- 显式内连接:查询有成绩的学生信息+成绩SELECT s.stu_id, s.stu_name, s.class, sc.subject, sc.scoreFROM student sINNER JOIN score sc ON s.stu_id = sc.stu_id;
运行结果
| stu_id | stu_name | class | subject | score |
|---|---|---|---|---|
| 1 | 张三 | 一班 | 语文 | 85 |
| 1 | 张三 | 一班 | 数学 | 92 |
| 2 | 李四 | 二班 | 语文 | 78 |
| 3 | 王五 | 一班 | 数学 | 88 |
说明
- 赵六(stu_id=4)因为在成绩表中没有对应的记录,所以内连接的结果中不会出现——这正体现了“无匹配不显示”的特性。
2. 外连接查询
外连接与内连接的区别在于,它以某一张表为基准,保留基准表的所有数据,另一张表有匹配则显示,无匹配则填充 NULL。具体分为左连接和右连接。
(1)左连接(LEFT JOIN)
核心逻辑
以左表为基准,左表的全部记录都会出现在结果集中,右表有匹配则显示数据,否则填充 NULL。
- 语法:
A LEFT JOIN B ON 关联条件(A 是左表,B 是右表)
代码示例
-- 左连接:以学生表为基准,查询所有学生(含无成绩的赵六)SELECT s.stu_id, s.stu_name, s.class, sc.subject, sc.scoreFROM student sLEFT JOIN score sc ON s.stu_id = sc.stu_id;
运行结果
| stu_id | stu_name | class | subject | score |
|---|---|---|---|---|
| 1 | 张三 | 一班 | 语文 | 85 |
| 1 | 张三 | 一班 | 数学 | 92 |
| 2 | 李四 | 二班 | 语文 | 78 |
| 3 | 王五 | 一班 | 数学 | 88 |
| 4 | 赵六 | 三班 | NULL | NULL |
说明
- 左表(学生表)中的所有学生都显示出来,赵六也没有被遗漏。但由于他没有成绩记录,因此右表的相关字段填充了
NULL。
(2)右连接(RIGHT JOIN)
核心逻辑
以右表为基准,右表全部记录都显示,左表匹配到则显示,否则填充 NULL。
- 语法:
A RIGHT JOIN B ON 关联条件(B 是右表,A 是左表) - 实际上,
A LEFT JOIN B与B RIGHT JOIN A是等价的。在日常开发中,优先使用左连接,因为代码可读性更好。
代码示例
-- 右连接:以成绩表为基准,查询所有成绩(本例中成绩表所有记录都能匹配到学生)SELECT s.stu_id, s.stu_name, s.class, sc.subject, sc.scoreFROM student sRIGHT JOIN score sc ON s.stu_id = sc.stu_id;
运行结果
与内连接结果完全一致——因为成绩表里的所有记录都能在学生表中找到对应的学生。
3. 复合条件连接查询
核心逻辑
在连接查询的基础上,叠加多个过滤条件,实现更精准的数据筛选。条件可以写在 ON 子句中(在连接时过滤),也可以写在 WHERE 子句中(连接完成后过滤)。
代码示例 1:连接 + 单条件过滤
-- 左连接+WHERE:查询一班所有学生(含无成绩的)SELECT s.stu_id, s.stu_name, s.class, sc.subject, sc.scoreFROM student sLEFT JOIN score sc ON s.stu_id = sc.stu_idWHERE s.class = '一班';
运行结果
| stu_id | stu_name | class | subject | score |
|---|---|---|---|---|
| 1 | 张三 | 一班 | 语文 | 85 |
| 1 | 张三 | 一班 | 数学 | 92 |
| 3 | 王五 | 一班 | 数学 | 88 |
代码示例 2:多条件复合连接
-- 左连接+多条件:查询一班成绩>80的学生,无成绩也显示SELECT s.stu_id, s.stu_name, s.class, sc.subject, sc.scoreFROM student sLEFT JOIN score sc ON s.stu_id = sc.stu_id AND sc.score > 80 -- 连接时过滤成绩>80WHERE s.class = '一班'; -- 过滤班级
运行结果
| stu_id | stu_name | class | subject | score |
|---|---|---|---|---|
| 1 | 张三 | 一班 | 数学 | 92 |
| 3 | 王五 | 一班 | 数学 | 88 |
关键说明:ON与WHERE的区别
ON子句:连接时过滤,只影响右表的匹配结果,不影响左表是否显示(左表仍然全显)WHERE子句:连接后过滤,是对最终结果集的筛选,不符合条件的行直接删除
这个区别在实际开发中非常关键,需要特别留意:查询条件放错位置,结果可能天差地别。
四、核心对比与避坑指南
1. 内连接 vs 外连接 核心区别
| 场景 | 推荐连接 | 原因 |
|---|---|---|
| 只需要匹配成功的数据 | 内连接 | 结果最精简,性能最优 |
| 需要保留左表所有数据 | 左连接 | 左表完整,右表补空 |
| 需要保留右表所有数据 | 右连接 | 可转换为左连接,优先用左连接 |
2. 常见避坑
1.关联条件缺失:多表连接必须加 ON 关联条件,否则会产生笛卡尔积(数据爆炸)
-- 错误!无关联条件,笛卡尔积SELECT * FROM student, score;
2.ON 与 WHERE 混用:外连接中,WHERE 会过滤左表数据,导致外连接失效
-- 错误!WHERE sc.score>80 会过滤掉赵六的NULL行,左连接变内连接SELECT * FROM student s LEFT JOIN score sc ON s.stu_id=sc.stu_id WHERE sc.score>80;
3.表别名不规范:多表同名字段必须加表别名,否则报错
-- 错误!stu_id 不明确属于哪个表SELECT stu_id FROM student s JOIN score sc ON s.stu_id=sc.stu_id;-- 正确:加表别名SELECT s.stu_id FROM student s JOIN score sc ON s.stu_id=sc.stu_id;
五、综合实战:多表连接 + 复合条件
-- 需求:查询所有学生的总分,无成绩的学生总分显示0,按班级分组SELECT s.class, s.stu_name, IFNULL(SUM(sc.score), 0) AS total_score -- IFNULL 把NULL转为0FROM student sLEFT JOIN score sc ON s.stu_id = sc.stu_idGROUP BY s.stu_id, s.stu_name, s.classORDER BY total_score DESC;
运行结果
| class | stu_name | total_score |
|---|---|---|
| 一班 | 张三 | 177 |
| 一班 | 王五 | 88 |
| 二班 | 李四 | 78 |
| 三班 | 赵六 | 0 |
六、核心总结
- 内连接:取交集,仅显示匹配数据
- 左连接:左表全显,右表补空;右连接:右表全显,左表补空
- 复合条件:
ON过滤连接,WHERE过滤结果,不可混用 - 避坑关键:必须加关联条件,同名字段加别名,外连接慎用
WHERE过滤 - 性能优化:大表连接优先用内连接,关联字段加索引,避免笛卡尔积
