网易首页 > 网易号 > 正文 申请入驻

新特性解读 | GROUPING() 函数用法解析

0
分享至

作者:杨涛涛
资深数据库专家,专研 MySQL 十余年。擅长 MySQL、PostgreSQL、MongoDB 等开源数据库相关的备份恢复、SQL 调优、监控运维、高可用架构设计等。目前任职于爱可生,为各大运营商及银行金融企业提供 MySQL 相关技术支持、MySQL 相关课程培训等工作。
本文来源:原创投稿
*爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。

MySQL 8.0 新增了 GROUPING() 函数,用来理清 GROUP BY with rollup 子句检索后所产生的每个分组汇总结果。

grouping 可用在分组列,having 子句以及 order by 子句。在了解 grouping 函数如何使用之前,先来看看简单 group by with rollup 的检索是何种情形。

GROUP BY WITH ROLLUP

GROUP BY 子句 ROLLUP 可以为 GROUP BY 运行结果的每一个分组返回一个统计行,并且为所有分组返回一个总的统计行。此文中所用的示例表 y1 结构:

mysql> show create table y1\G
*************************** 1. row ***************************
Table: y1
Create Table: CREATE TABLE `y1` (
`id` int NOT NULL,
`r1` int DEFAULT NULL,
`r2` int DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.00 sec)

按照字段 r1 r2 来正常检索,GROUP BY 的统计结果:

mysql> SELECT r1, r2, COUNT(*)
-> FROM y1
-> GROUP BY r1, r2;
+------+------+----------+
| r1 | r2 | count(*) |
+------+------+----------+
| 1 | 2 | 2 |
| 2 | 5 | 2 |
| 1 | 4 | 1 |
| 4 | 3 | 4 |
| 2 | 2 | 3 |
| 4 | 4 | 2 |
| 5 | 5 | 1 |
| 4 | 5 | 1 |
| 3 | 1 | 1 |
| 5 | 2 | 1 |
| 4 | 2 | 1 |
| 3 | 2 | 1 |
+------+------+----------+
12 rows in set (0.00 sec)

当此条统计 SQL 加上 ROLLUP 子句后,会在每个分组后面加上一行统计值,其中统计行高位字段显示为 NULL,COUNT 结果用来计算分组内的总记录数。

mysql> SELECT r1, r2, COUNT(*)
-> FROM y1
-> GROUP BY r1, r2 WITH ROLLUP;
+------+------+----------+
| r1 | r2 | count(*) |
+------+------+----------+
| 1 | 2 | 2 |
| 1 | 4 | 1 |
| 1 | NULL | 3 |
| 2 | 2 | 3 |
| 2 | 5 | 2 |
| 2 | NULL | 5 |
| 3 | 1 | 1 |
| 3 | 2 | 1 |
| 3 | NULL | 2 |
| 4 | 2 | 1 |
| 4 | 3 | 4 |
| 4 | 4 | 2 |
| 4 | 5 | 1 |
| 4 | NULL | 8 |
| 5 | 2 | 1 |
| 5 | 5 | 1 |
| 5 | NULL | 2 |
| NULL | NULL | 20 |
+------+------+----------+
18 rows in set (0.00 sec)

那表 y1 没有记录存储为 NULL,都是非 NULL 值,现在为表 y1 插入几条包含 NULL 的记录。

mysql> insert into y1 values (21,null,null);
Query OK, 1 row affected (0.01 sec)
mysql> insert into y1 values (22,1,null);
Query OK, 1 row affected (0.01 sec)
mysql> insert into y1 values (23,2,null);
Query OK, 1 row affected (0.01 sec)
mysql> insert into y1 values (24,3,null);
Query OK, 1 row affected (0.01 sec)
mysql> insert into y1 values (25,4,null);
Query OK, 1 row affected (0.01 sec)
mysql> insert into y1 values (26,5,null);
Query OK, 1 row affected (0.01 sec)

此时再来看看 WITH ROLLUP 统计的结果。

mysql> SELECT r1, r2, COUNT(*)
-> FROM y1
-> GROUP BY r1, r2 WITH ROLLUP;
+------+------+----------+
| r1 | r2 | count(*) |
+------+------+----------+
| NULL | NULL | 1 |
| NULL | NULL | 1 |
| 1 | NULL | 1 |
| 1 | 2 | 2 |
| 1 | 4 | 1 |
| 1 | NULL | 4 |
| 2 | NULL | 1 |
| 2 | 2 | 3 |
| 2 | 5 | 2 |
| 2 | NULL | 6 |
| 3 | NULL | 1 |
| 3 | 1 | 1 |
| 3 | 2 | 1 |
| 3 | NULL | 3 |
| 4 | NULL | 1 |
| 4 | 2 | 1 |
| 4 | 3 | 4 |
| 4 | 4 | 2 |
| 4 | 5 | 1 |
| 4 | NULL | 9 |
| 5 | NULL | 1 |
| 5 | 2 | 1 |
| 5 | 5 | 1 |
| 5 | NULL | 3 |
| NULL | NULL | 26 |
+------+------+----------+
25 rows in set (0.00 sec)

