ChatGPT解决这个技术问题 Extra ChatGPT

我有一张表,我想获取每个组的最新条目。这是表格:

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

如果这样的功能不存在,有什么办法可以实现我想要的输出?

或者首先,这可能是由非规范化数据库引起的吗?我在想,既然我要找的只是一行,那么该状态是否也应该位于父表中?

有关详细信息,请参阅父表:

当前 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            |

更新我刚刚学会了如何使用“应用”,它可以更容易地解决这些问题。

有关可能解决方案的更详细讨论和比较,我建议阅读 dba.se 上的类似问题:Retrieving n rows per group
我看了一下帖子,试了一下。使用按 StoreID 分组会产生错误。
此问题适用于 MS SQL Server,问题 Select first row in each GROUP BY group 适用于 Postgres。语言结构可以不同。

g
gbn
;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个地方保持状态

保留状态历史

...

就目前而言,您保留状态历史记录。如果您也想要父表中的最新状态(这是非规范化),您需要一个触发器来维护父表中的“状态”。或删除此状态历史记录表。


还有... Partition By 是什么? With 对我来说也是新的 :( 反正我使用的是 mssql 2005。
@domanokz:分区依据重置计数。所以在这种情况下,它说按 DocumentID 计数
嗯,我担心性能,我将查询数百万行。 SELECT * FROM (SELECT ...) 会影响性能吗?另外,ROW_NUMBER 是每行的某种子查询吗?
@domanokz:不,它不是子查询。如果您有正确的索引,那么数百万应该不是问题。无论如何,只有两种基于集合的方式:this 和聚合(Ariel 的解决方案)。所以两个都试试...
@domanokz:只需将 ORDER BY DateCreated DESC 更改为 ORDER BY ID DESC
d
dpp

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

这实际上没有什么区别,因为这个问题仍然得到解决。
我刚刚发布了针对所有提议的解决方案的时序测试结果,而您的则名列前茅。给你一个赞成票:-)
+1 大幅提升速度。这比诸如 ROW_NUMBER() 之类的窗口函数要快得多。如果 SQL 能够识别 ROW_NUMBER() = 1 类似的查询并将它们优化为应用程序,那就太好了。注意:我使用了 OUTER APPLY 因为我需要结果,即使它们在申请中不存在。
@TamusJRoyce,您不能仅仅因为这种情况总是如此,它就更快了。这取决于。如此处所述sqlmag.com/database-development/optimizing-top-n-group-queries
如果您已经有一个单独的 Documents 表,该表按照输出的需要为每个组提供一行,则此方法效果很好。但是,如果您只使用一个表(在本例中为 DocumentStatusLogs),您首先必须对 DocumentID(或 ROW_NUMBER()MAX(ID) 等)执行某种 DISTINCT 操作。 ),失去所有获得的性能。
J
Josh Gilfillan

我知道这是一个旧线程,但 TOP 1 WITH TIES 解决方案非常好,可能有助于阅读解决方案。

select top 1 with ties
   DocumentID
  ,Status
  ,DateCreated
from DocumentStatusLogs
order by row_number() over (partition by DocumentID order by DateCreated desc)

