這個函數大多數人都接觸過,將一行數據轉換成列數據,能夠用於array和map類型的數據。程序員
用於array的語法以下:sql
select explode(arraycol) as newcol from tablename;
用於map的語法以下:express
select explode(mapcol) as (keyname,valuename) from tablename;
注意:這兩個值須要在as以後用括號括起來而後以逗號分隔。函數
以上爲explode()函數的用法,此函數存在侷限性:測試
lateral view是Hive中提供給UDTF的結合,它能夠解決UDTF不能添加額外的select列的問題。.net
lateral view其實就是用來和想相似explode這種UDTF函數聯用的,lateral view會將UDTF生成的結果放到一個虛擬表中,而後這個虛擬表會和輸入行進行join來達到鏈接UDTF外的select字段的目的。code
lateral view udtf(expression) tableAlias as columnAlias (,columnAlias)*
from basetable (lateral view)*
from basetable (lateral view outer)*
它比格式二隻是多了一個outer,這個outer的做用是在UDTF轉換列的時候將其中的空也給展現出來,UDTF默認是忽略輸出空的,加上outer以後,會將空也輸出,顯示爲NULL。這個功能是在Hive0.12是開始支持的。orm
下面來講一個需求案例。blog
有一張hive表,分別是學生姓名name(string),學生成績score(map<string,string>),成績列中key是學科名稱,value是對應學科分數,請用一個hql求一下每一個學生成績最好的學科及分數、最差的學科及分數、平均分數。get
表數據以下:
zhangsan|Chinese:80,Math:60,English:90 lisi|Chinese:90,Math:80,English:70 wangwu|Chinese:88,Math:90,English:96 maliu|Chinese:99,Math:65,English:60
下面來作一下準備工做,建立表,並將數據導入表中,操做以下:
建立表:
create table student_score(name string,score map<String,string>) row format delimited fields terminated by '|' collection items terminated by ',' map keys terminated by ':';
導入數據:
load data local inpath '/home/test/score' overwrite into table student_score;
檢查一下數據,以下圖:
確認數據導入沒有問題。
首先要處理這個表中的數據,本人第一想法是想找一下Hive有沒有內置的操做map複雜類型的函數,惋惜看了一遍,沒有找到,這個思路只能放棄。
第二想法,是將map中的數據轉換成一個虛擬表,而後與name字段關聯,這樣造成一張可操做的虛擬表。在查閱了資料以後,看到explode()函數能夠作這個事情,首先寫了一條語句:
select explode(score) from student_score; select explode(score) as (key,value) from student_score;
結果:
此函數驗證了它倒是能夠作到分離map的功能,將行轉爲列,難麼既然行轉了列,那麼只須要將name字段關聯上,就能夠進行統計操做了。
惋惜的是,explode函數怎麼使用,都關聯不了name字段。
既然Hive有這些東西,確定可以作到關聯其餘字段的,這是本人做爲一個程序員的信念,若是沒有的話,這個功能作出來就是雞肋了,只有關聯了其餘能夠肯定其爲惟一消息的字段,這樣的功能才又意義。
又在網上查詢到,常常和explode函數和用的就是lateral view函數,那麼這兩個結合就能作到關聯其餘字段。寫法以下:
select name,key,value from student_score lateral view explode(score) scntable as key,value;
結果以下:
看到上面的數據,就是咱們想要的結果,產生了這樣一個虛擬表以後,全部的工做都變的簡單了起來。
從上面兩條語句能夠看出,explode在select句中和在from子句中給虛擬字段命名的格式稍微有些差異,select句中須要加括號,from子句中不須要括號。
以上是這個需求的難點,其餘的就不在作過多的說明。
下面將結果拋出來,這可能不是最優的,可是是一種方式:
select sname,gk,gv,bk,bv,av from ( select * from ( select C.name as sname,C.key as gk,C.value as gv from ( select name,max(value) as gv from ( select name,key,value from student_score lateral view explode(score) scnTable as key,value) as A group by name) as B left join (select name,key,value from student_score lateral view explode(score) scnTable as key,value) as C on B.name=C.name and B.gv=C.value) as GG left join (select C.name as bname,C.key as bk,C.value as bv from (select name,min(value) as bv from ( select name,key,value from student_score lateral view explode(score) scnTable as key,value) as A group by name) as B left join (select name,key,value from student_score lateral view explode(score) snTable as key,value) as C on B.name=C.name and B.bv=C.value) as BB on GG.sname=BB.bname) as SS left join (select name as aname,avg(value) as av from ( select name,key,value from student_score lateral view explode(score) scnTable as key,value) as A group by name) AA on SS.sname=AA.aname
結果以下:
列名依次爲:姓名、最好成績的科目、分數、最差成績的科目、分數、平均分
這裏須要說一些,Hive中的基本數據類型,string類型應該是使用的自動轉換機制,轉換爲了int,這裏將score map<string,string>聲明爲score map<string,int>也是能夠的。
本人的hive環境爲1.1.0CDH5版,此時將上面的數據作一下修改,來測試一下outer的做用,數據以下:
zhangsan|Chinese:80,Math:60,English:90 lisi|Chinese:90,Math:80,English:70 wangwu|Chinese:88,Math:90,English:96 maliu|Chinese:99,Math:65,English:
將maliu的英語成績給去掉,而後導入到表中。
在執行如下語句:
select explode(score) from student_score;
結果以下:
能夠看到最後一個English的成績沒有顯示任何東西,也就是被UDTF給忽略了。
下面使用lateral view看一下:
select name,key,value from student_score lateral view explode(score) scntable as key,value;
結果以下:
最後加上outer在試一下:
select name,key,value from student_score lateral view outer explode(score) scntable as key,value;
結果以下:
結果和沒加outer是同樣的,這就又是一個新的問題了,outer是否只對arrary類型的有效,對map類型無效呢?
本人又將arrary類型進行了測試,和map一樣,都是什麼都不顯示,只是將沒有的一列作了聯表匹配。
這個問題有待研究。
上一篇:Hive語法:union
下一篇: