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

6. 聚合与分组

这是什么:聚合 = 把很多行算成一个数(总数、总和、平均);GROUP BY = 先按某列分组,再对每组聚合。

为什么用:「博客有多少篇文章」「哪位作者平均阅读量最高」——凡是带「每、多少、平均」的问题,都是聚合查询。这章的 SQL 你在 MySQL 教程练过一遍,这里逐字不改也能跑。

如何用:还是 user + article 两张表,统计跑起来,顺便验证「学的 SQL 两边通用」。

说明:本章沿用前几章改完之后的数据——第 4 章删掉了《MySQL 练手记》、把第 1 篇阅读量加到了 130,所以现在库里只有 2 篇文章。

6.1 五个聚合函数

函数 算什么 示例问题
COUNT 行数 有多少篇文章
SUM 求和 总阅读量
AVG 平均 平均阅读量
MAX / MIN 最大 / 最小 最火 / 最凉的文章

先来两个单组统计:

SELECT COUNT(*) FROM article;
SELECT MAX(views) FROM article;

预期输出:

2
130

6.2 GROUP BY:按作者统计

想知道每位作者的文章数和平均阅读量,就按 user_id 分组:

SELECT user_id,
       COUNT(*)          AS 文章数,
       AVG(views)        AS 平均阅读
FROM article
GROUP BY user_id;

预期输出:

1|2|107.5

现在有文章的只剩 frog(两篇:130 和 85),所以只有一行。

6.3 带上作者名:先 JOIN 再分组

分组键换成用户表的用户名,顺带把没发过文章的作者也统计出来(LEFT JOIN),这就是 MySQL 章同款练习:

SELECT u.username,
       COUNT(a.id)                  AS 文章数,
       IFNULL(AVG(a.views), 0)      AS 平均阅读
FROM user u
LEFT JOIN article a ON a.user_id = u.id
GROUP BY u.id
ORDER BY 文章数 DESC;

预期输出(panda 没发过文章,被兜底成 0):

frog|2|107.5
panda|0|0

两个细节:COUNT(a.id) 数的是文章行数(没文章就是 0),而 COUNT(*) 会把 LEFT JOIN 出的空行也数进去——统计「每组的文章数」要用列名;IFNULL(..., 0) 把无文章的 NULL 平均值兜底成 0。

6.4 HAVING:对分组结果再筛选

WHERE 筛的是原始行,HAVING 筛的是分组后的统计值。只要文章数 ≥ 2 的作者:

SELECT u.username, COUNT(a.id) AS 文章数
FROM user u
LEFT JOIN article a ON a.user_id = u.id
GROUP BY u.id
HAVING 文章数 >= 2;

预期输出:

frog|2

口诀:WHERE 管行,HAVING 管组。

6.5 动手改

  1. 统计全站总阅读量与文章总数(一条 SELECT,两个聚合)
  2. 找出平均阅读量高于 90 的作者(JOIN + GROUP BY + HAVING)
  3. 按月统计文章数(提示:substr(created_at, 1, 7) 当分组键)

6.6 小结

  • 聚合五件套 COUNT / SUM / AVG / MAX / MIN
  • GROUP BY 分组统计,HAVING 筛组;WHERE 管行,HAVING 管组
  • 同一条统计 SQL 在 MySQL 和 SQLite 里结果一致——学一次两边用

下一章:多表查询与外键 🐸

📥 下载本章代码

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