2013-02-28 56 views
1

我有一個包含審計信息的SQL表:SQL CROSS APPLY

GroupId AuditDate ID FirstName LastName 
1  01/06/2011 123 Michael Jackson 
1  01/09/2010 123 M   J 
1  01/06/2009 123 Mike  J 

,並試圖顯示審計記錄之間的差異:我使用下面的SQL查詢

GroupId AuditDate ID Attribute From To 
1  01/06/2011 123 FirstName M  Michael 
1  01/06/2011 123 LastName J  Jackson 
1  01/09/2010 123 FirstName Mike M 
1  01/06/2009 123 FirstName NULL Mike 
1  01/06/2009 123 LastName NULL J 

WITH result AS (
SELECT   [Current].Id, 
       [Current].GroupId, 
       [Current].AuditDate, 
       [Current].FirstName, 
       [Current].LastName 
       Previous.FirstName AS PFirstName, 
       Previous.LastName AS PLastName, 
FROM 
    (SELECT 
     *, ROW_NUMBER() OVER(PARTITION BY GroupId ORDER BY AuditDate ASC) AS RowNumber 
    FROM 
     AuditTable 
    WHERE 
     Id = @ID 
    ) AS [Current] 
LEFT JOIN 
    (SELECT 
     *, ROW_NUMBER() OVER(PARTITION BY GroupId ORDER BY AuditDate ASC) AS RowNumber 
    FROM 
     AuditTable 
    WHERE 
     Id = @ID 
    ) AS [Previous] 
ON 
    [Current].RowNumber = [Previous].RowNumber + 1 
) 

SELECT r.Id,r.GroupId, r.AuditDate 
    x.Attribute, 
    x.[From], 
    x.[To] 
FROM result r 
CROSS APPLY 
(
    VALUES 
     ('FirstName', t.FirstName, t.PFirstName), 
     ('LastName', t.LastName, t.PLastName), 
) x (Attribute, [To], [From]) 
where 
    ISNULL(x.[From],'') <> ISNULL(x.[To],'') 
ORDER BY r.AuditDate asc; 

是否可以合併兩個select查詢來提高性能?

+0

您遇到的性能問題,或者你只是想要儘可能快的原則呢? – JNK 2013-02-28 13:53:15

+0

您是否在使用SQL Server 2012? – gbn 2013-02-28 13:59:05

+0

和你想要的結果是什麼? – 2013-02-28 14:13:39

回答

1

嘗試此查詢

WITH result AS (
SELECT Id, 
     GroupId, 
     AuditDate, 
     FirstName, 
     LastName,   
     ROW_NUMBER() OVER(PARTITION BY GroupId ORDER BY AuditDate ASC) AS RowNumber 
FROM AuditTable 
WHERE Id = @ID 
) 
SELECT r.Id,r.GroupId, r.AuditDate, 
     x.Attribute, 
     x.[From], 
     x.[To] 
FROM result r LEFT JOIN result r2 ON r.RowNumber = r2.RowNumber + 1 
CROSS APPLY (
      VALUES ('FirstName', r.FirstName, r2.FirstName), 
        ('LastName', r.LastName, r2.LastName) 
      ) x (Attribute, [To], [From]) 
WHERE ISNULL(x.[From],'') <> ISNULL(x.[To],'') 
ORDER BY r.AuditDate ASC; 

演示上SQLFiddle

+0

謝謝亞歷山大。我還可以用實際結果查詢替換「result r LEFT JOIN result r2」,將它們合併爲一個查詢。 – developer 2013-02-28 15:20:17

+0

沒問題;)... – 2013-02-28 15:28:39

1

您可以完全使用lag()消除兩個子查詢:

WITH result AS (
SELECT Id, 
     GroupId, 
     AuditDate, 
     FirstName, 
     LastName, 
     lag(FirstName) over (PARTITION BY GroupId ORDER BY AuditDate ASC) 
      AS PFirstName, 
     lag(LastName) over (PARTITION BY GroupId ORDER BY AuditDate ASC) 
      AS PLastName 
    FROM AuditTable 
    WHERE Id = @ID 
) 
... 

Here is the relevant documentation

更新:但是,這僅在SQL Server 2012中可用,不幸的是。如果你有一個更早的版本,你需要某種自我加入。

如果您不能使用lag(),你應該至少能減少你的代碼從3個查詢2:在您的第一select語句行號,並留下一個加入子查詢它,而不是兩個子查詢。我不確定這樣做還是Chris Moutray的方式會更快。

WITH result AS (
SELECT ROW_NUMBER() OVER(PARTITION BY GroupId ORDER BY AuditDate ASC) AS RowNumber   
     [Current].Id, 
     [Current].GroupId, 
     [Current].AuditDate, 
     [Current].FirstName, 
     [Current].LastName 
     [Previous].FirstName AS PFirstName, 
     [Previous].LastName AS PLastName, 
FROM AuditTable as [Current] 
LEFT JOIN 
    (SELECT 
     *, ROW_NUMBER() OVER(PARTITION BY GroupId ORDER BY AuditDate ASC) AS RowNumber 
    FROM 
     AuditTable 
    WHERE 
     Id = @ID 
    ) AS [Previous] 
ON 
    [Current].RowNumber = [Previous].RowNumber + 1 
) 
+0

感謝您的回覆,不幸的是我使用的SQL Server 2008,所以我不能使用lag(),所以我必須使用自聯接(如你所說)。 – developer 2013-02-28 15:22:28

1

您可以在SQL Server 2012中使用LAG我使用UNION ALL這裏UNPIVOT列成行。

您可以根據自己篩選和你的小組級別是什麼,添加/修改分區BY

DECLARE @foo TABLE (GroupId tinyint, AuditDate date, ID tinyint, FirstName varchar(100), LastName varchar(100)); 
INSERT @foo VALUES (1, '20110601', 123, 'Michael', 'Jackson'), (1, '20100901', 123, 'M', 'J'), (1, '20090601', 123, 'Mike', 'J'); 

SELECT 
    X.GroupId, X.AuditDate, X.ID, X.[From], X.[To] 
FROM 
    (
    SELECT 
     F.GroupId, F.AuditDate, F.ID, 'FirstName' AS Attribute, LAG(F.FirstName) OVER (/*PARTITION BY GroupId, ID*/ ORDER BY AuditDate) AS [From], F.FirstName AS [To] 
    FROM 
     @foo F 
    UNION ALL 
    SELECT 
     F.GroupId, F.AuditDate, F.ID, 'LastName' AS Attribute, LAG(F.LastName) OVER (/*PARTITION BY GroupId, ID*/ ORDER BY AuditDate) AS [From], F.LastName AS [To] 
    FROM 
     @foo F 
    ) X 
WHERE 
    ISNULL(X.[From], '') <> ISNULL(X.[To], '') 
ORDER BY 
    X.AuditDate DESC, X.Attribute 
+0

感謝您的回覆。我正在使用SQL Server 2008,所以我不能使用LAG(),但知道這種功能很有用。 – developer 2013-02-28 15:23:26