在MySQL中排序排行榜

时间:2015-01-14 03:22:16

标签: mysql

我使用以下SQL在排行榜表中按排名排序:

SELECT score, 1+(SELECT COUNT(*) FROM leaderboard a WHERE a.score > b.score) AS rank 
FROM leaderboard b 
WHERE stage=1 
GROUP BY id

我的表架构是这样的:

CREATE TABLE `leaderboard` (
  `auto_id` int(11) NOT NULL AUTO_INCREMENT,
  `score` int(11) NOT NULL DEFAULT '0',
  `id` int(11) NOT NULL,
  `created_on` datetime NOT NULL,
  PRIMARY KEY (`auto_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;

一些示例数据行如下:

auto_id     score      id  created_on
====================================================
1,          72023456,   1, '2014-12-30 11:49:59'
2,          1420234,    1, '2014-12-30 12:00:21'
3,          420234,     1, '2014-12-30 12:00:38'
4,          16382,      1, '2014-12-30 16:31:12'
5,          16382,      1, '2014-12-30 16:34:18'
6,          16382,      1, '2014-12-30 16:37:43'
7,          17713,      1, '2014-12-30 16:38:35'
8,          17257,      1, '2014-12-30 18:53:45'
9,          10625,      1, '2014-12-30 18:58:10'
10,         17272,      1, '2014-12-30 18:58:59'
11,         17328,      1, '2014-12-30 18:59:44'
12,         17267,      37, '2015-01-02 17:11:59'
13,         16267,      37, '2015-01-02 17:12:30'
14,         16267,      37, '2015-01-02 17:13:02'
15,         35509,      37, '2015-01-02 17:17:46'
16,         18286,      37, '2015-01-02 18:20:09'
17,         16279,      37, '2015-01-02 18:20:43'
18,         16264,      37, '2015-01-02 18:21:15'
19,         16265,      37, '2015-01-02 18:40:04'

由于id是玩家的ID,我必须GROUP BY id。它给出了以下结果:

id   score        rank
=========================
1    72023456     1
37   17267        11

如何获得以下预期结果?

id   score        rank
=========================
1    72023456     1
37   35509        2

目前的问题是,现有结果不是玩家的最高得分。

奖励:我的最终目标是让参赛作品获得1等排名。比特定id低1个等级。

2 个答案:

答案 0 :(得分:2)

由于MySql没有Windowing Functions您需要的查询必须模仿其行为,因此您必须使用变量。

select id, score, @rank :=@rank+1 as rank
  from (
         SELECT b.id, max(b.score) as score
           FROM leaderboard b
          GROUP BY id
          order by score desc
        ) tab
        ,(select @rank := 0) r
编辑:我犯了一个小错误。我现在已经纠正过了。

输出将是:

id   score        rank
=========================
1    72023456     1
37   35509        2

基本上我正在做的是在查询上创建一个迭代器,并且每行都会增加变量。当我添加订单时,它将根据该订单对您的值进行排名。但是这个等级必须在查询之外发生,因为如果有两个以上的ID,那么顺序与等级并列将会搞砸了

我将使用" 1等级更高的解决方案编辑查询。比特定身份低1个等级。"

编辑奖金(虽然不漂亮)

select id, score, rank
from (
   select tab.id, tab.score, @rank :=@rank+1 as rank
     from (select @rank := 0) r,
            (SELECT b.id, max(b.score) as score
            FROM leaderboard b
            GROUP BY id
            order by score desc) tab
) spec
where spec.id=2
UNION
select id, score, rank
from (
   select tab.id, tab.score, @rank :=@rank+1 as rank
     from (select @rank := 0) r,
            (SELECT b.id, max(b.score) as score
            FROM leaderboard b
            GROUP BY id
            order by score desc) tab
) spec
where spec.rank=
(select rank-1
from (
   select tab.id, tab.score, @rank :=@rank+1 as rank
     from (select @rank := 0) r,
            (SELECT b.id, max(b.score) as score
            FROM leaderboard b
            GROUP BY id
            order by score desc) tab
) spec
where spec.id=2)
UNION
select id, score, rank
from (
   select tab.id, tab.score, @rank :=@rank+1 as rank
     from (select @rank := 0) r,
            (SELECT b.id, max(b.score) as score
            FROM leaderboard b
            GROUP BY id
            order by score desc) tab
) spec
where spec.rank=
(select rank+1
from (
   select tab.id, tab.score, @rank :=@rank+1 as rank
     from (select @rank := 0) r,
            (SELECT b.id, max(b.score) as score
            FROM leaderboard b
            GROUP BY id
            order by score desc) tab
) spec
where spec.id=2)
order by rank;

请注意,您将特定ID放在条款spec.id=2上(我已经放2,因为我必须更改环境中的值以进行测试)

这里的SQL Fiddle和我的测试,两个查询工作:http://sqlfiddle.com/#!2/75047/2

答案 1 :(得分:0)

得分不是最大值的原因是,因为得分不在GROUP BY子句中,所以MySQL只是选择第一个值作为代表。从技术上讲,这不是有效的SQL。您可能想要使用MAX(score) AS score

至于排名,由于MySQL不支持窗口功能,你必须自己破解。您可以查看this SO post了解更多信息。标准方法似乎是使用可变变量来计算行,或者使用ON子句中的不等式将查询连接到自身。看起来都不是很优雅。