可以说我有所谓的“刮”可能设置像一个数据库表:
UserID (int)
UserName (varchar)
Wins (int)
Losses (int)
ScrapeDate (datetime)
我想能够根据他们的胜利/损失比率排名我的用户。 然而,每个星期我会刮在用户新的数据,使在刮表中的另一个项目。
我如何可以查询由胜/负排序的用户列表,但只有考虑到最近的条目(ScrapeDate)?
另外,你认为它很重要,人们会被击中的部位和刮可能是在完成中间?
例如,我可以有:
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
其中,这表示只更新鲍勃至今一刮,并在更新弗兰克的过程,但还没有被插入。 你将如何处理这种情况呢?
所以,我的问题是:
- 你会如何处理只查询每个用户的最近凑来确定排名
- 你认为的事实,数据库可能是在更新(尤其是如果刮擦可能需要1天才能完成)的状态,而不是所有的用户已经完全更新还重要吗? 如果是的话,你会如何处理呢?
谢谢大家,谢谢你们,感谢你们给予我对我相关的问题您的回答:
当从网页刮了大量的统计资料,我应该多久插入我的数据库中收集的结果?
这就是我所说的“最伟大的正每个组”的问题。 它配备了每周几次在计算器上。
我使用一个外部联接的技术来解决这类问题:
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;
这将返回每个用户名只有一排-与最值的行ScrapeDate
列。 这就是外连接什么是,要尽量配合s1
与另一列s2
具有相同的用户名和更大的日期。 如果没有这样的行,外部连接返回NULL对于所有列s2
,然后我们知道s1
对应于与该给定用户名的最大日起一行。
当你有一个进展中的部分完成的刮这也应该工作。
这种技术并不一定如CTE和排名的解决方案其他答案已经给出快捷。 你应该尝试,看看有什么适合你更好。 我喜欢我的解决方案的原因是,它工作在SQL中的任何味道。
尝试是这样的:
- 选择用户名并为每个用户最后一个条目的最大日期。
- 选择和订购的记录,我们将根据上面的查询结果中的排名。
这应该工作,但是取决于你的数据库的大小。
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
我没有测试此代码,因此它无法在第一次运行时编译。
回答你的问题的第一部分取决于你使用的是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
文章来源: How can I query rankings for the users in my DB, but only consider the latest entry for each user?