MySQL WITH ROLLUP 怎样生成小计和总计
MySQL 要在分组明细后同时生成小计和总计,可以在 GROUP BY 末尾加上 WITH ROLLUP。单列分组会多出总计行;多列分组则会按照列的先后顺序逐级生成小计,最后再生成总计。汇总行中的分组列通常显示为 NULL,如果源数据本身也允许 NULL,应配合 GROUPING() 判断它是不是 ROLLUP 产生的汇总值。
官方地址:https://dev.mysql.com/doc/refman/8.4/en/group-by-modifiers.html
GROUP BY year WITH ROLLUP在各年份之后追加全部年份的总计。GROUP BY year, country, product WITH ROLLUP会依次得到产品小计、国家小计和总计。GROUPING(column)返回 1 表示该列的NULL是汇总标记,返回 0 表示普通分组值。WHERE先筛明细,HAVING GROUPING(...)适合筛选已经生成的汇总行。
先用单列 WITH ROLLUP 生成总计
假设销售数据按年份统计利润。普通 GROUP BY 只会返回每个年份的聚合结果;在末尾加上 WITH ROLLUP 后,MySQL 会再追加一行跨越全部年份的超聚合结果。
-- 建立一个只用于演示分组层级的临时表
CREATE TEMPORARY TABLE sales_summary (
sale_year INT NOT NULL,
country VARCHAR(32) NOT NULL,
product VARCHAR(32) NOT NULL,
profit DECIMAL(12, 2) NOT NULL
);
-- 按年份统计,并在末尾追加所有年份的总计
SELECT sale_year,
SUM(profit) AS total_profit
FROM sales_summary
GROUP BY sale_year WITH ROLLUP;
查询返回的最后一行中,sale_year 会显示为 NULL,total_profit 则是所有年份利润之和。这里的 NULL 不是某条销售记录缺少年份,而是 MySQL 用来表示“所有年份”的汇总标记。
MySQL 8.4 文档还给出了等价的 GROUP BY ROLLUP (sale_year) 写法。文章后面的多列示例使用更常见的 GROUP BY ... WITH ROLLUP,这样更容易看出汇总层级。

按分组列顺序生成多级小计
多列 GROUP BY 时,列的顺序就是汇总层级。下面按“年份、国家、产品”分组:最细粒度是年份+国家+产品,产品列被汇总后形成国家内的小计;继续汇总国家和产品形成年度小计;最后三列都进入汇总行,得到总计。
-- 三列从左到右定义汇总层级:年份 -> 国家 -> 产品
SELECT sale_year,
country,
product,
SUM(profit) AS total_profit
FROM sales_summary
GROUP BY sale_year, country, product WITH ROLLUP;
可以把结果理解成四个层级:
| 结果层级 | 分组列表现 | 含义 |
|---|---|---|
| 明细聚合 | 年份、国家、产品都有值 | 某年某国某产品的利润 |
| 产品小计 | 产品为 NULL | 某年某国的全部产品利润 |
| 国家小计 | 国家、产品为 NULL | 某年的全部国家和产品利润 |
| 总计 | 年份、国家、产品都为 NULL | 全部数据的利润 |
因此,想把“国家小计”放在别的业务维度上,不能只调整展示文案,而要重新排列 GROUP BY 列。ROLLUP 是沿着分组列顺序产生前缀层级,不是任意组合所有维度。
用 GROUPING() 区分汇总 NULL
如果业务字段允许真实的 NULL,仅看结果中的 NULL 就不够了。例如,某个商品没有录入产品名时,普通分组也可能出现 product IS NULL 的明细聚合行。MySQL 提供 GROUPING(product) 来区分这两种情况:普通分组返回 0,ROLLUP 产生的超聚合列返回 1。
-- 同时输出每个维度是否处于 ROLLUP 汇总层级
SELECT sale_year,
country,
product,
SUM(profit) AS total_profit,
GROUPING(sale_year) AS is_year_total,
GROUPING(country) AS is_country_total,
GROUPING(product) AS is_product_total
FROM sales_summary
GROUP BY sale_year, country, product WITH ROLLUP;
例如,某行的 product 是 NULL 且 is_product_total=0,说明它可能是源数据中的真实空值;如果 is_product_total=1,则说明这一行是产品维度被汇总后的产品小计。这个判断也适用于国家和年份列。

