本文出處 MySQL排名函數實現
轉載請說明出處
如今有個需求對全部學生分數進行排名,而且列出名次。剛看到這個需求,我有點懵逼,徹底沒有思路😂,爲何難一點需求,我就不會作呢😔 去網上查詢資料,把全部實現都列出來,所有都要學會。git
建立一個分數表s_scoregithub
CREATE TABLE `s_score` ( `id` int NOT NULL AUTO_INCREMENT, `score` int NOT NULL DEFAULT 0, `name` varchar(20) CHARACTER SET utf8mb4 NULL, PRIMARY KEY (`id`) );
插入數據sql
INSERT INTO `s_score` (`name`, `score`) VALUES ('張三', 80), ('小明', 90), ('小紅', 60), ('李四', 70), ('趙武', 80), ('梁晨', 87), ('小綠', 69), ('威廉', 69), ('大衛', 91), ('王五', 96), ('趙六', 96), ('小五', 80), ('小龍', 88);
在MySQL8.0推出Rank排名函數RANK,徹底支持這種需求,可是必須MySQL8.0 以上版本才支持這個特性。8.0如下的版本有什麼方法實現呢,使用用戶變量,記錄名次。
用戶變量:以"@
"開始,形式爲"@var_name
",以區分用戶變量及列名。它能夠是任何隨機的,複合的標量表達式,只要其中沒有列指定。下面寫一個小例子,展現如何使用用戶變量數據庫
select @a:=1 a,@b:=@a+1 b
執行結果編程
a | b |
---|---|
1 | 2 |
:= 是賦值的意思,與編程語言賦值有點區別。下面開始展現使用簡單SQL實現RANK排名函數效果編程語言
SELECT name,score, @rank:=@rank+1 `rank` from s_score s,(select @rank:=0) q ORDER BY score desc
name | score | rank |
---|---|---|
趙六 | 96 | 1 |
王五 | 96 | 2 |
大衛 | 91 | 3 |
小明 | 90 | 4 |
小龍 | 88 | 5 |
梁晨 | 87 | 6 |
小五 | 80 | 7 |
張三 | 80 | 8 |
趙武 | 80 | 9 |
李四 | 70 | 10 |
威廉 | 69 | 11 |
小綠 | 69 | 12 |
小紅 | 60 | 13 |
如今還有一個問題,出現分數相同,並列排名,名次應該相同。咱們使用一個temp變量來記錄前一個分數值,判斷前面分數是否與當前相等,相等直接返回上一個排名狀況,不然排名+1。函數
select name,score,case when @temp_score=score then @rank when @temp_score:=score then @rank:=@rank+1 END `rank` from s_score s,(select @rank:=0,@temp_score:=NULL) q ORDER BY score desc
name | score | rank |
---|---|---|
趙六 | 96 | 1 |
王五 | 96 | 1 |
大衛 | 91 | 2 |
小明 | 90 | 3 |
小龍 | 88 | 4 |
梁晨 | 87 | 5 |
小五 | 80 | 6 |
張三 | 80 | 6 |
趙武 | 80 | 6 |
李四 | 70 | 7 |
威廉 | 69 | 8 |
小綠 | 69 | 8 |
小紅 | 60 | 9 |
若是出現並列排名,下一個名次將自動跳過,好比出現兩個並列第一,91應該變成第三名了,名次和人數相對應。code
SELECT name,score,rank from ( SELECT name ,score,@rank :=IF( @temp_score = score, @rank, @rank_incr ) `rank`,@rank_incr := @rank_incr + 1, @temp_score := score FROM score s,(SELECT@rank := 0,@temp_rank := NULL,@rank_incr := 1 ) q ORDER BY score DESC) a
name | score | rank |
---|---|---|
趙六 | 96 | 1 |
王五 | 96 | 1 |
大衛 | 91 | 3 |
小明 | 90 | 4 |
小龍 | 88 | 5 |
梁晨 | 87 | 6 |
小五 | 80 | 7 |
張三 | 80 | 7 |
趙武 | 80 | 7 |
李四 | 70 | 10 |
威廉 | 69 | 11 |
小綠 | 69 | 11 |
小紅 | 60 | 13 |
窗口函數的基本語法以下:排序
select 排序函數/聚合函數 over (<partition by ...> 分區字段 order by 排序字段)
注意over 後面有一個空格的,這個語法有點蛋疼,我本身試了十幾回才書寫成功。
根據維基百科解釋:窗口函數容許在當前記錄以前和以後訪問記錄中的數據。窗口函數定義一幀或一列窗口,其中當前行周圍具備給定的長度,並跨窗口中的數據集執行計算。能夠這樣理解,窗口就是數據集合,函數就是計算數據方法。文檔
partiton by是可選的。若是不使用partition by,那麼就是將整張表做爲一個集合,最後使用排序函數獲得的就是每一條記錄根據排序列的排序編號。
排序函數主要有rank()、dense_rank、row_number,他們主要區別:
select name,score, RANK() over (ORDER BY score DESC) `rank`,ROW_NUMBER() over (order by score DESC) `row`, DENSE_RANK()over (ORDER BY score DESC) `dense` from s_score
name | score | rank | row | dense |
---|---|---|---|---|
趙六 | 96 | 1 | 1 | 1 |
王五 | 96 | 1 | 2 | 1 |
大衛 | 91 | 3 | 3 | 2 |
小明 | 90 | 4 | 4 | 3 |
小龍 | 88 | 5 | 5 | 4 |
梁晨 | 87 | 6 | 6 | 5 |
趙武 | 80 | 7 | 7 | 6 |
小五 | 80 | 7 | 8 | 6 |
張三 | 80 | 7 | 9 | 6 |
李四 | 70 | 10 | 10 | 7 |
小綠 | 69 | 11 | 11 | 8 |
威廉 | 69 | 11 | 12 | 8 |
小紅 | 60 | 13 | 13 | 9 |
以上就是排序名次所有實現方式了,還有其餘實現方式,麻煩在評論裏補充一下。
https://cloud.tencent.com/developer/article/1562954
https://www.jianshu.com/p/bb1b72a1623e