select top 1 with ties 子句告诉 SQL Server 您要返回每个组的第一行。但是 SQL Server 是如何知道如何对数据进行分组的呢?这就是 order by row_number() over (partition by DocumentID order by DateCreated desc 的用武之地。partition by 之后的列/列定义 SQL Server 如何对数据进行分组。在每个组中,行将根据 order by 列进行排序。排序后,将在查询中返回每个组中的第一行。

有关 TOP 子句的更多信息,请参见 here


这是imo最优雅的解决方案
同意——这最好地复制了在其他版本的 SQL 和其他语言 imo 中很容易做到的事情
希望我能多次投票。我已经回到这个答案大约 7.000 次了。可能有一天,我会花时间去理解这一点,这样我就不必回来了。但这不是这一天。
嗯,'With Ties' 可能会导致返回的行数超过表达式中指定的值 (TOP 1)。如果 OP 只想要 1,那么你需要删除这个短语,对吗?
@TKBruin 这就是为什么需要按 row_number() 排序的原因。这允许检索每个分区的顶部记录。
J
John Fairbanks

我已经对这里的各种建议进行了一些计时,结果实际上取决于所涉及的表的大小,但最一致的解决方案是使用 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

我认为真正令人惊奇的是,无论涉及的行数如何,CROSS APPLY 的时间是多么一致。


这完全取决于数据分布和可用索引。在 dba.se 上进行了详细讨论。
D
Daniel Cotter

如果您担心性能,您也可以使用 MAX() 执行此操作:

SELECT *
FROM DocumentStatusLogs D
WHERE DateCreated = (SELECT MAX(DateCreated) FROM DocumentStatusLogs WHERE ID = D.ID)

ROW_NUMBER() 需要对 SELECT 语句中的所有行进行排序,而 MAX 不需要。应该大大加快您的查询速度。


不能通过正确的索引来解决 ROW_NUMBER() 的性能问题吗? (我觉得无论如何都应该这样做)
使用日期时间,您不能保证不会在同一日期和时间添加两个条目。精度不够高。
+1 为简单起见。 @TamusJRoyce 是对的。关于什么? 'select * from DocumentStatusLog D where ID = (select ID from DocumentsStatusLog where D.DocumentID = DocumentID order by DateCreated DESC limit 1);'
SELECT * FROM EventScheduleTbl D WHERE DatesPicked = (SELECT top 1 min(DatesPicked) FROM EventScheduleTbl WHERE EventIDf = D.EventIDf and DatesPicked>= convert(date,getdate()) )
就我而言,由于引入了子查询,这种方法比使用 ROW_NUMBER() 慢。您应该测试不同的方法,看看哪种方法最适合您的数据。
A
Ariel
SELECT * FROM
DocumentStatusLogs JOIN (
  SELECT DocumentID, MAX(DateCreated) DateCreated
  FROM DocumentStatusLogs
  GROUP BY DocumentID
  ) max_date USING (DocumentID, DateCreated)

什么数据库服务器?此代码不适用于所有这些。

关于你问题的后半部分,我认为将状态列为一列似乎是合理的。您可以将 DocumentStatusLogs 保留为日志,但仍将最新信息存储在主表中。

顺便说一句,如果您在 Documents 表中已有 DateCreated 列,则可以使用它加入 DocumentStatusLogs(只要 DateCreatedDocumentStatusLogs 中是唯一的)。

编辑:MsSQL 不支持 USING,因此将其更改为:

ON DocumentStatusLogs.DocumentID = max_date.DocumentID AND DocumentStatusLogs.DateCreated = max_date.DateCreated

线索就在标题中:MSSQL。 SQL Server 没有 USING 但想法还可以。
@gbn 愚蠢的版主通常会从标题中删除重要的关键字,就像他们在这里所做的那样。很难在搜索结果或 Google 中找到正确答案。
只是要指出,如果您在 max(DateCreated)
删除 Using(在 MS SQL 中)并完成 Join 代码,然后它就可以工作了。
M
MattSlay

这是关于该主题的最容易找到的问题之一,所以我想给出一个现代的答案(供我参考和帮助其他人)。通过使用 first_valueover,您可以简化上述查询:

Select distinct DocumentID
  , first_value(status) over (partition by DocumentID order by DateCreated Desc) as Status
  , first_value(DateCreated) over (partition by DocumentID order by DateCreated Desc) as DateCreated
From DocumentStatusLogs

这应该适用于 Sql Server 2008 及更高版本。在使用 over 子句时,可以将 First_value 视为完成 Select Top 1 的一种方式。 Over 允许在选择列表中进行分组,因此无需编写嵌套子查询(就像许多现有答案一样),它以更易读的方式进行。希望这可以帮助。


这在 SQL Server 2008 R2 中不起作用。我认为 first_value 是在 2012 年推出的!
非常快!我正在使用@dpp 提供的 Cross Apply 解决方案,但这个解决方案要快得多。
对于大量列(Status、DateCreated 等),这是否对每一列进行单独的分区/排序,还是优化为一个?
s
san

这里有 3 种不同的方法来解决手头的问题以及为每个查询建立索引的最佳选择(请自己尝试索引并查看逻辑读取、经过时间、执行计划。我根据我的经验提供了建议此类查询而不针对此特定问题执行)。

方法 1:使用 ROW_NUMBER()。如果行存储索引无法提高性能,您可以尝试非聚集/聚集列存储索引,对于具有聚合和分组的查询以及始终在不同列中排序的表,列存储索引通常是最佳选择。

;WITH CTE AS
    (
       SELECT   *,
                RN = ROW_NUMBER() OVER (PARTITION BY DocumentID ORDER BY DateCreated DESC)
       FROM     DocumentStatusLogs
    )
    SELECT  ID      
        ,DocumentID 
        ,Status     
        ,DateCreated
    FROM    CTE
    WHERE   RN = 1;

方法 2:使用 FIRST_VALUE。如果行存储索引无法提高性能,您可以尝试非聚集/聚集列存储索引,对于具有聚合和分组的查询以及始终在不同列中排序的表,列存储索引通常是最佳选择。

SELECT  DISTINCT
    ID      = FIRST_VALUE(ID) OVER (PARTITION BY DocumentID ORDER BY DateCreated DESC)
    ,DocumentID
    ,Status     = FIRST_VALUE(Status) OVER (PARTITION BY DocumentID ORDER BY DateCreated DESC)
    ,DateCreated    = FIRST_VALUE(DateCreated) OVER (PARTITION BY DocumentID ORDER BY DateCreated DESC)
FROM    DocumentStatusLogs;

方法 3:使用 CROSS APPLY。在 DocumentStatusLogs 表上创建覆盖查询中使用的列的行存储索引应该足以覆盖查询,而不需要列存储索引。

SELECT  DISTINCT
    ID      = CA.ID
    ,DocumentID = D.DocumentID
    ,Status     = CA.Status 
    ,DateCreated    = CA.DateCreated
FROM    DocumentStatusLogs D
    CROSS APPLY (
            SELECT  TOP 1 I.*
            FROM    DocumentStatusLogs I
            WHERE   I.DocumentID = D.DocumentID
            ORDER   BY I.DateCreated DESC
            ) CA;

感谢您提出的不同解决方案。我经历了第二个,今天救了我,伙计!
我有一个 100M 行的表,我需要在其中获取每个组的第一条和最后一条记录。前两种方法需要几分钟才能执行。方法 3 用了不到一秒钟。
感谢您提供这个非常全面的答案!值得更多的选票,尽管它的存在时间不及其他。
C
Clint

这是一个相当古老的线程,但我认为我会投入两分钱,因为接受的答案对我来说并不是特别好。我在一个大型数据集上尝试了 gbn 的解决方案,发现它非常慢(在 SQL Server 2012 中超过 500 万条记录超过 45 秒)。查看执行计划很明显,问题在于它需要一个 SORT 操作,这会显着减慢速度。

这是我从不需要 SORT 操作并执行非聚集索引搜索的实体框架中提取的替代方法。这将上述记录集的执行时间减少到 < 2 秒。

SELECT 
[Limit1].[DocumentID] AS [DocumentID], 
[Limit1].[Status] AS [Status], 
[Limit1].[DateCreated] AS [DateCreated]
FROM   (SELECT DISTINCT [Extent1].[DocumentID] AS [DocumentID] FROM [dbo].[DocumentStatusLogs] AS [Extent1]) AS [Distinct1]
OUTER APPLY  (SELECT TOP (1) [Project2].[ID] AS [ID], [Project2].[DocumentID] AS [DocumentID], [Project2].[Status] AS [Status], [Project2].[DateCreated] AS [DateCreated]
    FROM (SELECT 
        [Extent2].[ID] AS [ID], 
        [Extent2].[DocumentID] AS [DocumentID], 
        [Extent2].[Status] AS [Status], 
        [Extent2].[DateCreated] AS [DateCreated]
        FROM [dbo].[DocumentStatusLogs] AS [Extent2]
        WHERE ([Distinct1].[DocumentID] = [Extent2].[DocumentID])
    )  AS [Project2]
    ORDER BY [Project2].[ID] DESC) AS [Limit1]

现在我假设原始问题中未完全指定的内容,但如果您的表设计使得您的 ID 列是自动增量 ID,并且 DateCreated 设置为每次插入时的当前日期,那么即使如果不使用上面的查询运行,您实际上可以通过按 ID 排序而不是按 DateCreated 排序来为 gbn 的解决方案(大约一半的执行时间)获得相当大的性能提升,因为这将提供相同的排序顺序并且它是更快的排序。


A
AnuPrakash

我从每组中选择前 1 名的代码

select a.* from #DocumentStatusLogs a where 
 datecreated in( select top 1 datecreated from #DocumentStatusLogs b
where 
a.documentid = b.documentid
order by datecreated desc
)

M
Mohamed Thaufeeq

此解决方案可用于获取每个分区的 TOP N 最近行(在示例中,WHERE 语句中的 N 为 1,分区为 doc_id):

SELECT T.doc_id, T.status, T.date_created FROM 
(
    SELECT a.*, ROW_NUMBER() OVER (PARTITION BY doc_id ORDER BY date_created DESC) AS rnk FROM doc a
) T
WHERE T.rnk = 1;

D
Dale K

CROSS APPLY 是我用于解决方案的方法,因为它适用于我,也适合我的客户需求。从我读到的内容来看,如果他们的数据库大幅增长,应该会提供最佳的整体性能。


A
Andrew Morton

从上面验证克林特的真棒和正确的答案:

下面两个查询之间的性能很有趣。 52% 是第一名。 48% 是第二个。使用 DISTINCT 而不是 ORDER BY,性能提高了 4%。但是 ORDER BY 的优点是可以按多列排序。

IF (OBJECT_ID('tempdb..#DocumentStatusLogs') IS NOT NULL) BEGIN DROP TABLE #DocumentStatusLogs END

CREATE TABLE #DocumentStatusLogs (
    [ID] int NOT NULL,
    [DocumentID] int NOT NULL,
    [Status] varchar(20),
    [DateCreated] datetime
)