由于表 y1 本身包含了一系列包含 NULL 的记录,这条 SQL 有点分不清哪些是正常的 NULL,哪些是汇总的 NULL。

接下来 GROUPING() 函数准备上场……

GROUPING() 函数

GROUPING() 函数用来返回每个分组是否为 ROLLUP 结果,是为 1 否为 0。从结果中,很容易就能区分哪些 NULL 是正常记录,哪些是 ROLLUP 的结果。

mysql> SELECT r1
-> , if(GROUPING(r1) = 1, '汇总', '正常记录') AS grouping_r1
-> , r2
-> , if(GROUPING(r2) = 1, '汇总', '正常记录') AS grouping_r2
-> , COUNT(*)
-> FROM y1
-> GROUP BY r1, r2 WITH ROLLUP;
+------+--------------+------+--------------+----------+
| r1 | grouping_r1 | r2 | grouping_r2 | count(*) |
+------+--------------+------+--------------+----------+
| NULL | 正常记录 | NULL | 正常记录 | 1 |
| NULL | 正常记录 | NULL | 汇总 | 1 |
| 1 | 正常记录 | NULL | 正常记录 | 1 |
| 1 | 正常记录 | 2 | 正常记录 | 2 |
| 1 | 正常记录 | 4 | 正常记录 | 1 |
| 1 | 正常记录 | NULL | 汇总 | 4 |
| 2 | 正常记录 | NULL | 正常记录 | 1 |
| 2 | 正常记录 | 2 | 正常记录 | 3 |
| 2 | 正常记录 | 5 | 正常记录 | 2 |
| 2 | 正常记录 | NULL | 汇总 | 6 |
| 3 | 正常记录 | NULL | 正常记录 | 1 |
| 3 | 正常记录 | 1 | 正常记录 | 1 |
| 3 | 正常记录 | 2 | 正常记录 | 1 |
| 3 | 正常记录 | NULL | 汇总 | 3 |
| 4 | 正常记录 | NULL | 正常记录 | 1 |
| 4 | 正常记录 | 2 | 正常记录 | 1 |
| 4 | 正常记录 | 3 | 正常记录 | 4 |
| 4 | 正常记录 | 4 | 正常记录 | 2 |
| 4 | 正常记录 | 5 | 正常记录 | 1 |
| 4 | 正常记录 | NULL | 汇总 | 9 |
| 5 | 正常记录 | NULL | 正常记录 | 1 |
| 5 | 正常记录 | 2 | 正常记录 | 1 |
| 5 | 正常记录 | 5 | 正常记录 | 1 |
| 5 | 正常记录 | NULL | 汇总 | 3 |
| NULL | 汇总 | NULL | 汇总 | 26 |
+------+--------------+------+--------------+----------+
25 rows in set (0.00 sec)

GROUPING() 函数不仅仅是针对单个字段来统计汇总值,还可以针对多个字段。把上面的 SQL 修改下,变为:

mysql> SELECT r1, r2, GROUPING(r1, r2) AS grouping_r1_r2
-> , COUNT(*)
-> FROM y1
-> GROUP BY r1, r2 WITH ROLLUP;
+------+------+----------------+----------+
| r1 | r2 | grouping_r1_r2 | COUNT(*) |
+------+------+----------------+----------+
| NULL | NULL | 0 | 1 |
| NULL | NULL | 1 | 1 |
| 1 | NULL | 0 | 1 |
| 1 | 2 | 0 | 2 |
| 1 | 4 | 0 | 1 |
| 1 | NULL | 1 | 4 |
| 2 | NULL | 0 | 1 |
| 2 | 2 | 0 | 3 |
| 2 | 5 | 0 | 2 |
| 2 | NULL | 1 | 6 |
| 3 | NULL | 0 | 1 |
| 3 | 1 | 0 | 1 |
| 3 | 2 | 0 | 1 |
| 3 | NULL | 1 | 3 |
| 4 | NULL | 0 | 1 |
| 4 | 2 | 0 | 1 |
| 4 | 3 | 0 | 4 |
| 4 | 4 | 0 | 2 |
| 4 | 5 | 0 | 1 |
| 4 | NULL | 1 | 9 |
| 5 | NULL | 0 | 1 |
| 5 | 2 | 0 | 1 |
| 5 | 5 | 0 | 1 |
| 5 | NULL | 1 | 3 |
| NULL | NULL | 3 | 26 |
+------+------+----------------+----------+
25 rows in set (0.00 sec)

