一、實現步驟
- 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;