hive:常用函数(case when,collect_list/set,lateral view explode)

1.case when

原始数据如下:
在这里插入图片描述
要求:统计各部门每个性别有多少人
使用传统的group by能达到上述要求:

select dept_id,sex,count(*) from emp_sex
group by dept_id,sex;

在这里插入图片描述
但如果查询的结果以dept_id和两个性别为列,那么group by就不行了,这时可以使用case when:

select dept_id,
sum(case sex when '男' then 1 else 0 end) male,
sum(case sex when '女' then 1 else 0 end) female
from emp_sex
group by dept_id;

在这里插入图片描述

2.collect_list/set(行转列)

原始数据如下:
在这里插入图片描述
要求:将星座和血型相同的人放到一起,结果如下所示:
在这里插入图片描述
思路:

  • step1:
    先把问题简化,如果不是求相同星座、血型的人的名字,而是求人数,那么就和上例一样,使用group by就可以做到:
select constellation,blood_type,count(*) total
from person_info
group by constellation,blood_type;

在这里插入图片描述

  • step2:
    现在考虑把前两列合并起来:使用concat可以做到:
select concat(constellation,',',blood_type) group_,count(*) total
from person_info
group by constellation,blood_type;

在这里插入图片描述

  • step3:
    最后,只需要把人数换成姓名就可以,这里我们可以使用collect_list或collect_set实现,collect_list(xxx)将同一组里面的xxx聚合成一个数组(不去重),collect_set将同一组的xxx聚合成一个数组(去重)
select concat(constellation,',',blood_type) group_,collect_set(name) name_list
from person_info
group by constellation,blood_type;

在这里插入图片描述

  • step4:
    可以看到,现在呈现出来的name还是一个数组,和我们最终想要的结果还有些许不同,我们最终想把多个名字以一个字符串的形式展现出来,使用concat_ws可以实现,concat_ws将数组里面的内容用指定分隔符连接起来
select concat(constellation,',',blood_type) group_,
concat_ws(',',collect_set(name)) name_list
from person_info
group by constellation,blood_type;

在这里插入图片描述

3.explode(列转行)

原始数据如下:
在这里插入图片描述
要求:将每部电影的多个分类切分开,结果如下所示:

在这里插入图片描述
思路:

  • step1:
    原本的category是一个字符串,现在要把它切分开,使用split函数可以实现
select split(category,',') cate_split from movie_info ;

在这里插入图片描述

  • step2:
    经过split后,每一行的cate_split都是一个array,现在要把array中的每个元素取出来单独成行,explode函数可以实现,explode函数可以将一个array或者map展开,其中explode(array)使得结果中将array列表里的每个元素生成一行;explode(map)使得结果中将map里的每一对元素作为一行,key为一列,value为一列。
select explode(split(category,',')) cate_split from movie_info;

在这里插入图片描述

  • step3:
    与各自的电影名字对应起来,如果直接select会报错:
    在这里插入图片描述这是因为explode是一个udtf函数,即一个输入,对应多个输出;那么一个电影名字,就会对应多个电影种类,这样是不能直接匹配的,使用lateral view来解决该问题:
select
    m.movie,
    cate_view.cate
from
    movie_info m
lateral view 
explode(split(category, ",")) cate_view as cate ;

在这里插入图片描述
lateral view 生成一个视图(也就是生成一张虚拟表),cate_view是生成的这个view的名字,cate是这个列的列名。
拓展练习: explode炸开map类型的数据
原始数据:
在这里插入图片描述
在这里插入图片描述
要求:求每个人的孩子及孩子的年龄

select explode(children) from test;

在这里插入图片描述

select t.name father_name,child_info.child_name,child_info.child_age
from test t
lateral view
explode(children) child_info as child_name,child_age;

在这里插入图片描述

4.行列转换结合

上述电影数据,求每个电影种类对应哪些电影

  • step1:
    先用explode把每部电影对应的多个种类炸开
select
    m.movie,
    cate_view.cate
from
    movie_info m
lateral view 
explode(split(category, ",")) cate_view as cate ;

在这里插入图片描述

  • step2:
    然后使用group by和collect_set把相同种类的电影聚集到一起
select cate,concat_ws('~',collect_set(movie)) movie_list
from (
select
    m.movie,
    cate_view.cate
from
    movie_info m
lateral view 
explode(split(category, ",")) cate_view as cate
) my_table
group by cate;

在这里插入图片描述