INSERT INTO #DocumentStatusLogs([ID], [DocumentID], [Status], [DateCreated]) VALUES (2, 1, 'S1', '7/29/2011 1:00:00')
INSERT INTO #DocumentStatusLogs([ID], [DocumentID], [Status], [DateCreated]) VALUES (3, 1, 'S2', '7/30/2011 2:00:00')
INSERT INTO #DocumentStatusLogs([ID], [DocumentID], [Status], [DateCreated]) VALUES (6, 1, 'S1', '8/02/2011 3:00:00')
INSERT INTO #DocumentStatusLogs([ID], [DocumentID], [Status], [DateCreated]) VALUES (1, 2, 'S1', '7/28/2011 4:00:00')
INSERT INTO #DocumentStatusLogs([ID], [DocumentID], [Status], [DateCreated]) VALUES (4, 2, 'S2', '7/30/2011 5:00:00')
INSERT INTO #DocumentStatusLogs([ID], [DocumentID], [Status], [DateCreated]) VALUES (5, 2, 'S3', '8/01/2011 6:00:00')
INSERT INTO #DocumentStatusLogs([ID], [DocumentID], [Status], [DateCreated]) VALUES (6, 3, 'S1', '8/02/2011 7:00:00')

选项1:

    SELECT
    [Extent1].[ID], 
    [Extent1].[DocumentID],
    [Extent1].[Status], 
    [Extent1].[DateCreated]
