ROLLUP可一键生成明细、小计和总计,但需用GROUPING()区分真实NULL与占位符,MySQL 8.0+、PostgreSQL、SQL Server均支持;老版本需UNION ALL硬拼并严格对齐字段类型与排序。

用 GROUP BY + ROLLUP 快速生成小计和合计
直接上结论:MySQL 8.0+、PostgreSQL、SQL Server 都支持 ROLLUP,一条 GROUP BY ... WITH ROLLUP 就能同时出明细、按区域小计、按年份小计、总计——不用写多个 UNION 或嵌套子查询。
常见错误是把 ROLLUP 当成普通分组用,结果发现 NULL 值一堆,还搞不清哪行是小计。关键在于理解 ROLLUP 生成的 NULL 是“占位符”,代表该层级聚合(比如 region 为 NULL 且 year 有值,说明这是该年的跨区域合计)。
-
GROUP BY region, year WITH ROLLUP会生成 4 层:每组 (region, year) → 每个 region 小计(year为NULL)→ 总计(region和year都为NULL) - 用
CASE WHEN region IS NULL AND year IS NOT NULL THEN '年度合计'...可人工标注汇总行,避免靠 NULL 判断逻辑出错 - MySQL 中
ROLLUP不能和ORDER BY混用(会报错),得用子查询或窗口函数二次排序
用 GROUPING() 区分真实 NULL 和汇总占位符
销售数据里 region 字段本身可能存真实 NULL(比如未归属区域),这时单看 region IS NULL 会误判汇总行。必须用 GROUPING(region) —— 返回 1 表示这是 ROLLUP 生成的占位,0 表示原始数据里的 NULL。
PostgreSQL 和 SQL Server 支持 GROUPING();MySQL 8.0+ 也支持,但旧版不支持,得改用 IF(GROUPING(region), '小计', region) 这类写法。
-
SELECT GROUPING(region) AS is_region_rollup, GROUPING(year) AS is_year_rollup, ...先确认各层聚合状态 - 组合判断:
CASE WHEN GROUPING(region)=1 AND GROUPING(year)=0 THEN '年度合计' WHEN GROUPING(region)=1 AND GROUPING(year)=1 THEN '总计' ELSE region END - 别在 WHERE 里过滤
GROUPING()结果——它只能用于 SELECT 或 HAVING,否则报错
MySQL 5.7 或更老版本怎么办
没 ROLLUP 或 GROUPING()?老版本只能硬拼 UNION ALL,但要注意字段对齐和排序混乱问题。
典型结构是三块 SELECT 合并:明细行 → 按区域小计 → 总计。最容易踩的坑是字段类型不一致(比如明细用 DECIMAL,小计行用 CAST(SUM(...) AS CHAR) 导致排序错乱),或者漏加 ORDER BY 控制展示顺序。
- 所有
UNION ALL子句的列数、类型、顺序必须严格一致;建议统一用CAST显式转类型 - 加一列
sort_order(如1 AS sort_order)控制合并后顺序,再用外层ORDER BY sort_order, region, year - 小计行的非聚合字段(如
region)要显式写'小计'或NULL,不能留空,否则前端渲染容易出错
导出报表时合计行被 Excel 自动识别为“汇总”并折叠
很多 BI 工具或 Excel 导入 CSV 时,看到连续的合计行(尤其带 NULL 或特殊标记)会自动启用分级显示,把小计行折叠掉。这不是 SQL 问题,但直接影响使用体验。
解决思路不是改 SQL,而是控制输出格式:给合计行加前缀(如 [小计])、用不可见字符占位、或导出时禁用 Excel 的“自动检测标题/汇总”选项。
- 在 SQL 里写
CONCAT('[小计] ', region)替代纯region,Excel 就不会误判为可折叠节点 - 如果用 Python pandas 导出,设
df.to_excel(..., engine='openpyxl', index=False)并关闭自动筛选和分级 - 真正麻烦的是下游系统直接连数据库查表——这时候合计行必须用业务字段标识(如
report_level= 'total'),不能只靠 NULL 或空字符串
实际做报表时,最常被忽略的是「汇总层级语义是否清晰」:用户看到一行 region=NULL, year=2023,未必明白这是 2023 年全量合计,还是数据缺失。加明确标签比依赖 NULL 更可靠。










