← 返回题目列表

GROUP BY 的作用是什么?使用时有哪些规则?

高频 中等 第 8 / 28 题 更新于 2026/07/27
SQLGROUP BY聚合函数

简化版

GROUP BY 按指定键把输入行划分为若干组,聚合函数再对每组计算一个结果。分组查询的 SELECT 列通常只能是分组列、聚合表达式,或能由分组键唯一确定的列;否则结果没有确定含义。

详细版

SELECT department_id,
       COUNT(*) AS employee_count,
       AVG(salary) AS avg_salary
FROM employee
GROUP BY department_id;

该查询每个部门输出一行。COUNTSUMAVGMINMAX 等聚合函数通常忽略 NULL,但 COUNT(*) 统计行数,包括列值为 NULL 的行。

SELECT 同时写 department_id, employee_name, COUNT(*),而一个部门存在多个员工,数据库无法确定该显示哪个名字。MySQL 开启默认的 ONLY_FULL_GROUP_BY 时会拒绝这类不确定查询。

完整版教学

一、分组把多行压缩成一行

不带 GROUP BY 的聚合查询把所有输入行视为一个组:

SELECT COUNT(*), AVG(salary) FROM employee;

加入 GROUP BY department_id 后,每个不同的部门编号形成一组,每组分别计算聚合值。分组键可以有多个,此时按键的组合分组:

GROUP BY department_id, job_level

只有两个字段都相同的行才属于同一组。

二、SELECT 列为什么受到限制

分组后每组只输出一行。分组列在组内值相同,聚合函数能把多个值归约成一个值;普通非分组列却可能有多个候选值,所以不能随意输出。

SQL 标准允许输出函数依赖于分组键的列,例如按主键分组时,同一行的其他列由主键唯一确定。但不同数据库与版本对函数依赖的识别能力不同。为了清晰和可移植,面试与工程中应先解释“分组列或聚合列”这一基本规则,再说明函数依赖是更精确的例外。

三、NULL 如何参与分组和聚合

分组时,所有 NULL 分组键会归入同一组。聚合函数方面:

  • COUNT(*) 统计组内行数;
  • COUNT(column) 只统计该列非 NULL 的行;
  • SUMAVGMINMAX 通常忽略 NULL
  • 若一组没有任何非 NULL 输入,许多聚合函数返回 NULL,而 COUNT 返回 0

需要把空值当作零参与业务计算时,应根据语义使用 COALESCE,不能默认数据库会把 NULL 当成 0

四、WHERE 与 HAVING 的分工

SELECT customer_id, SUM(amount) AS total
FROM orders
WHERE status = 'paid'
GROUP BY customer_id
HAVING SUM(amount) >= 10000;

WHERE 先留下已支付订单,GROUP BY 再按客户分组,HAVING 最后筛选累计金额达标的客户。行级条件前置通常能减少分组工作量。

五、GROUP BY 不保证排序

分组结果看起来可能按分组键排列,但 SQL 不承诺没有 ORDER BY 的输出顺序。若业务要求稳定顺序,必须显式写:

ORDER BY total DESC, customer_id ASC

同理,依赖某次执行“碰巧返回第一行”的代码也不可靠。

六、常见误区与追问

SELECT 中的表达式是否通常允许原因
分组列每组内该值确定
聚合函数多行被归约为一个值
非分组普通列组内可能有多个候选值
由分组键唯一决定的列视数据库而定涉及函数依赖识别
  • 误区:GROUP BY 后可以随便 SELECT 任意列。 分组后每组只输出一行,普通列如果既不是分组键也不能由分组键唯一确定,就没有确定语义。
  • 误区:GROUP BY 会自动排序。 分组实现可能碰巧按某种顺序输出,但 SQL 结果顺序只有 ORDER BY 才保证。
  • 误区:聚合函数都会把 NULL 当 0。 多数聚合会忽略 NULLSUM/AVG 在全为空时可能返回 NULL,只有 COUNT 的计数规则不同。
  • 追问:为什么 MySQL 的 ONLY_FULL_GROUP_BY 很重要? 它会拒绝不确定的分组查询,避免从组内随机取一个非分组列导致线上结果随执行计划变化。
  • 追问:WHERE 和 HAVING 能互换吗? 行级条件放 WHERE,聚合后条件放 HAVING;能提前过滤的条件尽量前置,减少分组输入量。
  • 追问:按主键 GROUP BY 时能不能 SELECT 其他列? 理论上主键能唯一决定同一行的其他列,但可移植写法仍建议显式理解函数依赖,不要把宽松数据库行为当标准。

记忆钩子:GROUP BY 的核心是“每组只剩一行”,所以输出列必须能在这一组里得到唯一答案。

七、加强记忆

GROUP BY 先按键把行装进不同的组,聚合函数再把每组压成一个结果。输出列必须能为每组确定唯一值;NULL 分组键归为一组,多数聚合忽略 NULL,COUNT(*) 仍统计整行。分组不负责排序,稳定顺序必须写 ORDER BY。