rollup仅按group by列左前缀顺序生成固定层级汇总,如rollup(region,city,product)产出(region,city,product)→(region,city)→(region)→()四层,不支持跳级组合;顺序错误、where误用或未配合grouping()将导致数据遗漏或误判。

ROLLUP 不是万能的多级汇总方案,它只按 GROUP BY 列的左前缀顺序生成固定层级的空值占位汇总行,用错顺序或混用 WHERE 就会漏数据。
ROLLUP 的分组顺序决定汇总层级
ROLLUP(region, city, product) 生成的汇总行严格对应三类组合:(region, city, product)、(region, city)、(region)、()(全表总计)。它不会出现 (region, product) 这种跳级组合。
- 如果想先按
product再按region汇总,必须写成 ROLLUP(product,region) —— 顺序不能靠 ORDER BY 补救 - MySQL 8.0+ 和 PostgreSQL 支持,但 SQLite 的 ROLLUP 是语法糖,底层仍走 UNION ALL 模拟,大数据量时性能明显下降
- Oracle 中需配合
GROUPING()函数识别哪一列是汇总产生的 NULL,否则无法区分真实 NULL 和占位 NULL
WHERE 条件必须放在 GROUP BY 之前过滤
在 ROLLUP 查询中写 WHERE city = 'Beijing' 会导致 (region) 和 () 这两级汇总丢失 Beijing 以外的数据,但它们本应包含所有 city 的聚合结果。正确做法是用 HAVING 或子查询预过滤。
- 错误:
SELECT region, city, SUM(sales) FROM t GROUP BY region, city WITH ROLLUP WHERE city = 'Beijing'—— SQL 语法直接报错,WHERE 不能出现在 GROUP BY 后 - 正确:先过滤再汇总,例如用 CTE:
WITH filtered AS (SELECT * FROM t WHERE city IN ('Beijing', 'Shanghai'))<br>SELECT region, city, SUM(sales) FROM filtered GROUP BY region, city WITH ROLLUP - 若需保留全部 region 汇总但只展示部分 city 的明细,用
HAVING GROUPING(city) = 1 OR city IN ('Beijing', 'Shanghai')
ROLLUP 和 GROUPING() 配合识别汇总行
单纯看 city 列为 NULL,无法判断这是某 region 下所有 city 的小计,还是全表总计。必须用 GROUPING() 检查各列是否参与了当前分组。
-
GROUPING(region)= 1 且GROUPING(city)= 1 → 全表总计行 -
GROUPING(region)= 0 且GROUPING(city)= 1 → 某 region 小计行 -
GROUPING(region)= 0 且GROUPING(city)= 0 → 明细行 - PostgreSQL 中函数名是
GROUPING(),MySQL 中也支持同名函数,但旧版 MySQL 需用ISNULL()+ 逻辑推断,不可靠
真正麻烦的是嵌套维度场景,比如既要按时间周期(年/月/日)又要按地域(国家/省/市),ROLLUP 只能选一条路径展开;这时候得考虑用 GROUPING SETS 或手写 UNION ALL,而不是硬塞进 ROLLUP 里凑数。










