🎯 本月只剩几天支持 SQLTest.online,帮助我们让 SQL 练习对每个人都免费。 今天捐赠 →
SQL 代码已复制到剪贴板

用 GROUP BY 对数据分组

第 4.2 课 · 阅读时间:约 7 分钟 · 练习题 ↓

分组把单独的行转换为按类别划分的指标。当报表需要按类别、日期或其他维度计算合计时,GROUP BY 必不可少。在本课中,你将学习 GROUP BY 的语法、核心规则以及基于 Sakila 的实用示例。学完后,你将能够熟练编写带分组的分析查询。

在上一课中,你学习了聚合函数。现在进入下一步:把这些函数应用到不同的数据类别上。

GROUP BY 的做法是把数据划分为若干组,并分别为每一组计算指标。

SQL GROUP BY:payment 表的 16049 行按 staff_id 合并为每组一行,并计算 COUNT 和 SUM;执行步骤为 FROM、GROUP BY、SELECT

GROUP BY 语法

基本结构:

SELECT column1, AGG_FUNCTION(column2)
FROM table
GROUP BY column1;

核心规则

使用 GROUP BY 时,SELECT 中的每一列都必须:

  • 要么出现在 GROUP BY 列表中;
  • 要么被包在聚合函数(SUM、COUNT、AVG、MIN、MAX)中。

这条规则可以避免歧义:当一个组包含多行时,SQL 需要知道该返回哪个值。

按一列分组

每位客户的付款总额

SELECT customer_id, SUM(amount) AS total_paid
FROM payment
GROUP BY customer_id;

结果:每位客户一行,包含其付款总额。

每位员工处理的付款笔数

SELECT staff_id, COUNT(*) AS payments_count
FROM payment
GROUP BY staff_id;

结果:每位员工处理的付款笔数。

按日期计算平均付款额

SELECT DATE(payment_date) AS pay_date, AVG(amount) AS avg_payment
FROM payment
GROUP BY DATE(payment_date);

结果:每个日期的平均付款金额。

变体:在 GROUP BY 中使用别名

SELECT DATE(payment_date) AS pay_date, AVG(amount) AS avg_payment
FROM payment
GROUP BY pay_date;

说明:这在 MySQL/MariaDB 中可行,但并非所有 DBMS 都支持。为了跨数据库兼容,请完整写出 GROUP BY DATE(payment_date)。


按多列分组

你可以同时按多个字段分组,进行更细致的分析。

按员工和客户统计付款总额

SELECT staff_id, customer_id, SUM(amount) AS total_paid
FROM payment
GROUP BY staff_id, customer_id;

结果:每个“员工-客户”组合一行,包含其付款总额。


实用示例

每日收入报表

SELECT DATE(payment_date) AS pay_date, SUM(amount) AS total_sales
FROM payment
GROUP BY DATE(payment_date)
ORDER BY pay_date;

按租赁次数排列最活跃的客户

SELECT customer_id, COUNT(*) AS rentals_count
FROM rental
GROUP BY customer_id
ORDER BY rentals_count DESC;

按电影类别计算平均租金

SELECT category_id, AVG(rental_rate) AS avg_rental_rate
FROM film f
JOIN film_category fc ON f.film_id = fc.film_id
GROUP BY category_id;

常见问题

为什么使用 GROUP BY 时不能在 SELECT 中随意放列?

因为聚合函数(SUM、COUNT、AVG)已经告诉 SQL 如何处理组内的所有行。如果某一列没有被聚合,它就必须出现在 GROUP BY 中,这样 SQL 才知道该选哪个值。

可以按表达式而不是列分组吗?

可以,例如 GROUP BY DATE(payment_date) 或 GROUP BY YEAR(payment_date)。SELECT 和 GROUP BY 中的表达式必须一致。

如果 GROUP BY 后面是空的会怎样?

这是语法错误。GROUP BY 至少需要一列或一个表达式。


面试问题

什么是 GROUP BY,为什么需要它?

GROUP BY 把所选列取值相同的行合并为一组。然后你可以对每一组应用聚合函数,得到汇总统计。

为什么使用 GROUP BY 时不能随意选择一列?

因为一个组可能包含多行,而这些行在该列上的值各不相同。SQL 需要知道返回哪个值,否则结果就会有歧义。因此该列必须出现在 GROUP BY 中,或者放在聚合函数里。

WHERE 和 HAVING 有什么区别?

WHERE 在分组之前过滤行,而 HAVING 在分组之后过滤组。例如,WHERE amount > 10 在分组前排除行,而 HAVING SUM(amount) > 100 排除总和小于 100 的组。


本课要点:

  • GROUP BY 把数据分成若干组,并对每一组应用聚合函数。
  • 核心规则:SELECT 中的每一列要么在 GROUP BY 中,要么在聚合函数中。
  • 可以同时按一列或多列分组。
  • 可以按表达式分组,例如 GROUP BY DATE(payment_date)。
  • GROUP BY 是报表、分析和分类汇总的基础。

尝试解决以下任务,以巩固您在本课中学到的内容。

  1. 计算企鹅数量
  2. 按类别分布的电影
  3. 客户的平均租赁时长
  4. 按类别计算平均电影租赁成本
  5. 每月付款分析