行转列:
行转列其实就是把多行的数据连接在一起,放到一列里面,所用的函数是连接函数
concat(xx,xx) 连接到一起
concat_ws(separator, str1, str2,…) 这个多了一个separator分隔符,就是两个字符串之间用什么隔开
collect_set() 这个表示的是把某个字段进行去重汇总,产生一个array类型的字段
比如下面表的数据
name constellation blood_type
孙悟空 白羊座 A
老王 射手座 A
宋宋 白羊座 B
猪八戒 白羊座 A
凤姐 射手座 A
把星座和血型一类的归为一起:
射手座,A 老王|凤姐
白羊座,A 孙悟空|猪八戒
白羊座,B 宋宋
首先我们可以先把 血型和星座连接到一起:
select concat(constellation,',',blood_type) as temp,name from person_info;
或者
select concat_ws(',',constellation,blood_type) as temp,name from person_info;
结果:
+---------------+-------+--+
| temp | name |
+---------------+-------+--+
| 白羊座,A | 孙悟空 |
| 射手座,A | 老王 |
| 白羊座,B | 宋宋 |
| 白羊座,A | 猪八戒 |
| 射手座,A | 凤姐 |
接下来就是要对temp 进行分组合并,用到collect_set() temp转为一个数组:
select t.temp,collect_set(name) from (
select concat_ws(',',constellation,blood_type) as temp,name
from person_info
)t group by t.temp;
结果如下:
+---------------+----------------+--+
| t.temp | _c1 |
+---------------+----------------+--+
| 射手座,A | ["老王","凤姐"] |
| 白羊座,A | ["孙悟空","猪八戒"] |
| 白羊座,B | ["宋宋"] |
+---------------+----------------+--+
之后再把数组拆分就好了:
select t.temp,concat_ws('|',collect_set(name)) from (
select concat_ws(',',constellation,blood_type) as temp,name
from person_info
)t group by t.temp;
结果:
+---------------+----------+--+
| t.temp | _c1 |
+---------------+----------+--+
| 射手座,A | 老王|凤姐 |
| 白羊座,A | 孙悟空|猪八戒 |
| 白羊座,B | 宋宋 |
+---------------+----------+--+
列转行:
列传行其实就是将一列中的数据拆分为多行
需要用的函数是explode() 将一列中的array,map等拆分为多行,这个通常与lateral view一起连用,lateral view可以将explode 打散的数据和其他列连起来形成虚拟表,lateral view主要解决在select使用UTF做查询过程中,查询只能包含单个UDTF,不能包含其他字段、以及多个UDTF的问题, 有点难理解,看下面的例子:
数据:
《疑犯追踪》 悬疑,动作,科幻,剧情
《Lie to me》 悬疑,警匪,动作,心理,剧情
《战狼2》 战争,动作,灾难
需求是将结果展开如下:
《疑犯追踪》 悬疑
《疑犯追踪》 动作
《疑犯追踪》 科幻
《疑犯追踪》 剧情
《Lie to me》 悬疑
《Lie to me》 警匪
《Lie to me》 动作
《Lie to me》 心理
《Lie to me》 剧情
《战狼2》 战争
《战狼2》 动作
《战狼2》 灾难
首先创建表,并将数据导入到表中,创建表语句如下:
create table movie_info(movie string, category array<string>)
row format delimited fields terminated by "\t"
collection items terminated by ",";
之后我们就可以将数据打散了:
select explode(category) from movie_info;
结果如下:
+------+--+
| col |
+------+--+
| 悬疑 |
| 动作 |
| 科幻 |
| 剧情 |
| 悬疑 |
| 警匪 |
| 动作 |
| 心理 |
| 剧情 |
| 战争 |
| 动作 |
| 灾难 |
+------+--+
到这看起来很简单,直接加上电影名,不就可以了么:
select movie,explode(category) from movie_info;
但是很遗憾的是报错了:
UDTF's are not supported outside the SELECT clause, nor nested in expressions
所以这个时候就用到lateral view,他可以将其转为一张虚拟的表并和前面的数据结合
select movie,category_name from movie_info lateral view explode(category) table_tmp
as category_name;
结果:
+--------------+----------------+--+
| movie | category_name |
+--------------+----------------+--+
| 《疑犯追踪》 | 悬疑 |
| 《疑犯追踪》 | 动作 |
| 《疑犯追踪》 | 科幻 |
| 《疑犯追踪》 | 剧情 |
| 《Lie to me》 | 悬疑 |
| 《Lie to me》 | 警匪 |
| 《Lie to me》 | 动作 |
| 《Lie to me》 | 心理 |
| 《Lie to me》 | 剧情 |
| 《战狼2》 | 战争 |
| 《战狼2》 | 动作 |
| 《战狼2》 | 灾难 |
+--------------+----------------+--+
如果导入的数据格式不是array,只是一个字符串的话,也可以用split 进行切分,之后在打散也是可以的:
select movie, category_name from movie_info2 lateral view explode(split(category,',')) tab
as category_name;