6. 聚合与分组
这是什么:聚合函数 = 把一整列数据压成一个结果的计算器,如 COUNT 数条数、SUM 求和、AVG 求平均;GROUP BY 把行按某列分组后再算。
为什么用:SELECT 一次给你每一行,可老板要的往往是「一共多少条」「平均分多少」这类结论。没有聚合,你只能把数据全拉出来自己数。
如何用:本章先用五个聚合函数把 user 表算一遍,再用 GROUP BY 分组、用 HAVING 过滤分组结果。
6.1 五个聚合函数
以下都基于 user 表先塞一些数据来观察:
SELECT COUNT(*) FROM `user`; -- 总行数
SELECT COUNT(email) FROM `user`; -- 该列非空行数
SELECT AVG(age) FROM `user`; -- 平均年龄
SELECT MAX(age), MIN(age) FROM `user`; -- 最大 / 最小
SELECT SUM(views) FROM article; -- 求总和
你会看到:每条查询返回一个数(比如用户平均年龄 10.50),而不是一列数据。
6.2 GROUP BY:按组统计
单独一个总数不够用?比如「每个用户名有多少行记录」——先把相同的值归为一组,组内再聚合:
SELECT `username`, COUNT(*) AS `cnt`
FROM `user`
GROUP BY `username`;
你会看到:
+----------+-----+
| username | cnt |
+----------+-----+
| frog | 2 |
| panda | 1 |
+----------+-----+
核心规则:GROUP BY 之后 SELECT 里只允许两类列——出现在 GROUP BY 里的列,和聚合函数包裹的列。
6.3 HAVING:对「分组结果」过滤
WHERE 过滤的是「行」,HAVING 过滤的是「组」:
SELECT `username`, COUNT(*) AS `cnt`
FROM `user`
WHERE `age` > 5 -- 先按行过滤
GROUP BY `username`
HAVING COUNT(*) > 1 -- 再按组过滤:只留多于 1 条的
ORDER BY `cnt` DESC;
两条「过滤」井然有序:
- WHERE(进组前的行筛) coming
- GROUP BY 分组
- HAVING(组后的筛)
- ORDER BY / LIMIT
6.4 查文章热榜实战
SELECT `title`, `views`
FROM `article`
ORDER BY `views` DESC
LIMIT 3;
这类「统计一下」的话,都由聚合函数直接回答——试着自己写「article 平均阅读量」「总阅读量」。
6.5 动手改
- 统计 user 表平均年龄(保留 1 位小数:
ROUND(AVG(age), 1)) - 用 GROUP BY 统计每个年龄有几人
- 只显示出现次数 ≥ 2 的年龄(HAVING)
6.6 小结
- 五函数:COUNT / SUM / AVG / MAX / MIN,每个返回一个数
- GROUP BY 分组聚合,「组内谁说了算」只有聚合函数
- 行筛用 WHERE,组筛用 HAVING
下一章:多表查询 🐸