group by 为聚合函数提供分组依据,select 中非聚合字段必须出现在 group by 中或被聚合函数包裹;支持单/多字段分组,null 视为同一组;having 用于分组后筛选,order by 可配合使用,rollup/cube 提供高级汇总。

SQL 中统计数量、求和、算平均值等操作,离不开 GROUP BY。它不是简单地“把相同值的行堆在一起”,而是为聚合函数提供分组依据——没有 GROUP BY,SUM、COUNT 这类函数就只能算全表,无法按类别分开统计。
GROUP BY 的核心规则
SELECT 列中出现的字段,必须满足以下任一条件:
- 是 GROUP BY 子句中明确列出的列(即分组依据)
- 被包裹在聚合函数里(如 COUNT(*)、SUM(price)、AVG(score))
违反这条规则会直接报错,例如:SELECT name, age, COUNT(*) FROM users GROUP BY name —— age 不在 GROUP BY 中,也不在聚合函数里,数据库拒绝执行。
单字段与多字段分组的实际效果
单字段分组最常见,比如按部门统计人数:
SELECT department, COUNT(*) AS cnt FROM employees GROUP BY department;多字段分组本质是“先按第一列粗分,再在每组内按第二列细分”。例如:
SELECT department, gender, AVG(salary) FROM employees GROUP BY department, gender;这会生成类似“技术部-男”“技术部-女”“销售部-男”等独立组合。注意:NULL 值会被当作同一类处理,所有 gender 为 NULL 的记录会归入同一个分组。
HAVING:对分组结果做筛选
WHERE 在分组前过滤原始行,HAVING 则在分组后过滤“组”。想查员工数超过 10 人的部门?不能写 WHERE COUNT(*) > 10(WHERE 看不到聚合结果),得用:
SELECT department, COUNT(*) AS cnt FROM employees GROUP BY department HAVING COUNT(*) > 10;HAVING 后面可以跟聚合函数或分组字段,作用对象是“组”,不是单条记录。
实用技巧与常见误区
有些需求容易踩坑,提前注意可省去调试时间:
- ORDER BY 可以放心用在 GROUP BY 后,比如按平均薪资降序排列:
ORDER BY AVG(salary) DESC - GROUP_CONCAT() 能把每组内的多个值拼成字符串,适合查看“某部门有哪些员工”这类场景
- 避免在 GROUP BY 中堆太多字段(如超过 3 个),性能会明显下降;高频分组字段建议建复合索引,且把区分度高的列放前面
- ROLLUP 和 CUBE 属于高级汇总,能自动生成小计/总计行,但并非所有数据库都默认支持(MySQL 5.7+ 支持 ROLLUP,CUBE 多见于 SQL Server、Oracle)










