Как получить последнюю запись в группе в SQL

я столкнулся с довольно интересной проблемой. У меня есть таблица со следующей структурой:

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
    )
)

Итак, проблема в том, что я должен отображать эти данные в сетке. Есть два требования. Первый-отобразить все события, независимо от того, какое приложение их кинул. Это просто-оператор select сделает эту работу очень легко.

второе требование-уметь группировать события по Application. Другими словами отображать все события таким образом, что если ApplicationId повторяется более одного раза, захватить только последнюю запись для каждого приложения. Первичный ключ события (Id) на данный момент больше не нужен в этом запросе/представлении.

вы также можете заметить, что дата и время события находятся в строковом формате. Это нормально, потому что они следуют стандартным форматам даты: mm/dd/yyyy и hh:mm:ss. Я могу вытащить их следующим образом:

Convert( DateTime, (Date + ' ' +  Time)) AS 'TimeStamp'

моя проблема в том, что если я использую агрегатные функции на остальных столбцах, я не знаю, как будут ли они себя вести:

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

причина, по которой я не решаюсь сделать это, заключается в том, что такая функция, как MAX возвращает наибольшее значение для данного столбца из (sub)набора записей. Не надо тянуть последнюю запись!

любые идеи о том, как выбрать только последние записи на основе каждого приложения?

8 ответов


вы можете использовать ранжирующая функция и a общее табличное выражение.

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

С 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]

SELECT
    E.ApplicationId,
    E.Name,
    E.Description,
    CONVERT(DateTime, (E.Date + ' ' + E.Time)) AS 'TimeStamp',
    E.EventType
FROM
    Event E
    JOIN (SELECT ApplicationId,
                 MAX(CONVERT(DateTime, (Date + ' ' + Time))) AS max_date
            FROM Event
        GROUP BY ApplicationId) EM 
      on EM.ApplicationId = E.ApplicationId
     and EM.max_date = CONVERT(DateTime, (E.Date + ' ' + E.Time)))

вы можете использовать subqery или КТР стол для этого:

;WITH CTE_LatestEvents as (
SELECT
    ApplicationId,    
    MAX( CONVERT(DateTime, (Date + ' ' + Time))) AS 'LatestTimeStamp',
FROM
    Event
GROUP BY
    ApplicationId
)
SELECT
    ApplicationId,
    Name,
    Description,
    CONVERT(DateTime, (Date + ' ' + Time))) AS 'TimeStamp',
    EventType
FROM
    Event e
    Join CTE_LatestEvents le 
        on e.applicationid = le.applicationid
        and CONVERT(DateTime, (e.Date + ' ' + e.Time))) = le.LatestTimeStamp

потому что у вас нет предложения where, подмножество записей-это все записи. Но вы ставите max на неправильный столбец(ы), я думаю. Этот запрос даст вам то, что вы ищете.

Select max(applicationid), name, description, CONVERT(DateTime, (Date + ' ' + Time)) 
from event
group by name, description, CONVERT(DateTime, (Date + ' ' + Time)) 

вы можете использовать суб-запрос с group by - аргумент group by не должен быть в select. Это предполагает, что Id автоматически увеличивается, так что самый большой из них является самым последним.

SELECT
    ApplicationId,
    Name,
    Description,
    CONVERT(DateTime, (Date + ' ' + Time)) AS 'TimeStamp',
    EventType
FROM
    Event e
WHERE
    Id in (select max(Id) from Event GROUP BY ApplicationId)

Я думаю, что это будет работать для многих, желающих получить последнюю вставленную запись, и она должна быть group by:

select * from (select * from tableName ORDER by id DESC) AS X GROUP BY FieldName

Он будет работать для следующего:

Структура Таблицы Статус ID имя 1 Junaid Да 2 Jawad No 3 Фахад Да 4 Junaid No 5 Кашиф Да

Результаты После Запроса Выше ID имя Статус 4 Junaid No 2 Jawad No 3 Фахад Да 4 Кашиф Да

это просто результат последней записи группы по именам.


через 6 лет другой ответ для SQL Server:

select t1.[Id], t2.[Value]  
from [dbo].[Table] t1  
  outer apply (  
    select top 1 [Value]  
      from [dbo].[Table] t2  
        where t2.[Month]=t1.[Month]  
      order by [dbo].[Date] desc  
  )  

хотя мне нравится решение Postgresql намного лучше с его отличной функцией, которая приятнее для ввода и намного эффективнее:

select distinct on (id),val  
from tbl  
order by id,val