group by 是sql中实现分类汇总的核心语句,必须配合sum、count、avg等聚合函数使用,且select中的非聚合列必须全部出现在group by子句中;支持多列分组、with rollup生成小计总计、having筛选分组结果、order by控制排序,并需注意null处理与执行顺序。

GROUP BY 是分类汇总的核心,但不能只写 GROUP BY
直接用 GROUP BY 只能分组,不加聚合函数就报错——这是新手最常踩的坑。Excel 里点一下“分类汇总”自动算求和、计数、平均值,SQL 里必须显式写出每个要汇总的字段和对应的聚合函数。
比如按部门统计人数和平均薪资,得这样写:
SELECT dept, COUNT(*) AS cnt, AVG(salary) AS avg_salary FROM emp GROUP BY dept;
注意:COUNT(*) 统计行数,COUNT(salary) 会忽略 NULL 值;AVG() 同样跳过 NULL,这点和 Excel 默认行为一致,但容易被忽略。
需要小计和总计?ROLLUP 比 UNION 更可靠
Excel 的“分类汇总”支持嵌套小计(如部门→岗位→员工)和底部总计,SQL 里用 GROUP BY ... WITH ROLLUP 能原生支持,比手写多个 UNION ALL 更简洁、更易维护。
示例:按部门、岗位两级汇总,并生成小计和总计:
SELECT COALESCE(dept, '总计') AS dept, COALESCE(role, '小计') AS role, COUNT(*) AS cnt FROM emp GROUP BY dept, role WITH ROLLUP;
WITH ROLLUP 会在每级分组后插入一行 NULL 值,用 COALESCE 替换掉才像 Excel 输出;但要注意顺序:GROUP BY a, b WITH ROLLUP 产生的是 (a,b) → (a,NULL) → (NULL,NULL),不是 (b,NULL)。
过滤汇总结果要用 HAVING,不是 WHERE
Excel 里汇总完再筛选“人数 > 5 的部门”,SQL 里不能用 WHERE 过滤聚合后的结果——WHERE 在分组前执行,HAVING 才作用于分组后。
-
WHERE salary > 5000:先筛出高薪员工,再分组 -
HAVING COUNT(*) > 5:分组后只保留人数超 5 的部门 - 二者逻辑完全不同,混用会导致结果偏差甚至报错
常见错误是把 HAVING 当成“带条件的 GROUP BY”,其实它只是对 GROUP BY 结果的二次筛选,且只能引用 SELECT 中出现的分组字段或聚合表达式。
排序混乱?ORDER BY 必须放在最后且注意 NULL 位置
分类汇总结果默认无序,加 ORDER BY 才能控制展示顺序。但要注意:WITH ROLLUP 生成的 NULL 行在排序时排最前(MySQL)或最后(PostgreSQL),行为不一致。
稳妥做法是显式控制 NULL 位置:
SELECT dept, role, COUNT(*) AS cnt FROM emp GROUP BY dept, role WITH ROLLUP ORDER BY dept IS NULL DESC, dept, role IS NULL DESC, role;
这里 dept IS NULL DESC 把总计行压到底部;不同数据库对 NULLS FIRST/LAST 支持不同,用布尔表达式兼容性更好。
真正麻烦的不是语法,而是理解“分组→聚合→筛选→补空行→排序”这个链条里每一步的执行顺序和数据形态变化——漏掉任一环,结果就和 Excel 对不上。