给汇总行加标签并筛选
直接显示 NULL 对报表用户不够友好,可以在查询列中根据 GROUPING() 替换成“小计”或“总计”。保留普通数据的真实 NULL,只替换函数返回 1 的汇总值。
-- 只给 ROLLUP 产生的空维度加标签,保留业务数据里的真实 NULL
SELECT IF(GROUPING(sale_year) = 1, '全部年份', CAST(sale_year AS CHAR)) AS year_label,
IF(GROUPING(country) = 1, '全部国家', COALESCE(country, '未填写国家')) AS country_label,
IF(GROUPING(product) = 1, '全部产品', COALESCE(product, '未填写产品')) AS product_label,
SUM(profit) AS total_profit
FROM sales_summary
GROUP BY sale_year, country, product WITH ROLLUP;
如果只想查看小计和总计,可以用多参数形式的 GROUPING() 在 HAVING 中筛选。只要任意一个分组维度进入了汇总层级,组合结果就不为 0。
-- 过滤掉最细粒度明细,只保留产品小计、国家小计和总计
SELECT sale_year,
country,
product,
SUM(profit) AS total_profit
FROM sales_summary
GROUP BY sale_year, country, product WITH ROLLUP
HAVING GROUPING(sale_year, country, product) 0;
这里的多参数结果是一个位掩码,右侧参数对应低位。实际写报表时,如果只需要某一级,分别检查目标列的 GROUPING() 值通常更直观,例如只保留产品小计可以使用 GROUPING(product)=1 AND GROUPING(country)=0。
处理排序、WHERE、HAVING 与 LIMIT 边界
ROLLUP 的汇总行是在分组聚合之后形成的,几个常见条件要放在正确位置。
-- WHERE 先缩小原始数据范围,再对过滤后的数据生成小计和总计
SELECT sale_year,
country,
product,
SUM(profit) AS total_profit
FROM sales_summary
WHERE sale_year >= 2025
GROUP BY sale_year, country, product WITH ROLLUP
-- HAVING 可以识别已经生成的 ROLLUP 行
HAVING GROUPING(sale_year, country, product) 0
-- 将总计放到结果前面;明细排序规则可按报表需要继续补充
ORDER BY GROUPING(sale_year) DESC, sale_year;
WHERE过滤源表行,适合限定年份、租户或业务范围;它不能用来判断 ROLLUP 后才出现的汇总NULL。HAVING位于聚合之后,可以使用GROUPING()选择小计或总计。ORDER BY GROUPING(sale_year) DESC可以把总计行排在前面;不写排序时,不要把默认返回顺序当成业务契约。LIMIT作用于已经包含 ROLLUP 行的结果,截断时可能把一个汇总层级切开,报表分页要特别谨慎。
如果只是需要一个总数,而不需要明细、小计和总计同时返回,单独执行聚合查询通常更容易维护。ROLLUP 更适合一次性生成层级报表,或把多级汇总交给同一个 SQL 结果集。
相关问题
WITH ROLLUP 和 GROUP BY ROLLUP() 有什么区别?
在 MySQL 8.4 的文档示例中,两者都是 ROLLUP 修饰语的写法。日常维护时选团队更熟悉的一种,并保持分组列顺序一致。
为什么 ROLLUP 的汇总行显示为 NULL?
MySQL 用分组列上的 NULL 表示该维度已经被汇总。若源数据也可能为 NULL,应使用 GROUPING() 判断它是不是超聚合标记。
可以用 WHERE product IS NULL 只取小计吗?
不建议这样做。ROLLUP 的汇总 NULL 在较晚阶段写入结果,且真实数据也可能为 NULL;使用 HAVING GROUPING(product)=1 才能明确筛选产品小计。
多列 ROLLUP 为什么会多出很多行?
每个分组列前缀都会形成一个汇总层级。分组列越多,层级越多;应先确认报表需要的维度顺序,再决定是否使用 ROLLUP。
MySQL REGEXP_LIKE 怎样判断字符串是否匹配正则
- 上一篇
- MySQL REGEXP_LIKE 怎样判断字符串是否匹配正则
- 下一篇
- MySQL ST_GeomFromText 怎样把 WKT 文本转成空间对象
-
- 数据库 · MySQL | 43分钟前 |
- MySQL 锁等待超时怎样定位阻塞事务
- 325浏览 收藏
-
- 数据库 · MySQL | 44分钟前 | MySQL · mysql 时区 STR_TO_DATE 日期时间 CONVERT_TZ
- MySQL STR_TO_DATE 怎样处理带时区的日期字符串
- 117浏览 收藏
-
- 数据库 · MySQL | 50分钟前 | MySQL · 数据校验 · mysql IPv6 INET6_ATON INET6_NTOA VARBINARY
- MySQL INET6_ATON 怎样把 IPv6 文本转成二进制
- 207浏览 收藏
-
- 数据库 · MySQL | 53分钟前 |
- MySQL JSON_SCHEMA_VALID 怎样校验 JSON 文档
- 331浏览 收藏
-
- 数据库 · MySQL | 58分钟前 |
- MySQL DECLARE HANDLER 怎样只处理 NOT FOUND 条件
- 160浏览 收藏
-
- 数据库 · MySQL | 1小时前 |
- MySQL ST_GeomFromText 怎样把 WKT 文本转成空间对象
- 339浏览 收藏
-
- 数据库 · MySQL | 1小时前 |
- MySQL REGEXP_LIKE 怎样判断字符串是否匹配正则
- 108浏览 收藏
-
- 数据库 · MySQL | 1小时前 |
- MySQL 派生表为什么阻止索引下推
- 412浏览 收藏
-
- 数据库 · MySQL | 1小时前 |
- MySQL optimizer hint 怎样临时禁止索引合并
- 325浏览 收藏
-
- 数据库 · MySQL | 1小时前 |
- MySQL performance_schema.setup_consumers 怎样开启长语句历史
- 332浏览 收藏
-
- 数据库 · MySQL | 1小时前 |
- MySQL JSON_CONTAINS_PATH 怎样判断 JSON 路径是否存在
- 399浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- PubMedQA
- 深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
- 851次使用
-
- H2O EvalGPT
- H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
- 855次使用
-
- LMArena
- LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
- 936次使用
-
- HELM
- 深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
- 910次使用
-
- MMBench
- MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
- 739次使用
-
- MySQL JSON_TABLE 展开数组时如何保留缺失字段
- 2026-09-10 501浏览
-
- MySQL 分区表怎么处理跨分区唯一键:分区列约束与建表取舍
- 2026-08-30 501浏览
-
- MySQL权限管理设置全攻略
- 2026-03-29 501浏览
-
- MySQL分片实现方法及常见方案解析
- 2025-06-24 501浏览
-
- MySQL表空间碎片怎么清理?超详细优化教程
- 2025-06-13 501浏览

