MySQL 视频课 · 50 集 / 多表查询练习与本章小结 / P49
第 49 集 / 共 50 · 多表查询练习与本章小结 · 视频 p=49 · 时长 21:29
P49 49. 基础-多表查询-练习2
看视频,对照阅读:在新标签打开原视频(p=49) · 先看跟播对照
第二组练习是组合拳:分组统计、相关子查询,再加一条原课的重点形状——按薪资档位(salgrade)做区间连接,然后把部门连上变三表。题干按视频同主题重写,数据仍用本站小表。
复习模式:快速跳知识点(详解在下方各节)
复习顺序:先看“一句话理解”能否复述,再扫步骤,最后做自测;答不出时回到小例与易错。
一句话理解
先把需求拆成单句验证:分组统计、相关子查询各一条;薪资档位用 salgrade 的区间连接,再把部门连上就是三表。
跟播:视频里 ↔ 本站
视频停在「所有员工的工资等级」与「研发部员工及工资等级」两题上,第二题就是三表。
| 视频里 / 原课字段 | 本站对应 |
|---|---|
| 讲义 emp 17 行 × dept 6 行 × salgrade 8 档 | 本站 employee 4 行 × department 3 行 × salgrade 4 档 |
| emp.salary BETWEEN salgrade.losal AND salgrade.hisal | employee.salary BETWEEN salgrade.losal AND salgrade.hisal |
看完应能:能先写出「工资落哪档」,再加一条部门连接变成三表
看视频时以讲义表为准,跟练时用本站表;结构相同、数字不同。
按这 4 步做
- 统计类先定「以谁为基准」。要每个部门都出现(包括没人),就以 department 为左表 LEFT JOIN employee,别反过来。
- 计数时用 COUNT(e.id) 而不是 COUNT(*)。左连接会给没人部门补一行 NULL,COUNT(*) 会把它算成 1 人,COUNT(e.id) 才是 0。
- 相关子查询里外层的值会传进内层。e.salary > (SELECT AVG(x.salary) ... WHERE x.dept_id = e.dept_id) 读作「高于本部门平均」,内层每行重算。
- 查薪资档次不用等值连接:
e.salary BETWEEN s.losal AND s.hisal就是一条非等值连接;要部门名就把 department 再连一次,变成三表。
小例
-- 表:department(1 研发部, 2 测试部, 3 运营部)
-- employee:小林22/研发8000/上级2,小周25/研发10000/无上级,小陈30/测试12000/上级2,小李21/无部门/NULL/上级2
-- 建表与插入语句见本页练习脚本 p49.sql(独立练习库 mysqlnotes_p49,跑一次就有这两张表)
-- 每部门人数与平均工资(运营部也要出现)
SELECT d.name AS 部门, COUNT(e.id) AS 人数, AVG(e.salary) AS 平均工资
FROM department d
LEFT JOIN employee e ON e.dept_id = d.id
GROUP BY d.id, d.name
ORDER BY d.id;
-- 高于本部门平均工资的人(相关子查询)
SELECT e.name AS 员工, e.dept_id AS 部门号, e.salary AS 工资
FROM employee e
WHERE e.salary > (
SELECT AVG(x.salary) FROM employee x WHERE x.dept_id = e.dept_id
);
第一段 3 行:研发部 2 人 / 9000、测试部 1 人 / 12000、运营部 0 人 / NULL。第二段研发部平均 9000,小周 10000 入选;测试部只有小陈,12000 不大于 12000;小李没有部门,内层算不出平均(NULL),不入选。共 1 行。 反连接写法:SELECT d.id, d.name FROM department d LEFT JOIN employee e ON e.dept_id = d.id WHERE e.id IS NULL,结果只有 3 运营部。这三个数字就是核对后面所有统计题的基准,先记住它们。
下面每条只演示一个点,可以单独复制执行。
-- salgrade 是本页原创的 4 档小表(grade, losal, hisal),不是讲义那 8 档
SELECT e.name AS 员工, e.salary AS 工资, s.grade AS 档位
FROM employee e
JOIN salgrade s ON e.salary BETWEEN s.losal AND s.hisal
ORDER BY e.id;
3 行:小林 8000→2 档、小周 10000→3 档、小陈 12000→3 档。BETWEEN 含两端,所以 12000 落在 9001–12000 的第 3 档。小李的 salary 是 NULL,NULL BETWEEN … 得 unknown,连不上任何档,这一行就消失了——非等值连接只保留「真的落进某个区间」的行。
小林 8000 2|小周 10000 3|小陈 12000 3(小李 NULL 不出现)
SELECT e.name AS 员工, d.name AS 部门, s.grade AS 档位
FROM employee e
JOIN department d ON e.dept_id = d.id
JOIN salgrade s ON e.salary BETWEEN s.losal AND s.hisal
ORDER BY e.id;
3 行:小林 研发部 2、小周 研发部 3、小陈 测试部 3。两条连接条件互相独立:一条是等值(dept_id = id),一条是区间(BETWEEN losal AND hisal)。三表不是「一条 ON 写三个表」,而是每连一张表就补一条 ON,顺序按「先等值、后区间」读最清楚。
小林 研发部 2|小周 研发部 3|小陈 测试部 3
易错点
- LEFT JOIN 后用 COUNT(*) 统计人数,会把「没人」的部门算成 1。
- 相关子查询忘写 x.dept_id = e.dept_id,就退化成全公司平均,结果看似合理但是错的。
- 区间连接漏了端点(写成 salary > losal AND salary < hisal),正好等于档位边界的工资会掉档。
- 以为 NULL 工资会落进第 1 档:NULL 参与 BETWEEN 得 unknown,不会匹配任何档。
30 秒速记
自测(3 题,先答再展开)
自测 1:运营部为什么会出现在结果里,人数却是 0?
department 是左表,LEFT JOIN 保留全部部门;COUNT(e.id) 不数补出来的 NULL 行。
自测 2:相关子查询漏写 dept_id = e.dept_id 会怎样?
变成和全公司平均比,结果错但通常不报错。
自测 3:统计每个部门人数为什么不用 COUNT(*)?
LEFT JOIN 补出的 NULL 行也会被 COUNT(*) 计入,没人部门会变成 1。
材料与来源
展开材料出处、讲义页码与证据等级
| 材料 | 类型 / 位置 | 支持了什么 |
|---|---|---|
| BV1Kr4y1i7ru P49(平台标题) | 平台视频页 · P49 | 静帧 t=644s 显示三表连接题目;t=1031s 显示按部门统计人数的子查询写法 |
| MySQL 8.0 Reference Manual — Subqueries | 官方文档 | 仅用于核对子查询语义与错误码,不是课程材料 |
本集无逐字稿(匿名 player/v2 返回 subtitles=[]、need_login_subtitle=true),依据平台标题、讲义 p86「5.7 多表查询案例」第 5–6 题与公开静帧核对:原课用 emp / dept / salgrade 三表,salgrade 是 grade, losal, hisal 三列共 8 档。本站用 employee / department 加一张 4 档原创 salgrade 复现同一形状,表名、行数与档位数字都不同,不能拿本站结果对讲义答案。
讲义对照:讲义 5.7 多表查询案例(第 5–12 题所在段) · p86–88(公开镜像;按主题对应,切点 notexact)
- 画面静帧 9 帧,采样点 0:12–21:16 / 全片 21:29(只用于确认画面主题,不作内容边界)
- 原声字幕未取得:匿名接口字幕轨为空且需登录,未使用任何账号
等级含义:平台视频页 / 官方文档 / 课件 = 原始材料;二手整理 = 参考;推断 = 未经核实。站内补充的解释与练习会在此说明。