获得每个组的前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

    至于规范化与否,这取决于你是否想要:

  • 保持2个地方的状态
  • 保存状态历史
  • ...
  • 就目前而言,你保存了状态历史记录。 如果你想在父表中获得最新的状态(这是非规范化),你需要一个触发器来维护父状态。 或者丢弃这个状态历史表。


    我刚刚学会了如何使用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

    上一篇: Get top 1 row of each group

    下一篇: Appropriate Uses of the `IDENTITY` in TSQL