FROM #DocumentStatusLogs AS [Extent1]
    OUTER APPLY (
        SELECT TOP 1
            [Extent2].[ID], 
            [Extent2].[DocumentID],
            [Extent2].[Status], 
            [Extent2].[DateCreated]
        FROM #DocumentStatusLogs AS [Extent2]
        WHERE [Extent1].[DocumentID] = [Extent2].[DocumentID]
        ORDER BY [Extent2].[DateCreated] DESC, [Extent2].[ID] DESC
    ) AS [Project2]
WHERE ([Project2].[ID] IS NULL OR [Project2].[ID] = [Extent1].[ID])

选项 2:

SELECT 
    [Limit1].[DocumentID] AS [ID], 
    [Limit1].[DocumentID] AS [DocumentID], 
    [Limit1].[Status] AS [Status], 
    [Limit1].[DateCreated] AS [DateCreated]
FROM (
    SELECT DISTINCT [Extent1].[DocumentID] AS [DocumentID] FROM #DocumentStatusLogs AS [Extent1]
) AS [Distinct1]
    OUTER APPLY  (
        SELECT TOP (1) [Project2].[ID] AS [ID], [Project2].[DocumentID] AS [DocumentID], [Project2].[Status] AS [Status], [Project2].[DateCreated] AS [DateCreated]
        FROM (
            SELECT 
                [Extent2].[ID] AS [ID], 
                [Extent2].[DocumentID] AS [DocumentID], 
                [Extent2].[Status] AS [Status], 
                [Extent2].[DateCreated] AS [DateCreated]
            FROM #DocumentStatusLogs AS [Extent2]
            WHERE [Distinct1].[DocumentID] = [Extent2].[DocumentID]
        )  AS [Project2]
        ORDER BY [Project2].[ID] DESC
    ) AS [Limit1]

