(求TopN)求出每種愛好中,年齡最大的兩個人(姓名,愛好,年齡)
四個字段的意思:
id,姓名,年齡,愛好
表名topn
字段id, name, age, favors
1,ngxiaoming,45,a-c-d-f
2,huangzitao,36,b-c-d-e
3,huanglei,41,c-d-e
4,liushishi,22,a-d-e
5,liudehua,39,e-f-d
6,liuyifei,35,a-d-e
用到關鍵技術:
虛擬視圖leteral view、explode、窗口函數row_number()
-
需要把favor字段進行拆分,拆成多行一列的值
比如6,liuyifei,35,a-d-e拆成:
6,liuyifei,35,a
6,liuyifei,35,d
6,liuyifei,35,e -
使用explode進行拆分
select explode(split("a-d-e","-"));
無法直接寫sql語句進行favors的拆分,所以需要藉助虛擬視圖
-
藉助虛擬視圖使用CTAS創建一張topn1表
語法:lateral view utdf(表達式) 虛擬表名 as 虛擬表的列名,生成一張虛擬表。utdf函數通常把explode和split結合使用,針對from的表(如這裏是topn表)的每一行進行操作。create table topn1 as select id,name,age,favortable.favor from topn lateral view explode(split(favors,"-")) favortable as favor;
-
求出每種愛好的年齡最大的前2名
分析:(一般既要分組又要排序,就要想到窗口函數)
給topn1表弄一個排名,按愛好進行降序排序,然後選取每種愛好的前2名即可。窗口函數 row_number() 排序,排名相同編號也往後順位
select name,favor,age, row_number() over(partition by favor order by age desc) as index from topn1;
-
求排名前2個記錄
因爲where的執行順序要先於窗口函數,無法直接使用條件index<=2。必須在外面再套一層select。select c.name,c.favor,c.age from ( select name,favor,age,row_number() over(partition by favor order by age desc) as index from topn1) as c where c.index <=2;
窗口函數-排序-區別row_number() 排序,排名相同編號也往後順位
rank() 排序,排名相同編號一樣,跳過空位,比如4後直接到6
dense_rank() 排序,排名相同編號一樣,不跳過空位,比如4後接着到5
當排名一樣的時候,選排名前2,可能是2個人,也可能3個人,所以需要按實際需求選擇用哪個排序函數。