SQL GROUP BY 用法详解
因为总是忘记这个用法,特地做一篇文章,附带详细例子,力求一文讲清 group by 的语法。
核心规则
在 SQL 查询中使用 GROUP BY 时,有一个重要的规则需要理解:
在
SELECT子句中出现的、非聚合函数的列,必须出现在GROUP BY子句中。
反过来则不一定成立:GROUP BY 中的列,可以不出现在 SELECT 子句中(但这样通常会导致结果难以理解,只有统计结果但是没有对象)。
核心机制:理解“分组”与“聚合”
要明白这个规则,首先要理解 GROUP BY 在做什么:
- 分组:数据库会先根据
GROUP BY后面指定的列,将表中的所有行分成若干个“小组”。每个小组内,GROUP BY列的值完全相同。 - 聚合:分组后,数据库会将每个小组压缩成一行结果。对于非
GROUP BY列,一个小组里可能有多行不同的值,数据库不知道应该输出哪一个。因此,你必须通过聚合函数(如SUM(),COUNT(),AVG(),MAX(),MIN()等)来告诉数据库如何将这些多行的值合并成一个值。
规则详解与示例
假设我们有一张 sales 表:
| order_id | salesperson | region | amount |
|---|---|---|---|
| 1 | Alice | North | 100 |
| 2 | Bob | South | 150 |
| 3 | Alice | North | 200 |
| 4 | Bob | South | 50 |
场景一:SELECT 包含 GROUP BY 列(最常见且推荐)
-- 按销售员分组,查看每个销售员的总销售额
SELECT salesperson, SUM(amount) AS total_sales
FROM sales
GROUP BY salesperson;
GROUP BY salesperson:将数据按salesperson分成 “Alice组” 和 “Bob组”。SELECT salesperson:由于每组内salesperson值都相同(Alice组全是‘Alice’),所以可以且应该选出它,作为结果行的标识。SELECT SUM(amount):对每个组的amount列使用SUM函数进行聚合,计算总和。- 结果:
| salesperson | total_sales |
|---|---|
| Alice | 300 |
| Bob | 200 |
场景二:SELECT 不包含 GROUP BY 列(允许但通常无意义)
-- 按销售员分组,但只查看总销售额,不显示是谁的
SELECT SUM(amount) AS total_sales
FROM sales
GROUP BY salesperson;
GROUP BY salesperson:依然分成 “Alice组” 和 “Bob组”。SELECT SUM(amount):计算每组的销售额总和。SELECT中没有salesperson:语法上完全正确。但结果是,你会得到两行数字(300和200),却不知道它们分别对应哪位销售员。这种查询通常没有实际分析价值。- 结果:
| total_sales |
|---|
| 300 |
| 200 |
场景三:SELECT 包含了非 GROUP BY 列,且未使用聚合函数(错误!)
-- 错误的查询!
SELECT salesperson, region, SUM(amount) AS total_sales
FROM sales
GROUP BY salesperson;
GROUP BY salesperson:只按销售员分组。在“Alice组”里,region列的值虽然都是‘North’,但数据库的通用规则不允许这种推断。region列既不在GROUP BY中,也没有被聚合函数处理。- 结果:绝大多数数据库(如 MySQL, PostgreSQL, SQL Server 等)都会报错,提示
region必须出现在GROUP BY子句中或用在聚合函数里。
特殊模式:GROUP BY 的所有列 = SELECT 的所有非聚合列
有一种常见的查询风格,特别是在按多列分组时,会让 SELECT 中的非聚合列与 GROUP BY 后的列完全一致,这会使查询意图非常清晰:
-- 按销售员和地区分组,查看每个组合的总销售额
SELECT salesperson, region, SUM(amount) AS total_sales
FROM sales
GROUP BY salesperson, region; -- SELECT 中的两个非聚合列,都出现在了这里
总结
你可以这样记忆 GROUP BY 和 SELECT 的关系:
GROUP BY决定了“如何切分蛋糕”(按哪些列分组)。SELECT决定了“展示切分后的哪些信息”。- 如果你想展示“这块蛋糕是哪个部分的”(分组标识),那就把分组列放进
SELECT。 - 对于分组后每块蛋糕里的“馅料”(其他列),你必须用聚合函数(如
SUM,COUNT)把它们“混合”成一个值,才能放进SELECT展示。
- 如果你想展示“这块蛋糕是哪个部分的”(分组标识),那就把分组列放进
所以,GROUP BY 中的列不是必须在 SELECT 中,但为了结果可读,你几乎总是会这么做。而 SELECT 中所有未被聚合的列,则必须在 GROUP BY 中。
844



被折叠的 条评论
为什么被折叠?