在 Microsoft SQL Server Management Studio 中:突出显示并运行第一个块后,突出显示选项 1 和选项 2,右键单击 -> [显示估计执行计划]。然后运行整个事情以查看结果。

选项 1 结果:

ID  DocumentID  Status  DateCreated
6   1   S1  8/2/11 3:00
5   2   S3  8/1/11 6:00
6   3   S1  8/2/11 7:00

选项 2 结果:

ID  DocumentID  Status  DateCreated
6   1   S1  8/2/11 3:00
5   2   S3  8/1/11 6:00
6   3   S1  8/2/11 7:00

笔记:

当我想要一个连接是一对(许多中的一个)时,我倾向于使用 APPLY。如果我希望连接是一对多或多对多,我会使用 JOIN。我避免使用 ROW_NUMBER() 进行 CTE,除非我需要做一些高级的事情并且可以接受窗口性能损失。

我还避免在 WHERE 或 ON 子句中使用 EXISTS / IN 子查询,因为我经历过这会导致一些糟糕的执行计划。但里程不同。随时随地查看执行计划和性能分析!


c
cho
SELECT o.*
FROM `DocumentStatusLogs` o                   
  LEFT JOIN `DocumentStatusLogs` b                   
  ON o.DocumentID = b.DocumentID AND o.DateCreated < b.DateCreated
 WHERE b.DocumentID is NULL ;

如果您只想按 DateCreated 返回最近的文档订单,它将仅按 DocumentID 返回前 1 个文档


这只会返回表中的所有内容。
U
Union find

我相信这可以像这样完成。这可能需要一些调整,但您可以从组中选择最大值。

这些答案是多余的。。

SELECT
  d.DocumentID,
  MAX(d.Status),
  MAX(d1.DateCreated)
FROM DocumentStatusLogs d, DocumentStatusLogs d1
USING DocumentID
GROUP BY 1
ORDER BY 3 DESC

这是t-sql吗?不支持 Using...
mysql 8 应该支持@PedroC88
是的,我提到它是因为 OP 指定了 sql-server
@PedroC88 这个问题似乎已经改变,因此它不再引用 sql-server 了。所以这是一个好的答案。
它在标签上
B
BitwiseMan

在您想避免使用 row_count() 的情况下,您还可以使用左连接:

select ds.DocumentID, ds.Status, ds.DateCreated 
from DocumentStatusLogs ds
left join DocumentStatusLogs filter 
    ON ds.DocumentID = filter.DocumentID
    -- Match any row that has another row that was created after it.
    AND ds.DateCreated < filter.DateCreated
-- then filter out any rows that matched 
where filter.DocumentID is null 

对于示例模式,您还可以使用“不在子查询中”,它通常编译为与左连接相同的输出:

select ds.DocumentID, ds.Status, ds.DateCreated 
from DocumentStatusLogs ds
WHERE ds.ID NOT IN (
    SELECT filter.ID 
    FROM DocumentStatusLogs filter
    WHERE ds.DocumentID = filter.DocumentID
        AND ds.DateCreated < filter.DateCreated)

请注意,如果表没有至少一个单列唯一键/约束/索引(在本例中为主键“Id”),则子查询模式将不起作用。

这两个查询往往比 row_count() 查询更“昂贵”(由查询分析器衡量)。但是,您可能会遇到它们更快地返回结果或启用其他优化的情况。


4
4b0
SELECT documentid, 
       status, 
       datecreated 
