如何根据SQL Server中的最高点和最低时间计算排名

时间:2012-07-11 22:17:27

标签: sql sql-server-2008

我进行了搜索和搜索,但一直无法使用。如果有人可以帮助我,我真的很感激。

我有一个存储游戏信息的表格(小测验应用程序)。 我需要能够根据得分最高,然后是最低时间来确定排名前5位的球员。 (很多球员都有最高分)。 我还需要在任何给定时间确定用户排名。

以下是游戏桌的示例:

user_id  credits  time_played  alias
-------  -------  -----------  --------------
64       490      180          DaPlaya
93       690      187          Superman
64       336      187          DaPlaya
75       196      192          Flake
93       182      197          Superman
57       844      198          John Smith
75       350      198          Flake
64       858      384          DaPlaya
73       858      400          littleguy
57       858      412          John Smith
101      858      420          FLASH
73       858      423          littleguy
73       858      434          littleguy
65       858      460          Sheena
122      858      540          Sugar Queen
126      858      545          Rachel
176      350      2417         The Fire Light
157      350      2442         Big Q
161      350      2456         Joey Blue

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

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 个答案:

答案 0 :(得分: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个。但我上面的查询正确地列出了排名前5位的玩家中只有一次。

注意 - 我原来的sql小提琴有重复的用户行(我没有打扰定义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

答案 1 :(得分: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

答案 2 :(得分:0)

我承认你的SELECT子句有点混淆,但是......我想我只是在GROUP BY子句之后加上“ORDER BY credit DESC,time_played ASC”。可能只是SELECT *。

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

答案 3 :(得分: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