如何在SQL中获取每个组的最后一条记录

ble*_*ter 25 t-sql sql-server-2005 sql-server-2008 greatest-n-per-group

我面临着一个相当有趣的问题.我有一个具有以下结构的表:

CREATE TABLE [dbo].[Event]
(
    Id int IDENTITY(1,1) NOT NULL,
    ApplicationId nvarchar(32) NOT NULL,
    Name nvarchar(128) NOT NULL,
    Description nvarchar(256) NULL,
    Date nvarchar(16) NOT NULL,
    Time nvarchar(16) NOT NULL,
    EventType nvarchar(16) NOT NULL,
    CONSTRAINT Event_PK PRIMARY KEY CLUSTERED ( Id ) WITH (
        PAD_INDEX = OFF, 
        STATISTICS_NORECOMPUTE = OFF, 
        IGNORE_DUP_KEY = OFF, 
        ALLOW_ROW_LOCKS = ON, 
        ALLOW_PAGE_LOCKS  = ON
    )
)
Run Code Online (Sandbox Code Playgroud)

所以问题是我必须在网格中显示这些数据.有两个要求.第一个是显示所有事件,而不管是什么应用程序抛出它们.这很简单 - 选择语句可以非常轻松地完成工作.

第二个要求是能够按事件分组事件Application.换句话说,以一种方式显示所有事件,如果ApplicationId重复多次,则只获取每个应用程序的最后一个条目.此查询/视图中不再需要此时事件(Id)的主键.

您可能还注意到事件日期和时间是字符串格式.这没关系,因为它们遵循标准的日期时间格式:mm/dd/yyyy和hh:mm:ss.我可以按如下方式提取:

Convert( DateTime, (Date + ' ' +  Time)) AS 'TimeStamp'
Run Code Online (Sandbox Code Playgroud)

我的问题是,如果我在其余列上使用AGGREGATE函数,我不知道它们会如何表现:

SELECT
    ApplicationId,
    MAX(Name),
    MAX(Description),
    MAX( CONVERT(DateTime, (Date + ' ' + Time))) AS 'TimeStamp',
    MAX( EventType )
FROM
    Event
GROUP BY
    ApplicationId
Run Code Online (Sandbox Code Playgroud)

我犹豫不决的原因是因为诸如的函数MAX将从(子)记录集返回给定列的最大值.它没有必要拉最后一条记录!

关于如何根据每个应用程序仅选择最后一条记录的任何想法?

Ant*_*ull 43

您可以使用排名函数公用表表达式.

WITH e AS
(
     SELECT *,
         ROW_NUMBER() OVER
         (
             PARTITION BY ApplicationId
             ORDER BY CONVERT(datetime, [Date], 101) DESC, [Time] DESC
         ) AS Recency
     FROM [Event]
)
SELECT *
FROM e
WHERE Recency = 1
Run Code Online (Sandbox Code Playgroud)


tar*_*nov 8

从SQL Server 2012开始,您可以简单地完成

SELECT 
    [Month]
    , [First] = FIRST_VALUE(SUM([Clicks])) OVER (ORDER BY [Month])
    , [Last]  = FIRST_VALUE(SUM([Clicks])) OVER (ORDER BY [Month] DESC)
FROM 
    [dbo].[Table]
GROUP BY [Month]
ORDER BY [Month]
Run Code Online (Sandbox Code Playgroud)