1. 程式人生 > >hive之經典sql面試題

hive之經典sql面試題

Hive sql面試

select store,count(distinct uid) as uv from Visit group by store;

select * from Users order by age desc, total;

考點:列轉行

select  stage_someone, count(distinct UID)  from  LifeStage  lateral  view  explode(split(stage,','))  LifeStage_tmp  as stage_someone  group  by  stage_someone;

select UID,concat_ws(',',collect_set(stage)) as stages from LifeStage group by UID;

考點:行轉列

explode與lateral view在關係型資料庫中本身是不該出現的,因為他的出現本身就是在操作不滿足第一正規化的資料(每個屬性都不可再分),
本身已經違背了資料庫的設計原理(不論是業務系統還是資料倉庫系統),不過大資料技術普及後,很多類似pv,uv的資料,在業務系統中是存貯在非關係型資料庫中,
用json儲存的概率比較大,直接匯入hive為基礎的數倉系統中,就需要經過ETL過程解析這類資料,explode與lateral view在這種場景下大顯身手。


explode作用是處理map結構的欄位,使用案例如下(hive自帶map,struct,array欄位型別,但是需要先定義好泛型,所以在此案例不使用):
建表語句:
drop table explode_lateral_view;
create table explode_lateral_view
(`area` string,
`goods_id` string,
`sale_info` string)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY '|'
STORED AS textfile;


匯入資料:
a:shandong,b:beijing,c:hebei|1,2,3,4,5,6,7,8,9|[{"source":"7fresh","monthSales":4900,"userCount":1900,"score":"9.9"},{"source":"jd","monthSales":2090,"userCount":78981,"score":"9.8"},{"source":"jdmart","monthSales":6987,"userCount":1600,"score":"9.0"}]
表內資料如下

explode的使用:
我們只拆解array欄位,語句為select explode(split(goods_id,',')) as goods_id from explode_lateral_view;
結果如下

拆解map欄位,語句為select explode(split(area,',')) as area from explode_lateral_view;

拆解json欄位

這個時候要配合一下get_json_object

我們想獲取所有的monthSales,第一步我們先把這個欄位拆成list,並且拆成行展示:
select explode(split(regexp_replace(regexp_replace(sale_info,'\\[\\{',''),'}]',''),'},\\{')) as  sale_info from explode_lateral_view;

然後我們想用get_json_object來獲取key為monthSales的資料:
select get_json_object(explode(split(regexp_replace(regexp_replace(sale_info,'\\[\\{',''),'}]',''),'},\\{')),'$.monthSales') as  sale_info from explode_lateral_view;
然後掛了FAILED: SemanticException [Error 10081]: UDTF's are not supported outside the SELECT clause, nor nested in expressions
UDTF explode不能寫在別的函式內
如果你這麼寫,想查兩個欄位,select explode(split(area,',')) as area,good_id from explode_lateral_view;
會報錯FAILED: SemanticException 1:40 Only a single expression in the SELECT clause is supported with UDTF's. Error encountered near token 'good_id'
使用UDTF的時候,只支援一個欄位,這時候就需要LATERAL VIEW出場了

LATERAL VIEW的使用:
側檢視的意義是配合explode(或者其他的UDTF),一個語句生成把單行資料拆解成多行後的資料結果集。
select goods_id2,sale_info from explode_lateral_view LATERAL VIEW explode(split(goods_id,','))goods as goods_id2;

其中LATERAL VIEW explode(split(goods_id,','))goods相當於一個虛擬表,與原表explode_lateral_view笛卡爾積關聯。
也可以多重使用
select goods_id2,sale_info,area2
from explode_lateral_view 
LATERAL VIEW explode(split(goods_id,','))goods as goods_id2 
LATERAL VIEW explode(split(area,','))area as area2;
也是三個表笛卡爾積的結果

現在我們解決一下上面的問題,從sale_info欄位中找出所有的monthSales並且行展示
select get_json_object(concat('{',sale_info_r,'}'),'$.monthSales') as monthSales from explode_lateral_view 
LATERAL VIEW explode(split(regexp_replace(regexp_replace(sale_info,'\\[\\{',''),'}]',''),'},\\{'))sale_info as sale_info_r;


最終,我們可以通過下面的句子,把這個json格式的一行資料,完全轉換成二維表的方式展現

select get_json_object(concat('{',sale_info_1,'}'),'$.source') as source,
     get_json_object(concat('{',sale_info_1,'}'),'$.monthSales') as monthSales,
     get_json_object(concat('{',sale_info_1,'}'),'$.userCount') as monthSales,
     get_json_object(concat('{',sale_info_1,'}'),'$.score') as monthSales
  from explode_lateral_view 

LATERAL VIEW explode(split(regexp_replace(regexp_replace(sale_info,'\\[\\{',''),'}]',''),'},\\{'))sale_info as sale_info_1;