课程 4.2 · 阅读时间:~7 分钟
分组将单个行转换为分类指标。GROUP BY 对于需要按类别、日期或任何其他维度汇总的报告至关重要。在本课程中,您将学习 GROUP BY 语法、核心规则以及在 Sakila 上的实际示例。到课程结束时,您将自信地构建带有分组的分析查询。
使用 GROUP BY 分组数据
在上一课中,您学习了聚合函数。现在我们迈出下一步:将这些函数应用于不同的数据类别。
GROUP BY 通过将数据划分为组并分别计算每个组的指标来实现这一点。
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 中有效,但并非所有数据库管理系统都支持。为了跨数据库兼容性,请完整写出 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为报告、分析和基于类别的摘要提供动力。
在下一课中,我们将探索使用 HAVING 操作符过滤组。