ROLLUP 是什么
ROLLUP 在普通分组的基础上额外产出小计与总计行:按 a、b 分组时,结果里会同时出现每个 a 下的明细行、每个 a 的小计行(b 显示为 NULL),以及整表合计行(a、b 都为 NULL)。MySQL 8 用 GROUP BY a, b WITH ROLLUP,PostgreSQL 9.5+ 用标准写法 GROUP BY ROLLUP(a, b)。风险点在于区分「小计行」与「真实的 NULL 分组」:两者外观相同,必须用 GROUPING() 判断,否则口径会乱。
基本信息
| 适用平台 | MySQL 8.0(WITH ROLLUP 或 ROLLUP(...))、PostgreSQL 9.5+ |
|---|---|
| MySQL 写法 | GROUP BY 列… WITH ROLLUP,或 GROUP BY ROLLUP(列…) |
| PostgreSQL 写法 | GROUP BY ROLLUP (列…) |
| 层级判定 | GROUPING() 返回 1 表示该列由聚合上卷而来,MySQL 按列分别调用 |
| 排序建议 | 把 GROUPING() 结果放进 ORDER BY,让明细行在前、小计合计在后 |
典型使用场景
- 报表输出小计与合计,避免手工累加或多次查询
- 按地区与渠道两级汇总销售额
- 多级维度逐层上卷,一次查询拿到所有层级
- 与 GROUPING() 配合标记每一行的层级,前端据此缩进展示
- 替代多次 UNION ALL 拼装的分层统计,写法更短且口径统一
MySQL 写法
MySQL 写法
SELECT COALESCE(region, '全部') AS region,
COALESCE(channel, '小计') AS channel,
SUM(amount) AS total,
GROUPING(region) AS g_region, # 1 表示该列是上卷小计
GROUPING(channel) AS g_channel
FROM orders
GROUP BY region, channel WITH ROLLUP
ORDER BY g_region, region, g_channel;PostgreSQL 写法
PostgreSQL 写法
-- 标准写法,括号里是上卷顺序:先 channel,再 region
SELECT COALESCE(region, '全部') AS region,
COALESCE(channel, '小计') AS channel,
SUM(amount) AS total,
GROUPING(region, channel) AS grp -- 多参数返回位掩码
FROM orders
GROUP BY ROLLUP (region, channel)
ORDER BY grp, region, channel;层级判定与排序
| 判定结果 | 含义 | 处理建议 |
|---|---|---|
| GROUPING 为 0 | 该列参与分组,是明细行 | 正常展示列值 |
| GROUPING 为 1(某一列) | 该列为上卷产生的小计/合计行 | 显示「小计」「全部」等标签 |
| 多列 ROLLUP | 按括号内顺序自右向左逐层上卷 | 排序列顺序与 ROLLUP 保持一致 |
| 真实 NULL 分组 | 与小计行外观相同 | 必须用 GROUPING() 区分,不能靠 IS NULL |
把 GROUPING() 的返回值参与排序,就能自然得到「明细在前、小计居中、合计在最后」的层次结构;只按列值排序会把小计行的 NULL 排到最前面。
真实 NULL 分组与 ROLLUP 生成的小计行在结果里长得一样:直接对分组列做 COALESCE 会把真实空值也标成「小计」,必须用 GROUPING() 区分层级后再做展示处理。
ROLLUP 是 GROUPING SETS 的特例:它只按列顺序逐层上卷(a,b 组合、a 单独、全表),不会生成所有维度组合;需要「每个维度各自的小计」这类交叉统计时要用 CUBE 或 GROUPING SETS。