grouping sets 用法
在Hive中,会出现对同一个数据表进行不同粒度的汇总,这时可以有两种方案:
用多个sql,对不同粒度使用不同的 group by 方法。
用1个sql,使用 grouping sets 方法一次性得到所有粒度的汇总。
以测试数据表 tmp_student 为例:
1、生成测试数据
在 hive 环境中创建临时表:
create table tmp.tmp_student
(
name string,
class int,
sex string,
score int
)
row format delimited fields terminated by '|';
然后加载测试数据:
load data local inpath 'text.txt' into table tmp_student;
其中,text.txt 内容如下:
A|3|男|45
B|3|女|55
C|2|女|74
D|3|男|90
E|1|男|80
F|2|女|92
G|1|女|95
H|1|男|95
I|3|女|99
J|3|男|99
查看是否加载成功:
hive> select * from tmp_student;
OK
A 3 男 45
B 3 女 55
C 2 女 74
D 3 男 90
E 1 男 80
F 2 女 92
G 1 女 95
H 1 男 95
I 3 女 99
J 3 男 99
Time taken: 0.377 seconds, Fetched: 10 row(s)
2、grouping sets示例
数据表有4个字段:姓名、班级、性别、分数。
如果我想按照以下3个粒度汇总:
1、每个班级的平均分数
2、每个性别的平均分数
3、每个班级下不同性别的平均分数
则使用多个sql分别汇总的方案为:
select class, avg(score) from tmp.tmp_student group by class;
select sex, avg(score) from tmp.tmp_student group by sex;
select class, sex, avg(score) from tmp.tmp_student group by class, sex;
而使用1个sql使用grouping sets的方案为:
select
grouping__id, -- 内置变量,只要使用grouping sets就可以调用
class,
sex,
avg(score) as avg_score
from
tmp.tmp_student
group by
class,
sex
grouping sets(
class,
sex,
(class, sex)
)
结果为:
在这里插入图片描述
可以看到,使用 grouping sets 同时汇总出了 3 种不同粒度的平均分数。
注意:
1、grouping sets 只能用于 group by 之后。
2、grouping sets 中可以包含多种粒度,粒度之间用逗号连接。
3、grouping sets 中的所有字段,都必须出现在 group by 中,相当于 group by 后面的字段是最细粒度。
4、如果 select 中的字段,没有包含在某个 grouping set 中,那么这个粒度下的这个字段值为 NULL。
4、不同的粒度,可以使用内置变量 grouping__id 进行区分。
grouping_id计算方法
grouping sets 中的每一种粒度,都对应唯一的 grouping__id 值,其计算公式与 group by 的顺序、当前粒度的字段有关。
具体计算方法如下:
将 group by 的所有字段 倒序 排列。
对于每个字段,如果该字段出现在了当前粒度中,则该字段位置赋值为1,否则为0。
这样就形成了一个二进制数,这个二进制数转为十进制,即为当前粒度对应的 grouping__id。
以上述对 tmp_student 的3种粒度的统计结果为例:
1、group by 的所有字段倒序排列为:sex class
2、对于 3 种 grouping sets,分别对应的二进制数为:
序号 grouping set 给倒序排列的字段(sex class)赋值 对应的十进制(grouping__id 的值)
1 class 01 1
2 sex 10 2
3 class,sex 11 3