在實(shí)際使用Hive的過程中,常常會(huì)涉及到行列轉(zhuǎn)換,細(xì)分的話,有下面4種類型的行列轉(zhuǎn)換,分別是:
- 行轉(zhuǎn)多列
- 多列轉(zhuǎn)行
- 行轉(zhuǎn)單列
- 單列轉(zhuǎn)行
下面我們通過樣例介紹每種行列轉(zhuǎn)換的實(shí)現(xiàn)方法。
樣例表
班級(jí)成績(jī)表:
姓名(name) 學(xué)科(subject) 成績(jī)(score)
A 語文 70
A 數(shù)學(xué) 90
A 英語 80
B 數(shù)學(xué) 95
B 英語 85
B 語文 75
行列轉(zhuǎn)換思路分析及實(shí)現(xiàn)
行轉(zhuǎn)多列
如果需要將上面的樣例表轉(zhuǎn)換為
“姓名 | 語文成績(jī) | 數(shù)學(xué)成績(jī) | 英語成績(jī)”
這樣的格式,那么這就需要用到行轉(zhuǎn)多列。
思路:
涉及到行轉(zhuǎn)成列,肯定是會(huì)按照某一列或者某幾列的值進(jìn)行分組來壓縮行數(shù),所以會(huì)用到group by。
分組之后需要用到聚合函數(shù),由于多列中的每列只關(guān)心自己對(duì)應(yīng)的數(shù)據(jù),所以要使用case語句進(jìn)行選擇,至于聚合函數(shù),只要數(shù)據(jù)能保證唯一性,max、min、avg(數(shù)值類型)等都可以
樣例SQL:
select name,
max(case when subject = '數(shù)學(xué)' then score else null end) math,
max(case when subject='英語' then score else null end) english,
max(case when subject='語文' then score else null end) chinese
from t1
group by name;
多列轉(zhuǎn)行
將上面行轉(zhuǎn)多列的結(jié)果再轉(zhuǎn)回成原始表結(jié)構(gòu)的過程,就是多列轉(zhuǎn)行
思路
列轉(zhuǎn)行,會(huì)涉及到行數(shù)的增加,所以會(huì)用到UDTF,而UDTF只是針對(duì)某一列的,要把這列擴(kuò)展后生成的多行數(shù)據(jù)和源表中的各列拼接在一起,需要用到lateral view語法;
需要將多列里各列的列名(業(yè)務(wù)含義),在新數(shù)據(jù)中當(dāng)做一個(gè)標(biāo)識(shí)列,而與lateral view聯(lián)合使用的explode函數(shù)是支持Map類型的,所以要先將原表里的多列變換成Map類型的一列,然后再用lateral view拆開。
樣例SQL:
select name,subject,score from
(
select name,map('數(shù)學(xué)',math,'英語',english,'語文',chinese) scores
from t2
) tt1
lateral view explode(scores) tt2 as subject,score;
行轉(zhuǎn)單列
將原始表轉(zhuǎn)換為
“姓名 | 所有科目成績(jī)集合 ”
則涉及到行轉(zhuǎn)單列
思路
和行轉(zhuǎn)多列一樣,行數(shù)會(huì)減少,所以需要用到group by,然后轉(zhuǎn)成的是單列,所以需要用到collect_list或者collect_set聚合函數(shù),如果字段類型想要是有分隔符隔開的字符串,再套上一層concat_ws;
上面的方案得出的array或者字符串是亂序的,如果想要進(jìn)行排序,可以使用sort_array函數(shù)。但sort_array只能按字段類型的升序排列(數(shù)值字段自然序,字符串字段字典序);
如果想要自己指定排序規(guī)則,或者排序的不是單列里的這個(gè)字段(比如班級(jí)考試成績(jī)表,所有分?jǐn)?shù)字段里需要根據(jù)學(xué)科進(jìn)行排序,而不是分?jǐn)?shù)高低),則需要使用collect_list加上over子句來實(shí)現(xiàn)。
樣例SQL:
1、成績(jī)不排序
select name,concat_ws(',',collect_list(score))
from t1
group by name;
2、按分?jǐn)?shù)高低排序
select name,concat_ws(',',sort_array(collect_list(score)))
from t1
group by name;
3、按學(xué)科進(jìn)行排序
select name,concat_ws(',',max(a)) from
(
select name,
collect_list(score) over(partition by name order by subject
rows between unbounded preceding and unbounded following) a
from t1
) tt1 group by name;
4、按指定的學(xué)科順序排序
select name,concat_ws(',',max(a)) scores from
(
select name,
collect_list(score) over(partition by name
order by case when subject='語文' then 1
when subject='數(shù)學(xué)' then 2
when subject='英語' then 3 end
rows between unbounded preceding and unbounded following) a
from t1
) tt1 group by name;
單列轉(zhuǎn)行
將上面的結(jié)果轉(zhuǎn)成原始表結(jié)構(gòu),就是單列轉(zhuǎn)行
思路
和多列轉(zhuǎn)行一樣,使用lateral view加explode來轉(zhuǎn)換。但這種方式轉(zhuǎn)換出來會(huì)丟失掉科目字段信息;
如果需要加上科目信息,則需要按照單列里面的順序的業(yè)務(wù)含義,先將單列轉(zhuǎn)成Map類型,將科目加到數(shù)據(jù)里,然后再使用lateral view轉(zhuǎn)換。
樣例SQL:
1、無科目字段文章來源:http://www.zghlxwxcb.cn/news/detail-558309.html
select name,score from
(
select name,split(scores,',') s from t3
) tt1
lateral view explode(s) tt2 as score;
2、有科目字段文章來源地址http://www.zghlxwxcb.cn/news/detail-558309.html
select name,subject,score from
(
select name,map('語文',s[0],'數(shù)學(xué)',s[1],'英語',s[2]) ss from
(
select name,split(scores,',') s from t3
) tt1
) ttt1
lateral view explode(ss) ttt2 as subject,score;
到了這里,關(guān)于Hive的行列轉(zhuǎn)換(行轉(zhuǎn)多列、多列轉(zhuǎn)行、行轉(zhuǎn)單列、單列轉(zhuǎn)行)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!