Sql 我如何查询我的数据库中的用户排名,而只考虑每个用户的最新条目?
假设我有一个名为Scrape的数据库表,可能设置如下:Sql 我如何查询我的数据库中的用户排名,而只考虑每个用户的最新条目?,sql,database,sql-server-2005,screen-scraping,greatest-n-per-group,Sql,Database,Sql Server 2005,Screen Scraping,Greatest N Per Group,假设我有一个名为Scrape的数据库表,可能设置如下: UserID (int) UserName (varchar) Wins (int) Losses (int) ScrapeDate (datetime) 我试图能够根据用户的胜负比对他们进行排名。然而,每周我都会搜集关于用户的新数据,并在Scrape表中输入另一个条目 如何查询按胜负排序的用户列表,但只考虑最近的输入日期 你也认为,人们会在网站上打牌吗? 例如,我可以: 1 - Bob - Wins: 320 - L
UserID (int)
UserName (varchar)
Wins (int)
Losses (int)
ScrapeDate (datetime)
我试图能够根据用户的胜负比对他们进行排名。然而,每周我都会搜集关于用户的新数据,并在Scrape表中输入另一个条目
如何查询按胜负排序的用户列表,但只考虑最近的输入日期
你也认为,人们会在网站上打牌吗? 例如,我可以:
1 - Bob - Wins: 320 - Losses: 110 - ScrapeDate: 7/8/09
1 - Bob - Wins: 360 - Losses: 122 - ScrapeDate: 7/17/09
2 - Frank - Wins: 115 - Losses: 20 - ScrapeDate: 7/8/09
其中,这表示到目前为止只更新了Bob,并且正在更新Frank,但尚未插入。你会如何处理这种情况呢
所以,我的问题是:
您将如何处理仅查询每个用户的最新数据以确定排名
您是否认为数据库可能处于更新状态,特别是当一个scrape可能需要1天才能完成,并且并非所有用户都已完全更新时,这一事实是否重要?如果是这样,你会如何处理?
谢谢,谢谢你对我的相关问题的回答:
问题第一部分的答案取决于您使用的SQL server的版本—SQL 2005+提供的版本,这使得此类查询比SQL 2000及以前的版本更简单。如果你能指出你使用的是哪个平台,我会更详细地更新这个 我认为处理第2部分最清晰的方法是显示最近一次完整的刮削练习的统计数据,否则你不会显示时间一致的排名,尽管,如果你的数据收集练习需要24小时,那么已经有一定的自由度了 为了简化这一过程,您可以创建一个表来保存关于每个刮取操作的元数据,至少为每个刮取操作提供一个id、开始日期和完成日期,并显示与最新的完整刮取相关的记录。为了简化此操作,您可以从数据收集表中删除刮取日期,并将其替换为将每个数据行链接到刮取表中某一行的外键 编辑 以下代码说明了如何根据用户的最新分数对用户进行排名,而不管他们是否与时间一致:
create table #scrape
(userName varchar(20)
,wins int
,losses int
,scrapeDate datetime
)
INSERT #scrape
select 'Alice',100,200,'20090101'
union select 'Alice',120,210,'20090201'
union select 'Bob' ,200,200,'20090101'
union select 'Clara',300,100,'20090101'
union select 'Clara',300,210,'20090201'
union select 'Dave' ,100,10 ,'20090101'
;with latestScrapeCTE
AS
(
SELECT *
,ROW_NUMBER() OVER (PARTITION BY userName
ORDER BY scrapeDate desc
) AS rn
,wins + losses AS totalPlayed
,wins - losses as winDiff
from #scrape
)
SELECT userName
,wins
,losses
,scrapeDate
,winDiff
,totalPlayed
,RANK() OVER (ORDER BY winDiff desc
,totalPlayed desc
) as rankPos
FROM latestScrapeCTE
WHERE rn = 1
ORDER BY rankPos
编辑2
使用元数据表选择最新完整刮片的图示:
create table #scrape_run
(runID int identity
,startDate datetime
,completedDate datetime
)
create table #scrape
(userName varchar(20)
,wins int
,losses int
,scrapeRunID int
)
INSERT #scrape_run
select '20090101', '20090102'
union select '20090201', null --null completion date indicates that the scrape is not complete
INSERT #scrape
select 'Alice',100,200,1
union select 'Alice',120,210,2
union select 'Bob' ,200,200,1
union select 'Clara',300,100,1
union select 'Clara',300,210,2
union select 'Dave' ,100,10 ,1
;with latestScrapeCTE
AS
(
SELECT TOP 1 runID
,startDate
FROM #scrape_run
WHERE completedDate IS NOT NULL
)
SELECT userName
,wins
,losses
,startDate AS scrapeDate
,wins - losses AS winDiff
,wins + losses AS totalPlayed
,RANK() OVER (ORDER BY (wins - losses) desc
,(wins + losses) desc
) as rankPos
FROM #scrape
JOIN latestScrapeCTE
ON runID = scrapeRunID
ORDER BY rankPos
尝试以下方法:
为每个用户选择用户id和上次输入的最大日期。
根据以上查询结果,选择并排序记录以获得排名。
不过,这应该是可行的,这取决于您的数据库大小
DECLARE
@last_entries TABLE(id int, dte datetime)
-- insert date (dte) of last entry for each user (id)
INSERT INTO
@last_entries (id, dte)
SELECT
UserID,
MAX(ScrapeDate)
FROM
Scrape WITH (NOLOCK)
GROUP BY
UserID
-- select ranking
SELECT
-- optionally you can use RANK OVER() function to get rank value
UserName,
Wins,
Losses
FROM
@last_entries
JOIN
Scraps WITH (NOLOCK)
ON
UserID = id
AND ScrapeDate = dte
ORDER BY
Winds,
Losses
我没有测试这段代码,所以它无法在第一次运行时编译。这就是我所说的最大的每组n个问题。它每周在StackOverflow上出现几次 我使用外部连接技术解决此类问题:
SELECT s1.*, s1.wins / s1.losses AS win_loss_ratio
FROM Scrape s1
LEFT OUTER JOIN Scrape s2
ON (s1.username = s2.username AND s1.ScrapeDate < s2.ScrapeDate)
WHERE s2.username IS NULL
ORDER BY win_loss_ratio DESC;
这将为每个用户名只返回一行-在scrapdate列中具有最大值的行。这就是外部联接的目的,尝试将s1与具有相同用户名和更大日期的其他行s2匹配。如果没有这样的行,则外部联接将为s2的所有列返回NULL,然后我们知道s1对应于给定用户名的日期最大的行
当您正在进行部分完成的刮伤时,这也应该起作用
这种技术不一定像其他答案给出的CTE和排名解决方案那样快速。你应该同时尝试这两种方法,看看哪种方法更适合你。我之所以喜欢我的解决方案,是因为它可以在任何类型的SQL中工作。但是,SQL 7、SQL 2000、SQL 2005、SQL 2008、SQL 2008 R2是哪个版本?