我进行了搜索和搜索,但一直无法使用。如果有人可以帮助我,我真的很感激。
我有一个存储游戏信息的表格(小测验应用程序)。 我需要能够根据得分最高,然后是最低时间来确定排名前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更简单,但效率不高。)
如果需要,我很乐意提供更多信息。
提前致谢, 亚伦。
答案 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