人人都能学编程
English 开始学习
核心 · 数据库第 3 课 / 共 6 课免费阅读

分组与统计 · 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
逐步执行
  1. 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
逐步执行
  1. L3三个桶:bags(1 件)、home(2 件)、paper(2 件)。
  2. L4bags 只有一件,被去掉。
  3. 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;
  1. A
    customer_id | items
    1 | 14
    3 | 7
  2. B
    customer_id | items
    1 | 14
  3. C
    customer_id | items
    1 | 14
    2 | 3
    3 | 7
查看答案

答案:A

顾客 1 买了 4 + 10 = 14,顾客 2 买了 1 + 2 = 3,顾客 3 买了 2 + 5 = 7,顾客 4 买了 1。只有 14 和 7 大于 5。

2. 只要订单不少于 2 笔的日子,条件写在哪里?

  1. AWHERE COUNT(*) >= 2
  2. BHAVING COUNT(*) >= 2
  3. CORDER BY COUNT(*) >= 2
查看答案

答案:B

条件是针对一组(一天)的,所以放在 HAVING 里,跟在 GROUP BY day 后面。

动手练习

3 道练习,分三层:先预测程序的输出,再按新需求改程序,最后从零写一个。代码在浏览器里运行,提交马上判题。

  1. 预测输出每天的订单数

    准确写出查询结果。

  2. 改需求只看常客

    这条查询统计每个顾客的订单数。改成只保留订单数不少于 2 的顾客。

  3. 从零写每件商品卖了多少

    对 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.