MySql並列排名


業務背景

數據排名是很常用的功能,簡單的排名功能可以根據order by來實現,但是如果數據一樣,排名應該並列的時候,order by雖然是排序的,但是名次卻不是並列的。

我們先通過order by演示一下。

CREATE TABLE `user_score` (
   `user_id` INT(11) NOT NULL AUTO_INCREMENT COMMENT '用戶id',
   `score` TINYINT(3) UNSIGNED NOT NULL COMMENT '得分',
   PRIMARY KEY (`user_id`)
 ) ENGINE=INNODB DEFAULT CHARSET=utf8 COMMENT='用戶成績表'

插入數據

INSERT INTO user_score (score)
VALUES
(95),
(94),
(97),
(95),
(96),
(96),
(99),
(98);

通過order by 排名

 select * from user_score order by score desc;

可以看出,通過order by的結果雖然是有序的,但是不是真正的名次,此時如果要得到名次只有通過業務代碼中去排序得到1,2,3這樣的。

基本思路

我們通過order by可以得到排序后的結果,不過這個結果不代表名次,我們應該再進行一次遍歷來得到最終的名次。

這個遍歷的過程當然可以放到業務上去做,不過也可以通過sql直接就生成的。
思路也是一樣的,先order by獲取到了有序的數據,然后通過一個變量來計算真正的名次。

簡單的排名

SELECT u.user_id, u.score, @rank := @rank + 1 
FROM 
(SELECT * FROM user_score ORDER BY score DESC) u, (SELECT @rank := 0) r;

 

 

 這里我先通過order by得到了有序的結果,然后定義了一個變量@rank並賦值為0。 
再次通過SELECT 語句查詢排序后的結果,每一條數據結果都加變量@rank++,這樣就有了一個不區分並列情況的名次了。

並列排名

並列排名分為兩種情況,一種是並列了就占位位置了,比如名次是:1,2,2,4… 因為有兩個第二名,所以就占了第三名的位置。另一種就是並列了不占位置,名次就是:1,2,3,4…

並列但不占位

再簡單排名的基礎上,多創建一個變量,用來記錄上一個人的分數,然后通過比較來判斷名次是否需要增加

SELECT u.user_id, u.score, 
 CASE 
   WHEN @last_score = u.score
     THEN @rank 
   WHEN @last_score := u.score 
     THEN @rank := @rank + 1    
  END AS rank    
FROM 
(SELECT * FROM user_score ORDER BY score DESC) u, (SELECT @rank := 0, @last_score := NULL) r;

 

 

 

並列要占位

將簡單排名和不占位的並列排名綜合一下就可以得到並列要占位的排名了。 
按照並列且占位的規則來排名,那么96分應該是第四名,95分是第6名。 
我們觀察之前兩次查詢的結果,可以發現,當分數和上一次一樣的時候取第一個分數的排名,當分數不一樣的時候,取簡單排名的名次。

SELECT t.user_id, t.score, t.rank 
FROM 
  (SELECT u.user_id, u.score, @rank := @rank + 1, 
    @last_rank := CASE 
      WHEN @last_score = u.score
        THEN @last_rank 
      WHEN @last_score := u.score 
        THEN @rank 
    END AS rank    
  FROM 
    (SELECT * FROM user_score ORDER BY score DESC) u, 
    (SELECT @rank := 0, @last_score := NULL, @last_rank := 0) r
) t;

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM