MySQL - 排名實現

一、實現步驟

  • 1、實現自然排名
SELECT 
    id, name, score, 
    -- 排名變量每次+1,實現自然排名
    @curr_row_rank := @curr_row_rank + 1 AS rank 
FROM 
    scores, 
    (SELECT 
        -- 定義一個變量,每條記錄+1,用於標識自然的排名
        @curr_row_rank := 0
    ) vars
ORDER BY
    -- 排序必須存在
    score DESC

  • 2、實現並列排名
SELECT 
    id, name, score,
    -- CASE 只返回第一個條件成立的WHEN所對應THEN的值    
    CASE
        -- 對比上條記錄和當前記錄的分數,如分數相等,則排名不變,返回和上條記錄相同的排名
        WHEN @pref_row_score  = score THEN @curr_row_rank
        -- 如果上一個WHEN沒有進入,即分數不等,則將當前分數賦值給標識上條記錄分數的變量,同時將排名+1,返回+1後的排名
        WHEN @pref_row_score := score THEN @curr_row_rank := @curr_row_rank + 1
        -- 處理分數爲0沒有排名的問題(當WHEN中爲變量賦值爲0和Null時,WHEN不成立,不進入THEN,即上一個WHEN/THEN不執行)
        WHEN @pref_row_score  = 0     THEN @curr_row_rank := @curr_row_rank + 1  
    END AS rank,
    -- 將這個變量作爲排名(替代CASE返回值排名),可以在添加了上一個WHEN時兼容分數爲Null的情況,將0分和Null並列爲最後一名
    @curr_row_rank AS curr_row_rank,
    @pref_row_score AS pref_row_score
FROM 
    scores, 
    
    (SELECT 
        -- 定義一個變量,在當前記錄分數和上條記錄分數不同時+1,用於標識排名
        @curr_row_rank := 0, 
        -- 定義一個變量,保存上一條記錄的分數,用於當前記錄與上條記錄對比
        @pref_row_score := NULL
    ) vars
ORDER BY
    -- 排序必須存在
    score DESC

  • 3、實現並列順延
SELECT 
    id, name, score,
    -- 每條記錄自增一次,用於並列之後的記錄獲取跳過佔用的名次
    @incr_row_rank := @incr_row_rank + 1 AS incr_row_rank, 
    -- CASE 只返回第一個條件成立的WHEN所對應THEN的值    
    CASE
        -- 對比上條記錄和當前記錄的分數,如分數相等,則排名不變,返回和上條記錄相同的排名
        WHEN @pref_row_score  = score THEN @curr_row_rank
        -- 如果上一個WHEN沒有進入,即分數不等,則將當前記錄分數賦值給上條記錄分數的變量(用於下條記錄比較),同時將排名+1,返回+1後的排名
        WHEN @pref_row_score := score THEN @curr_row_rank := @incr_row_rank
        -- 處理分數爲0沒有排名的問題(當WHEN中爲變量賦值爲0和Null時,WHEN不成立,不進入THEN,即上一個WHEN/THEN不執行)
        WHEN @pref_row_score  = 0     THEN @curr_row_rank := @incr_row_rank
    END AS rank,
    -- 將這個變量作爲排名(替代返CASE回值排名),可以在添加了上一個WHEN時兼容分數爲Null的情況,將0分和Null並列爲最後一名
    @curr_row_rank AS curr_row_rank,
    @pref_row_score AS pref_row_score
FROM 
    scores, 
    (SELECT 
        -- 定義一個變量,在當前記錄分數和上條記錄分數相同時,賦值上條記錄的名次,否則賦值自然排名的名次(跳過並列佔用)
        @curr_row_rank := 0, 
        -- 定義一個變量,保存上一條記錄的分數,用於當前記錄與上條記錄對比
        @pref_row_score := NULL,
        -- 定義一個變量,保存自增的自然排序的排名,用於並列之後的記錄獲取跳過並列佔用的排名(初始爲0,爲當前記錄服務)
        @incr_row_rank := 0
    ) vars
ORDER BY
    -- 排序必須存在
    score DESC

二、其他實現

  • 1、IF函數方式
  •     1.1、並列連續
SELECT 
    id, name, score,
    -- IF(exp1, exp2, exp3):當exp1成立即true時,返回exp2的值,當exp1不成立即false是,返回exp2的值
    -- 如果當前記錄的分數和上條記錄的分數相同,則返回和上條記錄相同的排名,否則返回自增的排名(並列之後跳過佔用的名次)
    @curr_row_rank  := IF(@pref_row_score = score, @curr_row_rank, @curr_row_rank := @curr_row_rank + 1) AS rank,
    -- 將當前記錄的分數賦值爲上條記錄的分數,用於下條記錄比較
    @pref_row_score := score AS pref_row_score
    -- 兼容0分,不兼容Null分
FROM 
    scores, 
    
    (SELECT 
        -- 定義一個變量,在當前記錄分數和上條記錄分數不同時+1,用於標識排名
        @curr_row_rank  := 0, 
        -- 定義一個變量,保存上一條記錄的分數,用於當前記錄與上條記錄對比
        @pref_row_score := NULL
    ) vars
ORDER BY
    -- 排序必須存在
    score DESC

  •     1.2、並列順延
SELECT
    id, name, score, 
    -- IF(exp1, exp2, exp3):當exp1成立即true時,返回exp2的值,當exp1不成立即false時,返回exp2的值
    -- 如果當前記錄的分數和上條記錄的分數相同,則返回和上條記錄相同的排名,否則返回自增的排名(並列之後跳過佔用的名次)
    @curr_row_rank  := IF ( @pref_row_score = score, @curr_row_rank, @incr_row_rank ) AS rank,
    -- 每條記錄自增一次,用於並列之後的記錄迴歸跳過佔用的名次
    @incr_row_rank  := @incr_row_rank + 1 AS incr_row_rank,
    -- 將當前記錄的分數賦值爲上條記錄的分數,用於下條記錄比較
    @pref_row_score := score AS pref_row_score
    -- 兼容0分,不兼容Null分
FROM
    scores, 
    (SELECT 
        -- 定義一個變量,在當前記錄分數和上條記錄分數相同時,賦值上條記錄的名次,否則賦值自然排名的名次(跳過並列佔用)
        @curr_row_rank  := 0, 
        -- 定義一個變量,保存上一條記錄的分數,用於當前記錄分數與上條記錄分數對比
        @pref_row_score := NULL, 
        -- 定義一個變量,保存自增的自然排序的排名,用於並列之後的記錄獲取跳過並列佔用的排名(初始爲1,爲下條記錄服務)
        @incr_row_rank  := 1 
    ) vars
ORDER BY
    -- 排序必須存在
    score DESC

  • 2、子查詢方式
  •     2.1、並列連續
SELECT
    id, name, score,
    -- 大於等於此分數的不重複的個數
    ( SELECT count( distinct score ) FROM scores WHERE score >= s.score ) AS rank 
    -- 不兼容Null分,排名爲0名
FROM
    scores s 
ORDER BY
    score DESC;

  •     2.2、並列順延
SELECT
    id, name, score,
    -- 大於此分數的不重複的個數加一
    ( SELECT count(score) + 1 FROM scores WHERE score > s.score ) AS rank 
    -- 不兼容Null分,排名爲1名
FROM
    scores s 
ORDER BY
    score DESC;

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章