hive中有三個與分組排序相關的分析函數(我起初也認為是窗口函數,后來看到手冊里是把他們划到了Analytics functions下),row_number、rank、dense_rank,我一直傻傻的分不大清它們的區別,特地總結一下。
現在模擬一個場景,有一個比較時髦的學校決定借助大數據技術來提高教學質量,其中就有一張表存放了全校每個學生的考試成績,按照學期進行分區,創建這張表:
create table t_score ( class string, name string, score int ) partitioned by (term string);
插入一些測試數據:
-- 注意這里為了做實驗方便使用insert...values的形式,會產生臨時表
insert into t_score partition (term="201702")
values
("一班", "小黑", 80),
("一班", "小白", 90),
("一班", "小赤", 100),
("二班", "小橙", 80),
("二班", "小紅", 90),
("二班", "小綠", 100),
("三班", "小青", 90),
("三班", "小藍", 100),
("三班", "小紫", 100);
現在校長想知道在2017年下學期的考試中每個班級的排名情況:
select *, rank() over (partition by class order by score desc) from t_score where term="201702";
下面是查詢結果:
但是仔細看下查詢結果,發現有些不對勁的地方,三班的排名出現了兩個並列第一,然后緊接着就是第三名,沒有第二名了,按照我們一般的想法,如果有並列的話那么后面的就會排名提前,dense_rank可以實現這個效果:
select *, dense_rank() over (partition by class order by score desc) from t_score where term="201702";
跟預期一致,三班的兩個並列第一,然后緊接着就是第二名。
將rank()和dense_rank()的結果放在一起對比一下加深理解:
dense,意思是稠密的,稠密意味着生成的排名序列中沒有空隙(連續的),而rank()生成的排名序列中可能有空隙(可能是不連續的)。
但是這時候校長不高興了,他不喜歡這種並列的排名方式,他說要重新制定排名規則:
1. 首先按照成績排序 2. 成績相同的不要並列,而是再按照姓名排序,姓氏靠后的認倒霉吧 3. 對於成績和姓名都完全相同的情況,校長大人沒有指定就假裝不存在這種情況好啦
沒辦法,校長最大,只能再改下我們的sql,因為rank在生成排名序列的時候都會出現並列的情況,稀的稠的都不行啊,所以不能采用rank這種方式了,不過沒事我們還有招,有一個函數叫做row_number,它不考慮並列的情況,就是單純的排序,按照順序挨個的發號碼:
select *, row_number() over (partition by class order by score desc, name) from t_score where term="201702";
效果大概是這樣:
沒有出現並列的情況,可以交差了。
總結一下:
rank / dense_rank / row_number的語法都是一樣的,不同的只是幾個特性:
1. rank / dense_rank都考慮了並列的情況,所以序號可能不唯一,rank在出現並列之后會不連續,而dense_rank是連續的
2. row_number不考慮並列的情況,所以序號是唯一的,並且也不會出現不連續
.