此时会发现,GROUPING() 函数对多个字段结果并非只有 1 和 0,还有一个值为 3。在 GROUPING() 函数包含多个参数时,按照以下方式来返回结果:

  • GROUPING(r1,r2) 等价于 GROUPING(r2) + GROUPING(r1) << 1

  • GROUPING(r1,r2,r3,...) 等价于 GROUPING(r3) + GROUPING(r2) << 1 + GROUPING(r1) << 2

  • 以此类推

再次来改下以上 SQL,用 (GROUPING(r2) + (GROUPING(r1) << 1)) 来替换 GROUPING(r1,r2)

mysql> SELECT r1, r2,(grouping(r2) + (grouping(r1) << 1)) grouping_r1_r2, count(*) FROM y1 GROUP BY r
1, r2 WITH ROLLUP;
+------+------+----------------+----------+
| r1 | r2 | grouping_r1_r2 | count(*) |
+------+------+----------------+----------+
| NULL | NULL | 0 | 1 |
| NULL | NULL | 1 | 1 |
| 1 | NULL | 0 | 1 |
| 1 | 2 | 0 | 2 |
| 1 | 4 | 0 | 1 |
| 1 | NULL | 1 | 4 |
| 2 | NULL | 0 | 1 |
| 2 | 2 | 0 | 3 |
| 2 | 5 | 0 | 2 |
| 2 | NULL | 1 | 6 |
| 3 | NULL | 0 | 1 |
| 3 | 1 | 0 | 1 |
| 3 | 2 | 0 | 1 |
| 3 | NULL | 1 | 3 |
| 4 | NULL | 0 | 1 |
| 4 | 2 | 0 | 1 |
| 4 | 3 | 0 | 4 |
| 4 | 4 | 0 | 2 |
| 4 | 5 | 0 | 1 |
| 4 | NULL | 1 | 9 |
| 5 | NULL | 0 | 1 |
| 5 | 2 | 0 | 1 |
| 5 | 5 | 0 | 1 |
| 5 | NULL | 1 | 3 |
| NULL | NULL | 3 | 26 |
+------+------+----------------+----------+
25 rows in set (0.00 sec)

这里和直接 GROUPING(r1, r2) 的结果一致。
GROUPING 语句还可以用在 HAVING 子句里,比如用 GROUPING 子句来过滤掉非 ROLLUP 的结果。

mysql> SELECT r1, r2,count(*) FROM y1 GROUP BY r1, r2 WITH ROLLUP having grouping(r1) = 1 or grouping(r2) = 1;
+------+------+----------+
| r1 | r2 | count(*) |
+------+------+----------+
| NULL | NULL | 1 |
| 1 | NULL | 4 |
| 2 | NULL | 6 |
| 3 | NULL | 3 |
| 4 | NULL | 9 |
| 5 | NULL | 3 |
| NULL | NULL | 26 |
+------+------+----------+
7 rows in set (0.00 sec)


总结

这里介绍了 MySQL 8.0 的新函数 GROUPING()的用法,如有不足欢迎批评指正。

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
这天中午,男子去收废品,女子让他进屋喝口水,两人发生关系时,女子丈夫突然回家

这天中午,男子去收废品,女子让他进屋喝口水,两人发生关系时,女子丈夫突然回家

起喜电影
2024-04-27 07:50:26
想不到4月还没结束,国家一级演员何赛飞,就给影视圈演员敲警钟

想不到4月还没结束,国家一级演员何赛飞,就给影视圈演员敲警钟

陈述影视
2024-04-27 22:09:20
半小时内跑两枪!林雨薇东海岸12秒83夺银,再创赛季亚洲最佳

半小时内跑两枪!林雨薇东海岸12秒83夺银,再创赛季亚洲最佳

懂球帝
2024-04-28 10:37:14
回顾:河南好赌书记甘荣坤,一夜输掉几百万,扰乱司法,贪1.66亿

回顾:河南好赌书记甘荣坤,一夜输掉几百万,扰乱司法,贪1.66亿

江东浪流史
2024-04-28 14:04:37
现在是4月28日下午,消息不得了,突发一大要消息,要来大动作吗

现在是4月28日下午,消息不得了,突发一大要消息,要来大动作吗

