从报表需求认识 ROLLUP:它到底解决了什么问题
做后台管理系统或者报表导出的时候,我猜你大概率遇到过这种场景:运营要一张表,里面既要看到每一个品类、每一个月的销售额,又要在每段后面跟上小计,最后还要有一个总计行。第一反应就是写 GROUP BY,然后拿到数据在前端挨个算,或者干脆查三次 SQL 再拼结果。麻烦不说,数据不一致的风险还一直悬着。其实 MySQL 很早就给了答案,就是标题里这个 ROLLUP。
ROLLUP 是 GROUP BY 的一个扩展选项,名字直译是"上卷"。它的作用是在分组统计的基础上,自动往上多算一层汇总。比如 GROUP BY 某个字段只能得到明细分组,加上 WITH ROLLUP 之后,会把所有分组的合计、以及更粗粒度层级的小计也一起算出来。换句话说,一条 SQL 就能把"明细分组 + 小计 + 总计"全部带回来,前端直接渲染,后端不用再做二次聚合。
这篇文章适合谁?一类是刚接触聚合查询、对 GROUP BY 进阶用法还不熟的新手,另一类是写报表 SQL 写到想骂人的业务开发。我会从基础语法开始,把它的结果集规律、怎么区分汇总行、以及几个容易踩的坑一次性讲透。
1. 先建立实验环境:一张销售明细表
讲 SQL 不能空对空,我们先把实验表建出来。下面这张表模拟了一个简单的线上销售场景,包含订单 ID、销售日期、所属区域、产品类目、销售额这几个字段。
sql复制CREATE TABLE sales (
id INT PRIMARY KEY AUTO_INCREMENT,
sale_date DATE NOT NULL,
region VARCHAR(20) NOT NULL,
category VARCHAR(20) NOT NULL,
amount DECIMAL(10,2) NOT NULL
);
插入几行模拟数据,注意数据要覆盖多个日期、多个区域、多个类目,后面跑 ROLLUP 才看得清结果:
sql复制INSERT INTO sales (sale_date, region, category, amount) VALUES
('2024-01-05', '华东', '数码', 3200.00),
('2024-01-12', '华东', '家电', 5400.00),
('2024-01-18', '华北', '数码', 2100.00),
('2024-01-25', '华北', '服装', 1800.00),
('2024-02-03', '华东', '数码', 4300.00),
('2024-02-08', '华南', '家电', 6200.00),
('2024-02-14', '华南', '服装', 2500.00),
('2024-02-21', '华北', '数码', 3900.00),
('2024-03-02', '华东', '服装', 1600.00),
('2024-03-11', '华南', '数码', 4800.00),
('2024-03-20', '华北', '家电', 5100.00),
('2024-03-27', '华东', '家电', 3600.00);
字段不多,但足够演示单列分组、多列分组、时间维度汇总这些典型场景。下面所有示例都会基于这份数据运行,你可以直接复制到本地 MySQL 8.0 环境里跑。
提示:这里选用 MySQL 8.0 版本,8.0 对 GROUP BY 相关语法支持完善,而且引入了 GROUPING() 函数,对区分汇总行非常有用。MySQL 5.7 及更低版本也支持 ROLLUP,但没有 GROUPING(),后面会专门说怎么兼容。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 基础语法与结果集规律:一条 SQL 拿到分组+汇总
2.1 基本用法:GROUP BY 后加 WITH ROLLUP
先看最常见的写法。假设我们要按照产品类目统计销售额,并且需要知道所有类目的销售总额:
sql复制SELECT category, SUM(amount) AS total_amount
FROM sales
GROUP BY category WITH ROLLUP;
执行结果会是这样:
| category | total_amount |
|---|---|
| 服装 | 5900.00 |
| 家电 | 20300.0 |
