# P18 18. 基础-SQL-DQL-分组查询

> 本页是学习笔记，不等同于视频逐字稿。原声字幕未取得（匿名接口字幕轨为空且需登录，未使用任何账号），也没有逐句讲解记录；讲义只按节与页码对应，切点未逐句确证。

> 以同版讲义的公开镜像核对章节与页码（镜像非官方出品）；非逐字稿，示例为原创补充。

## P18 18. 基础-SQL-DQL-分组查询

- 原视频：https://www.bilibili.com/video/BV1Kr4y1i7ru/?p=18（p=18），时长 10:18
- 讲义：2.6.5 分组查询 p46–47（公开镜像；按主题对应，切点 notexact）

- 本集练习数据：practice/p18.sql（先执行，再对照小例）

### 一句话理解

把行按某一列的值分成几堆，再对每一堆算一个汇总数——这就是分组查询。

### 步骤

1. 先用 WHERE 把不要的行筛掉，这时还不知道最后会分几组。比如写 WHERE age < 30，先只留下符合条件的行。
2. 再用 GROUP BY dept_id 按部门把这些行分堆，每个不同的 dept_id 值成为一堆。 分组列可以写多个（如 `GROUP BY gender, dept_id`）：先按第一列分，相同再按第二列分。
3. SELECT 里只写分组列和聚合函数，例如 COUNT(*)、AVG(salary)，数据库会对每一堆各算一个值。
4. 对“堆”的条件写在 HAVING 里，比如只保留人数 ≥ 2 的组；它和 WHERE 的位置不同，作用对象也不同。

### SQL 示例

```
SELECT dept_id, COUNT(*) AS 人数, ROUND(AVG(salary), 0) AS 平均薪资
FROM employee
WHERE age < 30
GROUP BY dept_id
HAVING COUNT(*) >= 2;
```

说明：【原创演示】依赖前面给出的 employee 四行练习数据（小林 22/dept1/8000，小周 25/dept1/10000，小陈 30/dept2/12000，小李 21/NULL/NULL），不用额外建表。WHERE 先去掉 30 岁的小陈；剩下小林、小周在部门 1，小李的 dept_id 是 NULL，自成一堆。HAVING 只留人数 ≥ 2 的堆，于是只剩部门 1：人数 2，平均薪资 9000。结果一行：1、2、9000。

### 易错点

- 在 SELECT 里写 name 这类没参与分组的列：默认开启 ONLY_FULL_GROUP_BY 时会直接报错，而不是随手给你一条记录。
- 把 COUNT(*) >= 2 写进 WHERE：WHERE 执行时还没有“堆”，聚合函数在那里不合法，必须放 HAVING。
- 以为 dept_id 为 NULL 的行会被悄悄丢掉：它单独成一组，COUNT(*) 把它算作 1 行；想排除得显式写 WHERE dept_id IS NOT NULL。

### 30 秒速记

WHERE 筛行 → GROUP BY 分堆 → 聚合函数每堆一值 → HAVING 筛堆；非分组列不进 SELECT。

### 自测

1. 为什么 HAVING COUNT(*) >= 2 不能改写成 WHERE COUNT(*) >= 2？
   - 答：WHERE 在分组之前逐行判断，那时还没有“组”和计数结果；COUNT(*) 是分组后的汇总值，只能由 HAVING 判断。
2. 小李 dept_id 为 NULL，按 dept_id 分组后他会消失吗？
   - 答：不会。GROUP BY 把 NULL 当成一个独立的分组值，他单独成一组；只有写成 COUNT(dept_id) 时这一组的计数才会是 0。
3. 例子里的 ROUND(AVG(salary),0) 为什么放在 SELECT 而不是 WHERE？
   - 答：它是每堆算出来的汇总值，属于分组之后才存在的结果；放进 WHERE 时组还没形成，SQL 算不出来。

### 材料与来源

- [平台视频页] P18 原视频页（BV1Kr4y1i7ru） https://www.bilibili.com/video/BV1Kr4y1i7ru/?p=18
- [官方文档] MySQL 8.0 Reference：GROUP BY 处理与 ONLY_FULL_GROUP_BY https://dev.mysql.com/doc/refman/8.0/en/group-by-handling.html
- [官方文档] MySQL 8.0 Reference：SELECT 语句 https://dev.mysql.com/doc/refman/8.0/en/select.html

证据说明：按 P18 标题“分组查询”和 9 张采样静帧整理：t20 帧的 Workbench 画面里能看到本集演示注释——按性别分组统计人数、按性别统计平均年龄、先筛年龄<45 再按工作地址分组并要求数量≥3，说明本集讲的是 GROUP BY 与 HAVING 的组合。无字幕，讲师原话与逐条演示结果未核实；正文小表与数字是原创练习数据，不是课堂 emp 表。
