🐸 青蛙编程网
首页 / 数据库 / MySQL / 6. 聚合与分组

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;

两条「过滤」井然有序:

  1. WHERE(进组前的行筛) coming
  2. GROUP BY 分组
  3. HAVING(组后的筛)
  4. ORDER BY / LIMIT

6.4 查文章热榜实战

SELECT `title`, `views`
FROM `article`
ORDER BY `views` DESC
LIMIT 3;

这类「统计一下」的话,都由聚合函数直接回答——试着自己写「article 平均阅读量」「总阅读量」。

6.5 动手改

  1. 统计 user 表平均年龄(保留 1 位小数:ROUND(AVG(age), 1))
  2. 用 GROUP BY 统计每个年龄有几人
  3. 只显示出现次数 ≥ 2 的年龄(HAVING)

6.6 小结

  • 五函数:COUNT / SUM / AVG / MAX / MIN,每个返回一个数
  • GROUP BY 分组聚合,「组内谁说了算」只有聚合函数
  • 行筛用 WHERE,组筛用 HAVING

下一章:多表查询 🐸

📥 下载本章代码

ZIP 内含本章全部代码文件与说明,解压即用,与教程内容同步生成。