【计算机基础速成】第二课:SQL 进阶查询与 `JOIN` 高频题专项
1. 这节课的目标
第一课你已经认识了 MySQL、SQL 和最基础的查询语句。这一课要继续往“面试能打”的方向推进。
这节课学完后,你至少要做到:
- 能写多表查询
- 能分清
inner join、left join - 能写分组统计题
- 能理解并写基础子查询
- 能应对常见 SQL 面试题型
这一课非常重要,因为很多后端实习面试会直接让你:
- 解释一条 SQL
- 手写一条 SQL
- 根据业务表结构现场写查询语句
2. 先建立这一课的核心图景
如果说第一课是在学“单表怎么玩”,那么第二课就是在学:
- 两张表、三张表怎么联合查询
- 怎么做统计
- 怎么根据结果再继续过滤
- 怎么解决稍微复杂一点的业务查询问题
3. 本课会用到的示例表
为了方便统一讲解,我们假设有下面三张表。
3.1 student
| id | name | age | class_id |
|---|---|---|---|
| 1 | Tom | 19 | 101 |
| 2 | Lily | 20 | 102 |
| 3 | Jack | 19 | 101 |
| 4 | Rose | 21 | 103 |
3.2 class
| id | class_name | teacher_id |
|---|---|---|
| 101 | Class-A | 1001 |
| 102 | Class-B | 1002 |
| 103 | Class-C | 1003 |
3.3 teacher
| id | teacher_name |
|---|---|
| 1001 | Zhang |
| 1002 | Li |
| 1003 | Wang |
4. 多表查询为什么重要
实际业务里,数据往往不会都放在一张表里。
比如:
- 学生信息在
student - 班级信息在
class - 老师信息在
teacher
如果你想查询:
每个学生的姓名、班级名、老师名
那就必须做多表关联查询。
所以 join 是后端开发里最基础也最常用的 SQL 能力之一。
5. join 的核心理解
一句话理解
join 就是把几张有关系的表,按照某个关联字段拼起来查。
最常见的关联条件通常是:
on 表A.字段 = 表B.字段例如:
student.class_id = class.idclass.teacher_id = teacher.id
6. inner join 再强化
作用
只返回能关联成功的记录。
示例
select s.name, c.class_name
from student s
inner join class c
on s.class_id = c.id;结果含义
查询每个学生对应的班级名称。
只有当 student.class_id 能在 class.id 中找到对应值时,这条数据才会被返回。
面试话术
inner join 是内连接,只返回两张表中满足连接条件的记录。它适合查询关联关系明确且只关心匹配数据的场景。
7. left join 再强化
作用
保留左表的全部数据,右表匹配不到就补 NULL。
示例
select s.name, c.class_name
from student s
left join class c
on s.class_id = c.id;面试话术
left join 是左连接,会保留左表中的所有记录。如果右表中没有匹配项,则右表对应字段返回 NULL。它适合“左边数据必须都查出来”的场景。
一个典型场景
比如你要查“所有学生以及他们的班级信息”,即使有些学生没有分班,也要显示出来,那就应该优先考虑 left join。
8. 两张表和三张表怎么连
8.1 两张表连接
查询学生姓名和班级名:
select s.name, c.class_name
from student s
left join class c
on s.class_id = c.id;8.2 三张表连接
查询学生姓名、班级名、老师名:
select s.name, c.class_name, t.teacher_name
from student s
left join class c
on s.class_id = c.id
left join teacher t
on c.teacher_id = t.id;你要理解的重点
三表连接并不神秘,本质上就是:
- 先把第一张表和第二张表连起来
- 再把结果和第三张表连起来
9. join 高频面试题
9.1 on 和 where 在连接查询中的区别
这是面试里非常经典的一道题。
核心区别
on:定义表与表之间怎么关联where:对关联后的结果再进行过滤
示例
select s.name, c.class_name
from student s
left join class c
on s.class_id = c.id
where s.age > 19;这里:
on s.class_id = c.id是连接条件where s.age > 19是过滤条件
面试答法
在连接查询中,on 主要用于指定两张表如何关联,where 主要用于对查询结果进行进一步筛选。尤其是在 left join 中,如果把右表过滤条件写错位置,可能会影响最终结果。
为什么这题重要
因为面试官有时会继续追问:
left join时把右表条件写在on和写在where有什么区别?
你现在先记住结论:
- 写在
on:不会轻易破坏左连接“保留左表全部数据”的特性 - 写在
where:可能把右表为NULL的结果过滤掉,效果接近内连接
10. 分组统计题
这是另一个超级高频区。
10.1 统计每个班的人数
select class_id, count(*) as student_count
from student
group by class_id;含义
按 class_id 分组后,统计每个班的学生数量。
10.2 统计每个班的平均年龄
select class_id, avg(age) as avg_age
from student
group by class_id;10.3 查询人数大于 1 的班级
select class_id, count(*) as student_count
from student
group by class_id
having count(*) > 1;为什么这里用 having
因为要过滤的是聚合后的结果 count(*)。
11. 去重:distinct
作用
去掉重复值。
示例
select distinct class_id
from student;查询有哪些不同的班级编号。
面试答法
distinct 用于去重,常用于查询某个字段有哪些不同取值,但它本质上也会带来额外计算开销,所以不能滥用。
12. 子查询基础
一句话理解
子查询就是在一条 SQL 里面再嵌套一条 SQL。
它常用于:
- 先查出一个结果
- 再把这个结果作为条件或临时结果继续查询
12.1 示例:查询年龄大于平均年龄的学生
select *
from student
where age > (
select avg(age)
from student
);执行逻辑
- 先执行子查询,求出平均年龄
- 再查询年龄大于平均年龄的学生
面试答法
子查询适合解决“一个查询的条件依赖于另一个查询结果”的情况。比如先求平均值,再根据平均值筛选数据。
12.2 示例:查询属于 Class-A 的学生
select *
from student
where class_id = (
select id
from class
where class_name = 'Class-A'
);逻辑
- 先通过
class表查出Class-A的id - 再去
student表查属于这个班的学生
13. 常见 SQL 题型总结
面试里常见 SQL 题一般就这些类型。
| 题型 | 本质 |
|---|---|
| 条件查询 | where |
| 排序 | order by |
| 统计 | 聚合函数 |
| 分组统计 | group by + 聚合函数 |
| 分组后过滤 | having |
| 多表查询 | join |
| 去重 | distinct |
| 嵌套条件查询 | 子查询 |
你要做的,不是把 SQL 学得非常全,而是对这些题型形成条件反射。
14. 几道高频手写题
下面这些很像面试官会当场让你写的题。
14.1 查询每个学生的姓名和班级名
select s.name, c.class_name
from student s
left join class c
on s.class_id = c.id;14.2 查询每个班级的人数
select class_id, count(*) as cnt
from student
group by class_id;14.3 查询人数大于 1 的班级
select class_id, count(*) as cnt
from student
group by class_id
having count(*) > 1;14.4 查询年龄最大的学生
select *
from student
where age = (
select max(age)
from student
);14.5 查询每个学生姓名、班级名、老师名
select s.name, c.class_name, t.teacher_name
from student s
left join class c
on s.class_id = c.id
left join teacher t
on c.teacher_id = t.id;15. 本课高频面试问答
15.1 inner join 和 left join 的区别
标准回答
inner join 只返回两张表中连接成功的记录;left join 会保留左表的全部记录,即使右表没有匹配项,也会返回,只是右表字段为 NULL。
15.2 on 和 where 的区别
标准回答
在多表查询中,on 主要用于指定连接条件,where 主要用于对连接结果进行过滤。特别是在 left join 中,如果把右表过滤条件写到 where 里,可能会影响左连接的结果。
15.3 group by 和 having 怎么配合
标准回答
group by 用于分组,having 用于对分组后的结果做进一步过滤,通常与聚合函数一起使用。
15.4 什么是子查询
标准回答
子查询就是在一条 SQL 中嵌套另一条 SQL,通常用于让一个查询依赖另一个查询的结果,比如先查平均值,再根据平均值筛选数据。
16. 面试里如何组织表达
如果面试官问你:
你平时 SQL 都会写什么?
你可以这样答:
常见的 SQL 查询我都会写,比如单表的条件查询、排序、分组统计,
多表查询里常用 join,像 inner join 和 left join,
如果涉及聚合结果过滤会用 having,
如果条件依赖另一个查询结果,我也会用子查询来处理。这个回答的优点是:
- 覆盖面够广
- 术语正确
- 不会显得只会最基础的
select
17. 本课最小记忆卡片
卡片 1
join:多表关联查询on:连接条件where:结果过滤
卡片 2
inner join:只要匹配上的left join:左表全保留
卡片 3
group by:分组having:过滤分组后的结果
卡片 4
distinct:去重- 子查询:SQL 里套 SQL
18. 课后练习
18.1 口头复述题
请你尝试不看讲义回答:
inner join和left join的区别是什么?on和where的区别是什么?group by和having的区别是什么?- 什么是子查询?它常用来解决什么问题?
18.2 SQL 手写题
根据上面的三张表示例,尝试手写:
- 查询所有学生姓名及班级名
- 查询所有学生姓名、班级名、老师名
- 统计每个班的人数
- 查询人数大于 1 的班级
- 查询年龄大于平均年龄的学生
- 查询所有不同的班级编号
18.3 今日最低完成标准
如果今天时间有限,你至少完成下面任务:
- 背下本课 4 张最小记忆卡片
- 手写 6 道 SQL
- 口头回答 4 道高频题
19. 下一课预告
第三课:索引入门与高频面试题