GROUP BY用于先分组再聚合,必须在WHERE后、ORDER BY前,SELECT中非聚合字段须全部出现在GROUP BY中;多字段分组按值完全相同归组;HAVING用于过滤分组结果,可使用聚合函数。

MySQL 中的 GROUP BY 用于将查询结果按一个或多个字段进行分组,配合聚合函数(如 COUNT()、SUM()、AVG()、MAX()、MIN())统计每组的数据。它不是简单“分组”,而是“先分组、再聚合”,理解这一点是正确使用的前提。
基础语法与核心逻辑
GROUP BY 必须出现在 WHERE 子句之后、ORDER BY 之前;SELECT 列表中所有非聚合字段都必须出现在 GROUP BY 子句中(SQL 标准要求,MySQL 5.7+ 默认开启 ONLY_FULL_GROUP_BY 模式后强制校验)。
- ✅ 正确写法:
SELECT dept, COUNT(*) FROM emp GROUP BY dept; - ❌ 错误写法:
SELECT dept, name, COUNT(*) FROM emp GROUP BY dept;(name 不在 GROUP BY 中,也不聚合,会报错) - ? 小技巧:若想查每组中某条记录(如最新一条),不能只靠 GROUP BY,需结合子查询、窗口函数(MySQL 8.0+)或 JOIN 处理。
多字段分组与组合统计
按多个字段分组时,MySQL 将“字段值完全相同”的记录归为一组,适合分析交叉维度数据。
- 例如统计“每个部门每种职位的人数”:
SELECT dept, job, COUNT(*) FROM emp GROUP BY dept, job; - 注意顺序不影响分组逻辑,但影响结果排序(除非显式加 ORDER BY)
- 可对分组结果进一步筛选,用 HAVING(不是 WHERE)——WHERE 过滤行,HAVING 过滤组。
HAVING 过滤分组结果
HAVING 在分组和聚合计算完成后执行,用于筛选满足条件的组;WHERE 无法使用聚合函数,但 HAVING 可以。
- 查人数超过 2 人的部门:
SELECT dept, COUNT(*) FROM emp GROUP BY dept HAVING COUNT(*) > 2; - 查平均工资高于 8000 的部门:
SELECT dept, AVG(salary) FROM emp GROUP BY dept HAVING AVG(salary) > 8000; - WHERE + HAVING 可共存:WHERE 先过滤原始数据(如
WHERE status='active'),再分组,最后 HAVING 筛组。
常见误区与注意事项
GROUP BY 容易因理解偏差导致结果异常或报错。
- ⚠️ 不要依赖 MySQL 旧版本的“隐式 GROUP BY”行为(如 SELECT id, name, COUNT(*) GROUP BY dept),该写法不标准且在严格模式下失败。
- ⚠️ 聚合函数作用于每组内部,不是全表。比如
MAX(salary)返回的是每组最高薪,不是整张表最大值。 - ✅ 排序建议显式写:
ORDER BY COUNT(*) DESC,避免依赖默认顺序。 - ✅ MySQL 8.0+ 推荐用窗口函数替代部分复杂分组需求,如
ROW_NUMBER() OVER (PARTITION BY dept ORDER BY salary DESC)查各部门最高薪员工。










