MySQL排名函數實現

本文出處 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

使用SQL窗口函數

窗口函數的基本語法以下:排序

select 排序函數/聚合函數 over (<partition by ...> 分區字段 order by 排序字段)

注意over 後面有一個空格的,這個語法有點蛋疼,我本身試了十幾回才書寫成功。
根據維基百科解釋:窗口函數容許在當前記錄以前和以後訪問記錄中的數據。窗口函數定義一或一列窗口,其中當前行周圍具備給定的長度,並跨窗口中的數據集執行計算。能夠這樣理解,窗口就是數據集合,函數就是計算數據方法。文檔

partiton by是可選的。若是不使用partition by,那麼就是將整張表做爲一個集合,最後使用排序函數獲得的就是每一條記錄根據排序列的排序編號。
排序函數主要有rank()、dense_rank、row_number,他們主要區別:

  • 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

相關文章
相關標籤/搜索