2015-11-07 12 views
0

我需要在MSSQL查詢返回以下結果返回不同的上次登錄日期:根據從最近的日期從下表

客戶端ID,用戶名,EVENTDATE

明顯的每個客戶端ID如下表所示:

Login History table

例如:鑑於上面的表格,返回:

450SB 2013-03-01 16:40:29 nevadan 
    LASB 2013-03 001 16:37:27 siteuser 

正想着,創造了一個光標:從表 DISTINCT客戶端Id和通過的maxDate的各只返回進入循環,但沒想到它 是非常有效的。

回答

0

可以使用CTE抓住每個客戶端的最新訪問日期,然後再加入回到了CTE來獲取每個客戶端的每個最新訪問日期的用戶名。如果您的表具有主鍵,則JOIN在性能,可讀性和優雅方面會更好。

;WITH latestClientAccess (ClientId, LatestEventDate) AS (
     SELECT ClientId, MAX(EventDate) 
     FROM MyTable 
     GROUP BY ClientId 
) 
SELECT t.ClientId, t.UserName, lca.LatestEventDate [EventDate] 
FROM MyTable t 
INNER JOIN latestClientAccess lca 
     ON t.ClientId=lca.ClientId 
      AND t.EventDate=lca.LatestEventDate 

通過運行下面的腳本可以執行上述概念和腳本的快速本地測試。這樣,任何查看此響應的人都可以測試,而無需創建任何模式。

declare @temp table(ClientId int, EventDate datetime, UserName varchar(20)) 

insert into @temp 
select 1, '2015-11-06 00:00:00', 'user1' 

insert into @temp 
select 2, '2015-11-06 00:01:00', 'user1' 

insert into @temp 
select 1, '2015-11-06 00:01:00', 'user2' 

insert into @temp 
select 1, '2015-11-06 00:03:00', 'user1' 

;WITH latestClientAccess (ClientId, LatestEventDate) AS (
     SELECT ClientId, MAX(EventDate) 
     FROM @temp 
     GROUP BY ClientId 
) 
SELECT t.ClientId, t.UserName, lca.LatestEventDate [EventDate] 
FROM @temp t 
INNER JOIN latestClientAccess lca 
     ON t.ClientId=lca.ClientId 
      AND t.EventDate=lca.LatestEventDate 

編輯

考慮你有一個主鍵和一個第二表的客戶名稱,考慮下面的腳本:

;WITH latestClientAccess (ClientId, HistoryId) AS (
     SELECT ClientId, MAX(HistoryId) 
     FROM MyTable 
     GROUP BY ClientId 
) 
SELECT ct.ClientName, t.UserName, t.EventDate 
FROM MyTable t 
INNER JOIN latestClientAccess lca 
     ON t.HistoryId=lca.HistoryId 
INNER JOIN MyClientTable ct 
     ON t.ClientId=ct.ClientId 

對於最新事件概念的快速測試(無客戶名稱):

declare @temp table(HistoryId int, ClientId int, EventDate datetime, UserName varchar(20)) 

insert into @temp 
select 1, 1, '2015-11-06 00:00:00', 'user1' 

insert into @temp 
select 2, 2, '2015-11-06 00:01:00', 'user1' 

insert into @temp 
select 3, 1, '2015-11-06 00:01:00', 'user2' 

insert into @temp 
select 4, 1, '2015-11-06 00:03:00', 'user1' 

;WITH latestClientAccess (ClientId, HistoryId) AS (
     SELECT ClientId, MAX(HistoryId) 
     FROM @temp 
     GROUP BY ClientId 
) 
SELECT t.ClientId, t.UserName, t.EventDate 
FROM @temp t 
INNER JOIN latestClientAccess lca 
     ON t.HistoryId=lca.HistoryId 
+0

它確實有一個主要的:歷史ID - 謝謝。 –

+0

如果HistoryID是一個不斷增加的標識字段,您可以使用MAX(HistoryID)而不是MAX(EventDate)。這可能會加快聯接的速度。 –

+0

謝謝你,先生。如果我想在查詢中返回一個更清晰的clientId名稱,它位於tableB中,作爲tableb.sccClientID = table.clientId上的sccCompanyName字段。我將如何修改您的查詢? –

0

我沒有在我的計算機上安裝MSSQL,因此我無法爲您測試此選項,但是我認爲您可以將「ORDERBY ASC eventdate」篩選器添加到您的SQL中,然後僅選擇第一行來實現您的目標。

因此,這將是像

SELECT DISTINCT客戶端Id FROM表 ORDER BY EVENTDATE

至於這是否是更有效的或不...我想你預訂購一定要看查詢執行計劃來查看MSSQL做什麼操作來執行查詢,性能可能不如您以前的那樣好,因爲這個SQL正在做一些額外的事情,那就是排序。

通過這種方法至少你不必自己認爲有效的排序算法,並將其保存的密碼算法和兩行的你時間思考:P

+0

Msg 145,Level 15,State 1,Lin e 1 如果指定了SELECT DISTINCT,則ORDER BY項目必須出現在選擇列表中。 –

+0

Ooops,我沒有太多的MSSQL經驗,但你可以嘗試使用GROUP BY而不是DISTINCT?所以像這樣的東西; 從表組中選擇ClientID,UserName,EventDate按ClientId排序由eventdate asc –

0

你所描述的是一個有點複雜人們會認爲,主要是因爲除了ClientID和EventDate之外,您還需要UserName。

這應該可以工作,雖然我沒有在本地構建您的模式來測試,所以讓我知道如果你有任何錯誤。

SELECT 
    t1.* 
FROM 
    SomeTable t1 
INNER JOIN 
    (
    SELECT 
     ClientId 
     MaxEventDate = MAX(EventDate) 
    FROM 
     SomeTable 
    GROUP BY 
     ClientId 
    ) t2 
ON 
    t1.ClientID = t2.ClientID 
    AND t1.EventDate = t2.EventDate 

...注意:如果你擺脫用戶名的,它只是:

SELECT 
    ClientId 
    MaxEventDate = MAX(EventDate) 
FROM 
    SomeTable 
GROUP BY 
    ClientId