开发者

mySQL Ranking (and draws)

Next weekend we're having a competition with 3 qualifications a semifinal and a final. Only the best 15 participants could compete in the semifinal. Only the best 6 compete in the Finals.

in the qualifications you get a score from 0 to 100 for each qualification

I'm looking to find a way to select the contesters for the semi-final. This should be based on (rank of qualification1) * (rank of qualification2) * (rank of qualification3)

so i need something like:

select id, name, ((.... as RANK_OF_SCORE_1) * (.. as RANK_OF_SCORE_2) * (... as     RANK_OF_SCORE_3)) as qualification_score from participants order by qualification_score desc limit 15

but of course this is not valid 开发者_运维百科mySQL.

Besides this problem if tho contesters have the same score, they should be both included in the semi-finals even if this exceeds the maximum of 15.

For the finals, we would like to select the best 6 of the semi-final scores. If 2 scores are the same we would like to select on the qualifications..


option 1 : use postgres, which support windowing functions (namely RANK() and DENSE_RANK())

SELECT user_id, score, rank() over (order by score desc) from scores;
Time : 0.0014 s

option 2 : use a self- join : the rank of a user with score X is (1 +the count(*) of users with score less than X) ; this is likely to be pretty slow

CREATE TABLE scores( user_id INT PRIMARY KEY, score INT, KEY(score) );
INSERT INTO scores SELECT id, rand()*100 FROM serie LIMIT 1000;

SELECT a.user_id, a.score, 1+count(b.user_id) AS rank 
    FROM scores a 
    LEFT JOIN scores b ON (b.score>a.score) 
    GROUP BY user_id ORDER BY rank;

+---------+-------+------+
| user_id | score | rank |
+---------+-------+------+
|     381 |   100 |    1 |
|     777 |   100 |    1 |
|     586 |   100 |    1 |
|     907 |   100 |    1 |
|     790 |   100 |    1 |
|     253 |    99 |    6 |
|     393 |    99 |    6 |
|     429 |    99 |    6 |
|     376 |    99 |    6 |
|     857 |    99 |    6 |
|     293 |    99 |    6 |
|     156 |    99 |    6 |
|     167 |    98 |   13 |
|     594 |    98 |   13 |
|     690 |    98 |   13 |
|     510 |    98 |   13 |
|     436 |    98 |   13 |
|     671 |    98 |   13 |

time 0.7s

option 3 :

SET @rownum = 0;
SELECT a.user_id, a.score, b.r FROM
scores a
JOIN (
    SELECT score, min(r) AS r FROM (
        SELECT user_id, score, @rownum:=@rownum+1 AS r 
        FROM scores ORDER BY score DESC
    ) foo GROUP BY score
) b USING (score)
ORDER BY r;

time : 0.0014 s

EDIT

SET @rownum1 = 0;
SET @rownum2 = 0;
SET @rownum3 = 0;

SELECT s.*, s1.r, s2.r, s3.r FROM
scores s
JOIN
(
    SELECT score_1, min(r) AS r FROM (
        SELECT score_1, @rownum1:=@rownum1+1 AS r 
        FROM scores ORDER BY score_1 DESC
    ) foo GROUP BY score_1
) s1 USING (score_1) JOIN (
    SELECT score_2, min(r) AS r FROM (
        SELECT score_2, @rownum2:=@rownum2+1 AS r 
        FROM scores ORDER BY score_2 DESC
    ) foo GROUP BY score_2
) s2 USING (score_2) JOIN (
    SELECT score_3, min(r) AS r FROM (
        SELECT score_3, @rownum3:=@rownum3+1 AS r 
        FROM scores ORDER BY score_3 DESC
    ) foo GROUP BY score_3
) s3 USING (score_3)
ORDER BY s1.r * s2.r * s3.r;
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