group by rollup 是生成多级汇总报表的高效方法,自动添加小计和总计行;其层级由字段顺序决定,null 表示上卷,用 grouping() 函数精准识别,避免原始 null 误判。

SQL 中 GROUP BY ROLLUP 能自动在分组结果中插入小计行和总计行,无需手动 UNION ALL 拼接,是生成多级汇总报表的高效写法。关键在于理解其层级逻辑和如何识别小计/总计行。
ROLLUP 的分组层级与 NULL 含义
ROLLUP(a, b, c) 会生成 4 组分组:
(a,b,c) → 原始明细粒度
(a,b,NULL) → a 和 b 维度的小计(c 被上卷)
(a,NULL,NULL) → a 维度的小计(b、c 全上卷)
(NULL,NULL,NULL) → 全局总计
每层上卷时,右侧列值变为 NULL,这是识别小计/总计的唯一可靠依据。
用 CASE 区分小计/总计并命名
直接查出 NULL 不直观,建议用 CASE 显式标注:
SELECT
CASE
WHEN grouping(c) = 1 AND grouping(b) = 1 THEN '总计'
WHEN grouping(c) = 1 THEN '小计(' || a || ', ' || b || ')'
WHEN grouping(b) = 1 THEN '小计(' || a || ')'
ELSE a
END AS group_label,
COALESCE(a, 'ALL') AS a,
COALESCE(b, 'ALL') AS b,
COALESCE(c, 'ALL') AS c,
SUM(sales) AS total_sales
FROM orders
GROUP BY ROLLUP(a, b, c)
ORDER BY a, b, c;
注意:GROUPING(col) 函数返回 1 表示该列被上卷(即实际为 NULL),比直接判 IS NULL 更安全(避免原始数据真含 NULL 的歧义)。
控制小计层级与避免冗余
ROLLUP 严格按字段顺序逐级上卷。若只需 a 和总计,不要 a-b 小计,就别写 ROLLUP(a,b),改用:
-
GROUP BY a+ 单独UNION ALL总计(简单明确) - 或用
GROUPING SETS ((a), ())—— 更灵活,只定义想要的组合 - 避免对高基数列(如订单ID)用 ROLLUP,会导致大量无意义小计行
兼容性与替代写法提示
MySQL 8.0+、PostgreSQL 9.5+、SQL Server、Oracle 均支持 ROLLUP;旧版 MySQL 需用 WITH ROLLUP(语法位置不同,且不支持 GROUPING())。如遇不支持环境,可用:
- 子查询 +
UNION ALL多次聚合(可读性差但通用) - 窗口函数
SUM() OVER ()实现总计,再配合GROUP BY做小计(需业务逻辑允许)










