分组与统计 · SQL 与数据库
怎么把很多行汇总成几个数字?
课程目录为什么需要它
各种看板都是汇总:每天的销售额、每个城市的用户数、平均订单金额。在 SQL 里,这些来自聚合函数和 GROUP BY,数据库替你数,哪怕有几百万行。
直觉理解
GROUP BY city 把行分进不同的桶里,每个城市一个桶。然后聚合函数把每个桶压成一个数:
COUNT(*):有几行SUM(x)、AVG(x):总和、平均值MIN(x)、MAX(x):最小、最大
WHERE 在分组之前筛行;HAVING 在分组之后筛桶,所以它可以用 COUNT(*)。
定义
聚合函数
A function that turns many values into one: COUNT, SUM, AVG, MIN, MAX. Without GROUP BY the whole table is one group.把许多值变成一个值的函数:COUNT、SUM、AVG、MIN、MAX。没有 GROUP BY 时,整张表就是一组。
GROUP BY / HAVING
GROUP BY makes one result row per distinct value; HAVING keeps only the groups that pass a condition.GROUP BY 为每个不同的值生成一行结果;HAVING 只保留满足条件的组。
示例
整张表的数字
在互动课里运行没有 GROUP BY:整张表是一个桶。
SELECT COUNT(*) AS products, MIN(price) AS cheapest, MAX(price) AS dearest, AVG(price) AS average
FROM products;输出
products | cheapest | dearest | average 5 | 1.5 | 25.0 | 10.8
逐步执行
- L1五行数据,一行结果。
5 | 1.5 | 25.0 | 10.8
按类别汇总,再筛选组
在互动课里运行按类别给商品分组,再只留商品多于一件的组。
SELECT category, COUNT(*) AS n, SUM(price) AS total
FROM products
GROUP BY category
HAVING COUNT(*) > 1
ORDER BY total DESC;输出
category | n | total home | 2 | 24.0 paper | 2 | 5.0
逐步执行
- L3三个桶:bags(1 件)、home(2 件)、paper(2 件)。
- L4bags 只有一件,被去掉。
- L5home 24.0 排在 paper 5.0 前面。
home | 2 | 24.0
常见错误
选了没分组的列
SELECT category, name, COUNT(*) … GROUP BY category 要求每个类别给出一个名字,可一个类别里有好几个。多数数据库会报错;SQLite 会悄悄随便挑一个,更糟。
在 WHERE 里用 COUNT
WHERE COUNT(*) > 1 会报错:WHERE 执行时还没有分组。要用 HAVING。
小测验
1. 这段代码会输出什么?
SELECT customer_id, SUM(qty) AS items FROM orders GROUP BY customer_id HAVING SUM(qty) > 5 ORDER BY customer_id;查看答案
答案:A
顾客 1 买了 4 + 10 = 14,顾客 2 买了 1 + 2 = 3,顾客 3 买了 2 + 5 = 7,顾客 4 买了 1。只有 14 和 7 大于 5。
2. 只要订单不少于 2 笔的日子,条件写在哪里?
查看答案
答案:B
条件是针对一组(一天)的,所以放在 HAVING 里,跟在 GROUP BY day 后面。
动手练习
3 道练习,分三层:先预测程序的输出,再按新需求改程序,最后从零写一个。代码在浏览器里运行,提交马上判题。
- 预测输出每天的订单数
准确写出查询结果。
- 改需求只看常客
这条查询统计每个顾客的订单数。改成只保留订单数不少于 2 的顾客。
- 从零写每件商品卖了多少
对
orders里的每个product_id,返回商品 id 和卖出的总数量,列名units。按units从多到少排序。
本课术语
| 术语 | 中文 | 英文定义 |
|---|---|---|
| Aggregate | 聚合 | To combine many values into one, such as a count or a sum. |
| GROUP BY | 分组 | Splits rows into groups that share a value, one result row each. |