多维汇总应使用rollup、cube或grouping sets:rollup按字段顺序逐级卷起,适合层级关系;cube穷举所有组合,性能开销大;grouping sets显式定义所需分组,最可控;三者均需grouping()函数区分null是真实值还是汇总占位符。

直接用 GROUP BY 多字段只能出固定粒度,真要按“地区+产品+时间”任意组合出明细、小计、总计,得靠 ROLLUP、CUBE 或 GROUPING SETS —— 它们才是多维汇总的正确入口。
ROLLUP 适合有明确层级关系的维度(比如年→季→月)
ROLLUP 按字段顺序从左到右逐级“卷起”,生成天然的树状汇总结构。它不猜业务逻辑,只认顺序:写成 GROUP BY ROLLUP(year, quarter, month),就一定先出月级明细,再每季度小计,最后年度总计;反过来写就全乱。
- 汇总行中靠右字段为
NULL,表示该层被折叠(如year=2024, quarter='Q1', month=NULL就是 Q1 小计) - 必须用
GROUPING()判断NULL是真实数据还是汇总占位,否则把原始month IS NULL的记录误标为“Q1 小计” - MySQL 8.0+、PostgreSQL 9.5+、SQL Server 都支持,但 SQLite 和旧版 MySQL 不行
- 别在
SELECT里引用没出现在ROLLUP列表里的非聚合字段,会报错或结果不可靠
CUBE 适合需要所有交叉组合(比如地区×产品×渠道全排列)
CUBE 不管顺序,暴力穷举所有 2ⁿ 种分组组合,包括空集(全表总计)。5 个维度就是 32 行结果 —— 这不是“多几行”,而是执行计划要跑 32 路聚合,内存和 CPU 压力陡增。
-
region和product同时为NULL,可能是“全国总销售额”,也可能是原始数据里真有双NULL记录,必须靠GROUPING(region)和GROUPING(product)双判断才能区分 - 结果里大量
NULL是正常现象,不是数据脏,是 CUBE 的语义约定 - 如果只需要部分组合(比如不要纯“渠道”汇总),别硬套
CUBE,换GROUPING SETS - Oracle、PostgreSQL、SQL Server 支持,MySQL 目前(8.4)仍不支持
CUBE,会报ERROR 1064
GROUPING SETS 是最可控的显式组合方案
当你清楚知道只要哪几档汇总(比如“部门+城市明细”、“部门小计”、“城市小计”、“全公司总计”),GROUPING SETS 就是最稳的选择 —— 它不生成冗余组合,也不依赖字段顺序,逻辑完全由你定义。
- 每个元组代表一个分组维度,
()表示全局总计,不能省略括号 - 未参与当前分组的字段值自动为
NULL,这是识别层级的线索,但不能直接用IS NULL判断,必须配合GROUPING() - MySQL 至今(8.4)不支持
GROUPING SETS,硬写会报错;PostgreSQL、SQL Server、Oracle 都支持 - 字段顺序不影响分组逻辑,但会影响
GROUPING()返回值的解读方式(比如GROUPING(dept)在 (dept, city) 组合里返回 0,在 (city) 组合里返回 1)
真正容易被忽略的点是:NULL 在多维汇总里永远有两种身份——真实缺失值,和引擎生成的汇总占位符。不用 GROUPING() 函数,光靠 COALESCE 或 IS NULL 做判断,报表口径一定出错。










