3

我已经搜索和搜索,但无法使其正常工作。如果有人可以帮助我,我将不胜感激。

我有一个存储所玩游戏信息的表格(小测验应用程序)。我需要能够根据得分最高,其次是最低时间来确定排名前 5 的玩家。(许多玩家有最高分)。我还需要确定任何给定时间的用户排名。

这是游戏桌的示例:

user_id 学分 time_played 别名
-------- ------- ------------ --------------
64 490 180 达普拉亚
93 690 187 超人
64 336 187 达普拉亚
75 196 192 薄片
93 182 197 超人
57 844 198 约翰·史密斯
75 350 198 薄片
64 858 384 达普拉亚
73 858 400 小家伙
57 858 412 约翰·史密斯
101 858 420 闪光灯
73 858 423 小家伙
73 858 434 小家伙
65 858 460 希娜
122 858 540 糖皇后
126 858 545 雷切尔
176 350 2417 火光
157 350 2442 大Q
161 350 2456 乔伊蓝

我正在使用的当前查询是这样的:

select top 5 alias,user_id, 
   rank() over (order by max(credits) desc,min(time_played)) as rank 
from games,users 
where games.user_id=users.id and users.id <> 20 and games.credits > 0 
group by user_id,alias

(从查询中可以看出,别名实际上存储在 users 表中。)

我认为这个查询有效,因为它似乎显示了正确的结果,但是现在该网站已经上线,并且我有成千上万的游戏,我可以看出它是错误的。

上面的查询基本上给了我 5 个可能得分最高的玩家,但它对他们的最低游戏时间进行了排名。(因此得分较低的游戏速度更快)。

请让我知道如何调整/修改此查询或完全重写它。

(注意,我可以使用带有循环的 php 来简单得多,但这不会很有效。)

如果需要,我很乐意提供更多信息。

在此先感谢,亚伦。

4

4 回答 4

3
with user_ranked_games as (
  select user_id,
         credits,
         time_played,
         row_number() over (  partition by user_id 
                              order by credits desc, time_played asc
                           ) as game_rank
    from games
)
select top 5
       rank() over (order by g.credits desc, g.time_played asc) as rank,
       g.user_id,
       u.alias,
       g.credits,
       g.time_played
  from user_ranked_games g
  join users u
    on g.user_id = u.user_id
 where g.game_rank=1
order by rank

我在SQL Fiddle上成功测试了上述内容。我修改了数据值,使 littleguy 获得前 5 名中的 2 个。但我上面的查询正确地列出了 littleguy 在排名前 5 名的玩家中只有一次。

注意 - 我原来的 sql fiddle 有重复的用户行(我没有费心定义 PK),这会导致不同的输出,具体取决于连接的完成位置。我已经修复了数据并从 CTE 中删除了连接,并按照我最初的意图将它放在最外层的查询中。

更新以回应评论

一个小的修改提供了一个查询,可以查找单个用户的用户排名和分数:

with user_ranked_games as (
  select user_id,
         credits,
         time_played,
         row_number() over (  partition by user_id 
                              order by credits desc, time_played asc
                           ) as game_rank
    from games
),
ranked_users as (
  select rank() over (order by g.credits desc, g.time_played asc) as rank,
         g.user_id,
         u.alias,
         g.credits,
         g.time_played
    from user_ranked_games g
    join users u
      on g.user_id = u.user_id
   where g.game_rank=1
)
select * from ranked_users where user_id=93

您可能需要考虑创建一个可以方便地用来回答这两个问题的视图:

create view ranked_users as
with user_ranked_games as (
  select user_id,
         credits,
         time_played,
         row_number() over (  partition by user_id
                              order by credits desc, time_played asc
                           ) as game_rank
    from games
),
select rank() over (order by g.credits desc, g.time_played asc) as rank,
       g.user_id,
       u.alias,
       g.credits,
       g.time_played
  from user_ranked_games g
  join users u
    on g.user_id = u.user_id
 where g.game_rank=1

然后第一个查询变为:

select top 5 * from ranked_users order by rank

第二个查询变为

select * from ranked_users where user_id=93
于 2012-07-12T04:38:56.297 回答
1

如果你想要得分最高的玩家的排名,然后是最低的时间,那么使用这个:

select 
    topalias,
    user_id, 
    rank() OVER (ORDER BY Credits DESC, timePlayed ASC) AS Rank
from 
    games
    INNER JOIN users 
        on games.user_id = users.id 
 Order By 
     Credits DESC, timePlayed ASC
于 2012-07-11T22:25:24.283 回答
0

我承认对您的 SELECT 子句有些困惑,但是......我想我只是在 GROUP BY 子句之后加上“ORDER BY credits DESC,time_played ASC”。并且可能只是选择 *。

如果您想要一个保证 5 个不同名称的解决方案,请更改 FROM 子句以获取包含该表中不同名称的表。

于 2012-07-11T22:25:11.660 回答
0

复杂的因素是(如果我理解正确的话)你只想向每个玩家展示一次,即使他或她有(例如)五个最好的分数。所以你必须首先对所有游戏进行排名,然后为每个玩家获取最好的游戏,然后获取其中前五名的详细信息。

CREATE TABLE #Games
    (
    GameID  INT NOT NULL PRIMARY KEY,
    UserID  INT NOT NULL,
    Rank    INT NOT NULL,
    )
INSERT INTO #Games (GameID, UserID, Rank)
    SELECT
        game_id, user_id, ROW_NUMBER() OVER (ORDER BY credits DESC, time_played) AS Rank
    FROM
        games

SELECT TOP 5
    U2.alias, G2.credits, G2.time_played
FROM
    (
    SELECT UserID, MIN(Rank) AS BestRank
    FROM #Games
    GROUP BY UserID
    ) AS U1
    INNER JOIN users AS U2 ON U1.UserID = U2.user_id
    INNER JOIN #Games AS G1 ON U.BestRank = G1.Rank
    INNER JOIN games AS G2 ON G1.GameID = G2.game_id
ORDER BY
    U1.BestRank
于 2012-07-11T22:58:37.260 回答