2013年10月8日 星期二

【轉】MySQL 求名次的問題

MySQL 求名次的問題

Oracle 有Rank()可以使用,所以作排名很方便.
MySQL 使用一些技巧也可以達到排名的功能.

CREATE TABLE test0707 (
member_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
score INT
);

插入測試資料.

INSERT INTO test0707(score) VALUES
(386),(497),(538),(998),(346),(123),(675),(665),(386),(448);

--------------------
簡易排序
SELECT score, member_id
FROM test0707
ORDER BY score DESC;


SELECT @rownum := @rownum+1 AS 'Rank', a.*
FROM (SELECT score, member_id
       FROM test0707 
       ORDER BY score DESC) a, (SELECT @rownum := 0) r;
+------+-------+-----------+
| Rank | score | member_id |
+------+-------+-----------+
|    1 |   998 |         4 |
|    2 |   675 |         7 |
|    3 |   665 |         8 |
|    4 |   538 |         3 |
|    5 |   497 |         2 |
|    6 |   448 |        10 |
|    7 |   386 |         9 |
|    8 |   386 |         1 |
|    9 |   346 |         5 |
|   10 |   123 |         6 |
+------+-------+-----------+

上面可以看到兩個分數為386的為7/8名.這種Rank的方法,在作一些資料分析時方便,但是拿來發獎金或是
考試分發就會被抗議了.

改用以下的方法:
SELECT a.rank AS 'Rank', a.score, a.member_id 
FROM (SELECT member_id, score, @prev := @curr, @curr := score, @rank := IF(@prev = @curr, @rank, @rank+1) AS rank
FROM test0707, (SELECT @curr := null, @prev := null, @rank := 0) s
ORDER BY score DESC) a;

+------+-------+-----------+
| Rank | score | member_id |
+------+-------+-----------+
|    1 |   998 |         4 |
|    2 |   675 |         7 |
|    3 |   665 |         8 |
|    4 |   538 |         3 |
|    5 |   497 |         2 |
|    6 |   448 |        10 |
|    7 |   386 |         9 |
|    7 |   386 |         1 |
|    8 |   346 |         5 |
|    9 |   123 |         6 |
+------+-------+-----------+

這樣排名的方式就是相同分數會是同樣名次.

回到樓主的問題,若是單獨只要算一個人的名次,也不必用全部的排名,用上面網友提出的方法更好.
但若是需要後續計算好幾個名次的, 可以試試這樣的方式.裡面的排名部份,會放到cache裡.
然後再視需要取出對應的資料.

假設要取 member_id 為8 的名次

SELECT member_id, b.Rank
FROM (SELECT a.rank AS 'Rank', a.score, a.member_id 
       FROM (SELECT member_id, score, @prev := @curr, @curr := score, @rank := IF(@prev = @curr, @rank, @rank+1) AS rank
             FROM test0707, (SELECT @curr := null, @prev := null, @rank := 0) s
             ORDER BY score DESC) a) b
WHERE member_id = 8;

+-----------+------+
| member_id | Rank |
+-----------+------+
|         8 |    3 |
+-----------+------+

沒有留言: