首页/数据/SQL 速查/多列分组
聚合与窗口函数54 条

多列分组

GROUP BY 多列时按列组合分组:结果行数等于组合数;顺序影响中间排序但结果集一致。

SQL 速查数据更新于 2026-10-13

多列分组是什么

GROUP BY 写多列时,按这些列取值的组合来分组,结果行数等于实际出现过的组合数。列的顺序会影响中间排序与索引利用,但不会改变结果集合。多列分组常用来一次产出多维度的交叉统计。

基本信息

语义按列的取值组合分组,每个组合一行
顺序GROUP BY a, b 与 GROUP BY b, a 结果集相同,中间过程可能不同
索引复合索引按最左前缀匹配分组列可省去排序步骤
结果行数等于实际组合数,比单列分组更容易放大
HAVING对分组后的聚合结果过滤,例如只留数量大于 1 的组合
与窗口函数需要保留明细行时用窗口函数而不是分组

两列组合统计

两列组合统计
SELECT city, status,
       COUNT(*)    AS cnt,          -- 每个组合的记录数
       SUM(amount) AS amount_sum    -- 每个组合的金额合计
FROM users
GROUP BY city, status               -- 组合分组
HAVING COUNT(*) > 0                 -- 过滤分组结果
ORDER BY city, status;              -- 分组后顺序不保证,必须显式排序

转成二维交叉表

转成二维交叉表
-- 把某一列的取值变成列,做简单交叉表
SELECT city,
       SUM(CASE WHEN status = 1 THEN 1 ELSE 0 END) AS active_cnt,    -- 启用数
       SUM(CASE WHEN status = 0 THEN 1 ELSE 0 END) AS inactive_cnt   -- 停用数
FROM users
GROUP BY city
ORDER BY city;   -- 展示友好的形态,比多列分组更直观

要点与风险

要点说明风险
分组粒度组合数由数据分布决定组合爆炸会让结果行数远超预期
列顺序不影响结果集与索引顺序不一致时排序成本上升
NULL 分组NULL 自成一组的语义按库而异容易出现一行“空值”稀释统计
HAVING对聚合结果过滤与 WHERE 位置写错结果不同
索引匹配遵循最左前缀前导列缺失时索引帮助有限

典型使用场景

  • 多维交叉统计:城市加状态、渠道加品类
  • 分组去重统计:按组合看有多少个不同主体
  • 排查重复数据:同一业务键出现多行时用组合分组定位
  • 报表钻取:先按粗粒度分组,再按细粒度组合展开
  • 对比不同维度的分布,判断数据是否均衡
  • 为下游宽表准备聚合结果
NULL 会自成一个分组:某列没有取值的记录会聚成一行,不看清楚就会稀释统计。需要排除时在 WHERE 里加 IS NOT NULL,需要保留时要在口径说明里点出来。
多列分组的行数容易失控:组合数接近各列基数的乘积,上线前先用 SELECT COUNT(*) 包一层分组子查询估算结果行数,避免把明细表扫爆。

易错点

  • 把多列分组当单列看:行数按组合数增长,报表页数可能远超预期
  • 分组列顺序与索引顺序不一致:优化器需要额外排序,关注执行计划里的额外步骤
  • 忽略 NULL 自成一组:统计总数时对不上,先确认是否需要过滤或单独归集
  • HAVING 与 WHERE 混用:过滤原始行用 WHERE,过滤聚合结果才用 HAVING,位置写错结果不同

数据来源与参考

  • MySQL 8.0 Reference Manual · GROUP BY
  • PostgreSQL Documentation · GROUP BY
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