FROM   documentstatuslogs dlogs 
WHERE  status = (SELECT status 
                 FROM   documentstatuslogs 
                 WHERE  documentid = dlogs.documentid 
                 ORDER  BY datecreated DESC 
                 LIMIT  1) 

S
Suraj Kumar

尝试这个:

SELECT [DocumentID]
    ,[tmpRez].value('/x[2]', 'varchar(20)') AS [Status]
    ,[tmpRez].value('/x[3]', 'datetime') AS [DateCreated]
FROM (
    SELECT [DocumentID]
        ,cast('<x>' + max(cast([ID] AS VARCHAR(10)) + '</x><x>' + [Status] + '</x><x>' + cast([DateCreated] AS VARCHAR(20))) + '</x>' AS XML) AS [tmpRez]
    FROM DocumentStatusLogs
    GROUP BY DocumentID
    ) AS [tmpQry]

您应该始终描述您的 SQL 语句将如何工作并解决 OP 的查询。
M
MasterKiller

一些数据库引擎*开始支持 QUALIFY 子句,该子句允许过滤窗口函数的结果(接受的答案使用)。

所以接受的答案可以变成

SELECT *, ROW_NUMBER() OVER (PARTITION BY DocumentID ORDER BY DateCreated DESC) AS rn
FROM DocumentStatusLogs
QUALIFY rn = 1

请参阅这篇文章以获得深入的解释:https://jrandrews.net/the-joy-of-qualify

您可以使用此工具查看哪个数据库支持此子句: https://www.jooq.org/translate/ 当目标方言不支持时,可以选择转换限定子句。

*Teradata、BigQuery、H2、雪花……


r
rich s

这是我能想到的最普通的 TSQL

    SELECT * FROM DocumentStatusLogs D1 JOIN
    (
      SELECT
        DocumentID,MAX(DateCreated) AS MaxDate
      FROM
        DocumentStatusLogs
      GROUP BY
        DocumentID
    ) D2
    ON
      D2.DocumentID=D1.DocumentID
    AND
      D2.MaxDate=D1.DateCreated

不幸的是 MaxDate 不是唯一的。可以同时输入两个日期。因此,这可能会导致每组重复。但是,您可以使用标识列或 GUID。身份列将为您提供最新输入的内容(使用默认身份计算,1...x 步骤 1)。
好吧,我有点同意,但作者要求提供最新条目——除非你包含一个自动增量标识列,否则这意味着同时添加的两个项目同样是“最新的”
最新记录将是一条记录。所以是的。您需要考虑自动增量标识列。
D
Dale K

我的 SQL Server 版本:15.x (2019)

SELECT  TOP 1 WITH TIES
        DocumentID,
        GetOnlyTheTop(Status),
        GetOnlyTheTop(DateCreated)
FROM DocumentStatusLogs
GROUP BY DocumentID
ORDER BY ROW_NUMBER() OVER(PARTITION BY DateCreated ORDER BY DateCreated DESC)

这与@JoshGilfillan 的回答有何不同stackoverflow.com/a/48412942/14868997
OP 标记为 MS-SQL 不是 My SQL
S
Suraj Rao

希望这会起作用..只需根据您的数据库更改列。

select
r2.id,
r2.name,
r2.e_date,
r2.roomcode,
r2.roomname,
r2.bedn
from 
(   
 select 
    id,
    max(e_date) e_date
    from rooms
    group by id
) r1
inner join rooms r2 on r2.id = r1.id and r2.e_date = r1.e_date;

这个问题有 22 个现有答案,包括一个获得最高票数、超过 800 票被接受的答案。你确定你的解决方案还没有给出吗?如果不是,您为什么认为您的方法改进了已通过社区验证的现有提案?在 Stack Overflow 上提供解释总是有用的,但在问题已得到解决且令 OP 和社区都满意的情况下尤为重要。请通过解释您的答案的不同之处以及何时可能更受欢迎来帮助读者。
m
malex

在 SQLite 中检查,您可以将以下简单查询与 GROUP BY 一起使用

SELECT MAX(DateCreated), *
FROM DocumentStatusLogs
GROUP BY DocumentID

这里 MAX 有助于从每个组中获取最大 DateCreated。

但似乎 MYSQL 没有将 *-columns 与 max DateCreated 的值相关联:(