🙏 感谢您的支持! 我们在七月份已经筹集了 $65 — 这足够我们工作到下个月。请帮助我们保持进度,进一步支持这个项目。 支持这个项目 →
SQL 代码已复制到剪贴板

课程 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 列表中;
  • 要么被包裹在聚合函数中(SUMCOUNTAVGMINMAX)。

此规则防止歧义: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 中?

因为聚合函数(SUMCOUNTAVG)已经告诉 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 操作符过滤组。

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

  1. 客户的平均租赁时长
  2. 按类别计算平均电影租赁成本
  3. 每月付款分析
  4. 每个商店的平均收入
  5. 按类别统计电影数量