2015-04-06 98 views
0

我们有一个计时游戏和一个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,每个名称,以及该用户在该级别有时间。

请注意,此排行榜允许每个用户拥有多个时间。它保持旧时代并将其显示在排行榜页面上。但是,在下一个案例中,我们希望忽略除每个用户最高时间以外的所有内容。

我们希望能够得到用户所玩过的每个级别的列表,并且这种方法可以正常工作,但棘手的部分是我们想要获得与同一级别其他用户相关的用户排名。所以,从这个表中,我们要像返回数据:

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仅在那里排名第二。

我们实际上测量的是以毫秒为单位的时间,但我决定在几秒钟内写出它,所以我的表格看起来并不令人困惑。我可以很容易地得到表2,除非我不知道如何在没有循环表格中的其他用户的情况下获得排名,这非常低效。

因此,这里有一些代码位我见过漂浮在SO,我试过:

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 

除了使没有意义并具有我没办法只能选择一个特定的水平(它选择表格中的所有内容),最终只需要一分钟即可完成。

有谁知道我应该怎么做才能在排行榜上获得玩家的等级?

回答

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)指数合理的性能。如果性能问题很大,而且您的桌子很大,则可能需要考虑触发器。

注意:这不会为给定的用户多次处理,因为您的示例代码不处理这个问题。

+0

这工作得很好!你能解释它是如何工作的吗?我不擅长MySQL。 – tomysshadow 2015-04-06 11:05:29

+0

简要说明:'order by'通过'level'和'time'排序行。变量'@ l'跟踪这个级别。当该值改变时,则@ rn被重新设置为1.否则,它会递增。 – 2015-04-06 11:33:34