2011-06-01 143 views
23

我正面臨一個相當有趣的問題。我有一個表結構如下:如何在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 
    ) 
) 

所以問題是,我必須在網格中顯示此數據。有兩個要求。第一個是顯示所有事件,而不管應用程序拋出它們。這很簡單 - 選擇語句將很容易地完成這項工作。

第二個要求是能夠按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這樣的函數會從(子)記錄集中返回給定列的最大值。它不需要拉最後的記錄!

關於如何在每個應用程序的基礎上只選擇最後一條記錄的想法?

+2

使用窗口函數(在Oracle中,所以像row_number()over(partition by ...),AFAIK SQL服務器具有類似的功能。 – 2011-06-01 12:42:59

回答

40

您可以使用ranking functioncommon table expression

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 
+0

由於'mm/dd/yyyy'格式不能正確排序爲字符串,因此您不能只按日期和時間排序而不轉換爲日期時間值。 – 2011-06-01 12:56:21

+1

謝謝@Anthony Faull。這工作,但我不明白如何。 – bleepzter 2011-06-01 12:56:54

+0

@damien好的。我已更新ORDER BY子句將美國日期(月 - 日 - 年)轉換爲可排序的日期。 – 2011-06-01 13:11:56

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

因爲你沒有在那裏where子句,記錄的子集,是所有記錄。但是,你正在對我認爲錯誤的列進行最大限度的處理。這個查詢會給你你想要的。

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

您可以使用subqery或CTE表來做到這一點:

;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 
0

您可以通過使用子查詢與組 - 組通過爭論並不需要在選擇。這假設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) 
0

,我認爲它會爲許多工作在那裏願意獲取最後插入的記錄,它應該由組:

SELECT * FROM(SELECT * FROM表名ORDER BY ID DESC)爲X GROUP BY字段名

它將以下工作:

表結構 ID名稱狀態 1朱奈德是 2賈瓦德否 3法赫德是 4朱奈德否 5卡希夫是

結果上述查詢 ID名稱狀態後 4朱奈德否 2賈瓦德否 3法赫德是 4卡希夫是

它只是產生組名稱的最後一個記錄。

6

由於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] 
+2

當然也有LAST_VALUE – sehe 2014-09-09 14:31:36

0

經過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 
相關問題