获得每个组的前1行
我有一张表格,我想为每个组获得最新的条目。 这里是表格:
DocumentStatusLogs
表
|ID| DocumentID | Status | DateCreated |
| 2| 1 | S1 | 7/29/2011 |
| 3| 1 | S2 | 7/30/2011 |
| 6| 1 | S1 | 8/02/2011 |
| 1| 2 | S1 | 7/28/2011 |
| 4| 2 | S2 | 7/30/2011 |
| 5| 2 | S3 | 8/01/2011 |
| 6| 3 | S1 | 8/02/2011 |
该表将按DocumentID
进行分组,并按降序排列DateCreated
进行排序。 对于每个DocumentID
,我想获得最新状态。
我的首选输出:
| DocumentID | Status | DateCreated |
| 1 | S1 | 8/02/2011 |
| 2 | S3 | 8/01/2011 |
| 3 | S1 | 8/02/2011 |
是否有任何聚合函数只能获得每个组的顶部? 请参阅下面的伪代码GetOnlyTheTop
:
SELECT
DocumentID,
GetOnlyTheTop(Status),
GetOnlyTheTop(DateCreated)
FROM DocumentStatusLogs
GROUP BY DocumentID
ORDER BY DateCreated DESC
如果这样的功能不存在,有什么办法可以实现我想要的输出吗?
status
也位于父表中? 请参阅父表以获取更多信息:
当前Documents
表
| DocumentID | Title | Content | DateCreated |
| 1 | TitleA | ... | ... |
| 2 | TitleB | ... | ... |
| 3 | TitleC | ... | ... |
父表是否应该像这样,以便我可以轻松访问其状态?
| DocumentID | Title | Content | DateCreated | CurrentStatus |
| 1 | TitleA | ... | ... | s1 |
| 2 | TitleB | ... | ... | s3 |
| 3 | TitleC | ... | ... | s1 |
更新我刚刚学会了如何使用“应用”,这可以更容易地解决这些问题。
;WITH cte AS
(
SELECT *,
ROW_NUMBER() OVER (PARTITION BY DocumentID ORDER BY DateCreated DESC) AS rn
FROM DocumentStatusLogs
)
SELECT *
FROM cte
WHERE rn = 1
如果您期望每天有2个参赛作品,那么这将随意挑选一个参赛作品。 要获得一天的两个条目,请改用DENSE_RANK
至于规范化与否,这取决于你是否想要:
就目前而言,你保存了状态历史记录。 如果你想在父表中获得最新的状态(这是非规范化),你需要一个触发器来维护父状态。 或者丢弃这个状态历史表。
我刚刚学会了如何使用cross apply
。 以下是在这种情况下使用它的方法:
select d.DocumentID, ds.Status, ds.DateCreated
from Documents as d
cross apply
(select top 1 Status, DateCreated
from DocumentStatusLogs
where DocumentID = d.DocumentId
order by DateCreated desc) as ds
我在这里对各种建议做了一些计时,结果实际上取决于涉及的表的大小,但最一致的解决方案是使用CROSS APPLY这些测试是针对SQL Server 2008-R2运行的, 6,500条记录,另一条(相同的模式),有1.37亿条记录。 被查询的列是表中主键的一部分,表宽度非常小(约30个字节)。 SQL Server从实际执行计划中报告时间。
Query Time for 6500 (ms) Time for 137M(ms)
CROSS APPLY 17.9 17.9
SELECT WHERE col = (SELECT MAX(COL)…) 6.6 854.4
DENSE_RANK() OVER PARTITION 6.6 907.1
我认为真正令人惊讶的是,无论涉及多少行,交叉应用的时间是多么一致。
链接地址: http://www.djcxy.com/p/94521.html