我们有一个计时游戏和MySQL数据库记录每个用户的时间。以下是表格组织的示例。
| level | userid | time |
--------------------------------
| levelone | 1 | 7.00 |
| levelone | 2 | 8.00 |
| levelone | 3 | 9.00 |
| levelone | 3 | 10.00 |
| leveltwo | 2 | 22.00 |
| leveltwo | 1 | 23.00 |
| levelthree | 3 | 14.00 |
| levelthree | 1 | 16.00 |
| levelthree | 2 | 18.00 |
因此,我们拥有用户完成的关卡的名称,用户的ID,每个ID对应一个用户名,以及该用户在该关卡上获得的时间。
请注意,此排行榜允许每个用户拥有多次。它保留了旧时代并将它们显示在排行榜页面上。但是,在下一种情况下,除了每个用户的最高时间之外,我们要忽略所有内容。
我们希望能够获得用户已经玩过的每个级别的列表,并且这样做是正常的,但是棘手的部分是我们希望获得该用户与其他用户相关的排名同一水平。因此,从这个表中我们想要返回如下数据:
User ID 1 Has Played These Levels
| level | rank | time |
-----------------------------
| levelone | 1 | 7.00 |
| leveltwo | 2 | 23.00 |
| levelthree | 2 | 16.00 |
正如您所看到的,用户ID 1在第一级击败了所有人。因此,用户ID 1在该级别上排名第一。
但是用户1在第二级被用户2击败,因此用户1仅排在第二位。
我们实际上以毫秒为单位测量时间,但我决定在几秒钟内写出来,所以我的表格看起来并不令人困惑。我可以轻松地将表格二显示出来,除非我不知道如何在没有遍历表格中的每个其他用户的情况下获得排名,这是非常低效的。
所以这里有一些我已经看过的代码位,我已经尝试过了:
SELECT (COUNT(*) + 1) AS rank FROM lb WHERE time < (SELECT time FROM lb WHERE userid = 1')
这是有道理的,但是当我尝试它时,MySQL给了我一个错误:
#2014 - Commands out of sync; you can't run this command now
这是另一个:
SET @rownum := 0;
SELECT rank, userid, time FROM (SELECT @rownum := @rownum + 1 AS rank, userid, time FROM lb ORDER BY time DESC) AS t1
除了没有任何意义,也没有办法让我只选择一个特定的级别(它选择表中的所有内容),它需要大约一分钟才能执行,最终才会超时。
有谁知道我应该做些什么才能在排行榜的某个级别上获得玩家的排名?
答案 0 :(得分:1)
您可以使用变量为所有级别执行此操作:
SELECT rank, userid, time
FROM (SELECT (@rn := if(@l = level, @rn + 1,
if(@l := level, 1, 1)
)
) as rank,
userid, time
FROM lb CROSS JOIN
(SELECT @rn := 0, @l := '') vars
ORDER BY level, time DESC
) t1
WHERE userid = @USERID;
这应该具有合理的性能,索引在lb(level, time, userid)
。如果性能是一个大问题而且你有一个大表,你可能需要考虑触发器。
注意:对于给定用户,这不会多次处理,因为您的示例代码无法处理此问题。