【计算机基础速成】第二课:SQL 进阶查询与 `JOIN` 高频题专项

4 小时前(已编辑)

【计算机基础速成】第二课:SQL 进阶查询与 `JOIN` 高频题专项

1. 这节课的目标

第一课你已经认识了 MySQL、SQL 和最基础的查询语句。这一课要继续往“面试能打”的方向推进。

这节课学完后,你至少要做到:

  • 能写多表查询
  • 能分清 inner joinleft join
  • 能写分组统计题
  • 能理解并写基础子查询
  • 能应对常见 SQL 面试题型

这一课非常重要,因为很多后端实习面试会直接让你:

  • 解释一条 SQL
  • 手写一条 SQL
  • 根据业务表结构现场写查询语句

2. 先建立这一课的核心图景

如果说第一课是在学“单表怎么玩”,那么第二课就是在学:

  • 两张表、三张表怎么联合查询
  • 怎么做统计
  • 怎么根据结果再继续过滤
  • 怎么解决稍微复杂一点的业务查询问题

3. 本课会用到的示例表

为了方便统一讲解,我们假设有下面三张表。

3.1 student

idnameageclass_id
1Tom19101
2Lily20102
3Jack19101
4Rose21103

3.2 class

idclass_nameteacher_id
101Class-A1001
102Class-B1002
103Class-C1003

3.3 teacher

idteacher_name
1001Zhang
1002Li
1003Wang

4. 多表查询为什么重要

实际业务里,数据往往不会都放在一张表里。

比如:

  • 学生信息在 student
  • 班级信息在 class
  • 老师信息在 teacher

如果你想查询:

每个学生的姓名、班级名、老师名

那就必须做多表关联查询。

所以 join 是后端开发里最基础也最常用的 SQL 能力之一。


5. join 的核心理解

一句话理解

join 就是把几张有关系的表,按照某个关联字段拼起来查。

最常见的关联条件通常是:

on 表A.字段 = 表B.字段

例如:

  • student.class_id = class.id
  • class.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;

你要理解的重点

三表连接并不神秘,本质上就是:

  1. 先把第一张表和第二张表连起来
  2. 再把结果和第三张表连起来

9. join 高频面试题

9.1 onwhere 在连接查询中的区别

这是面试里非常经典的一道题。

核心区别

  • 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
);

执行逻辑

  1. 先执行子查询,求出平均年龄
  2. 再查询年龄大于平均年龄的学生

面试答法

子查询适合解决“一个查询的条件依赖于另一个查询结果”的情况。比如先求平均值,再根据平均值筛选数据。


12.2 示例:查询属于 Class-A 的学生

select *
from student
where class_id = (
    select id
    from class
    where class_name = 'Class-A'
);

逻辑

  1. 先通过 class 表查出 Class-Aid
  2. 再去 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 joinleft join 的区别

标准回答

inner join 只返回两张表中连接成功的记录;left join 会保留左表的全部记录,即使右表没有匹配项,也会返回,只是右表字段为 NULL


15.2 onwhere 的区别

标准回答

在多表查询中,on 主要用于指定连接条件,where 主要用于对连接结果进行过滤。特别是在 left join 中,如果把右表过滤条件写到 where 里,可能会影响左连接的结果。


15.3 group byhaving 怎么配合

标准回答

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 口头复述题

请你尝试不看讲义回答:

  1. inner joinleft join 的区别是什么?
  2. onwhere 的区别是什么?
  3. group byhaving 的区别是什么?
  4. 什么是子查询?它常用来解决什么问题?

18.2 SQL 手写题

根据上面的三张表示例,尝试手写:

  1. 查询所有学生姓名及班级名
  2. 查询所有学生姓名、班级名、老师名
  3. 统计每个班的人数
  4. 查询人数大于 1 的班级
  5. 查询年龄大于平均年龄的学生
  6. 查询所有不同的班级编号

18.3 今日最低完成标准

如果今天时间有限,你至少完成下面任务:

  1. 背下本课 4 张最小记忆卡片
  2. 手写 6 道 SQL
  3. 口头回答 4 道高频题

19. 下一课预告

第三课:索引入门与高频面试题

使用社交账号登录

  • Loading...
  • Loading...
  • Loading...
  • Loading...
  • Loading...