股市皆大事
2024-04-28 11:30:34
傅崐萁一行人访陆进行时!朱立伦未等其返台,趁机对美献忠!

傅崐萁一行人访陆进行时!朱立伦未等其返台,趁机对美献忠!

波顿要统一
2024-04-28 11:54:22
拜登彻底输了!刚刚,英企最新消息传来,这是向中国企业投降了?

拜登彻底输了!刚刚,英企最新消息传来,这是向中国企业投降了?

户外钓鱼哥阿旱
2024-04-27 23:19:56
养老金调整总算敲定,农民、企退、事退养老金能涨多少钱?

养老金调整总算敲定,农民、企退、事退养老金能涨多少钱?

社保小达人
2024-04-28 08:45:45
59岁“李莫愁”与梁小龙聚会!颜值崩塌认不出,与李若彤似两代人

59岁“李莫愁”与梁小龙聚会!颜值崩塌认不出,与李若彤似两代人

裕丰娱间说
2024-04-27 09:42:58
55岁邓文迪最新出席晚宴把人美到!花朵裙配波浪卷发,又嫩又霸气

55岁邓文迪最新出席晚宴把人美到!花朵裙配波浪卷发,又嫩又霸气

时尚丽人风行
2024-04-27 14:50:20
皮尔斯:湖人飞到丹佛必输,系列赛5场结束。G4是掘金故意放水的

皮尔斯:湖人飞到丹佛必输,系列赛5场结束。G4是掘金故意放水的

好火子
2024-04-28 15:19:49
布林肯入住和平饭店,视野中有导弹驱逐舰,中方安排体现东方智慧

布林肯入住和平饭店,视野中有导弹驱逐舰,中方安排体现东方智慧

国平视野
2024-04-26 10:45:24
是谁?詹宁斯:库里下赛季会联手一名超巨 我深信

是谁?詹宁斯:库里下赛季会联手一名超巨 我深信

直播吧
2024-04-28 09:54:23
宗馥莉的KELLYONE饮料遇到了大麻烦

宗馥莉的KELLYONE饮料遇到了大麻烦

快乐的漂流瓶
2024-04-28 14:58:22
苗苗真的一点也不像3孩的妈,真的好少女,身材好薄好元气好白

苗苗真的一点也不像3孩的妈,真的好少女,身材好薄好元气好白

阿芒娱乐说
2024-04-27 22:36:45
一点都不想呆在中国了,出国的人已经排得人山人海到底是什么原因

一点都不想呆在中国了,出国的人已经排得人山人海到底是什么原因

娱乐圈的笔娱君
2024-04-24 15:32:30
张玉宁本轮攻破浙江队大门,他却拒绝为此庆祝,原因让球迷点赞

张玉宁本轮攻破浙江队大门,他却拒绝为此庆祝,原因让球迷点赞

罗掌柜体育
2024-04-27 15:15:35
美媒评述:中国国航订购100架C919飞机

美媒评述:中国国航订购100架C919飞机

参考消息
2024-04-28 09:11:17
湖北省纪委监委通报

湖北省纪委监委通报

湖北e家庭
2024-04-28 10:53:29
恩里克:从积分上来说还没结束,但我认为可以说我们是冠军了

恩里克:从积分上来说还没结束,但我认为可以说我们是冠军了

懂球帝
2024-04-28 07:35:34
2024-04-28 16:10:44
爱可生云数据库
爱可生云数据库
企业数据处理技术整体解决方案
411文章数 20关注度
往期回顾 全部

科技要闻

马斯克周日意外来华,目前或已身在北京

头条要闻

乌多地遭袭击 泽连斯基:至少还需7套"爱国者"防空系统

头条要闻

乌多地遭袭击 泽连斯基:至少还需7套"爱国者"防空系统

体育要闻

赢了!詹皇末节14分制胜咆哮 压力给到KD

娱乐要闻

张杰谢娜发文为何炅庆生,亲如家人!

财经要闻

日元“崩”了!影响多大?

汽车要闻

5月上市/智能化丰富 海狮 07EV正式到店

态度原创

旅游
手机
家居
游戏
亲子

旅游要闻

年轻人出游:为了爱好说走就走 好玩不贵很重要

手机要闻

荣耀Magic6首销第一季度出货量暴涨 超上代两季度之和

家居要闻

光影之间 空间暖意打造生活律动

日本销量周榜:《方舟:生存飞升》首发第9位

亲子要闻

女孩嘴部肿胀似“香肠”般,家长发现后立即带其就医,经检查是虫子咬的

无障碍浏览 进入关怀版