1

監査情報を含むSQLテーブルがあります。

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

監査レコード間の違いを表示しようとしています。

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

次のSQLクエリを使用しています。

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;

パフォーマンスを向上させるために2つの選択クエリをマージすることは可能ですか?

4

3 に答える 3

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

関連するドキュメントは次のとおりです。

更新:ただし、残念ながら、これはSQLServer2012でのみ使用できます。以前のバージョンを使用している場合は、何らかの自己参加が必要になります。

を使用できない場合lag()は、少なくともコードを3クエリから2に減らすことができるはずです。最初のselectステートメントに行番号を含め、2つのサブクエリではなく、1つのサブクエリをその行に結合したままにします。この方法とChrisMoutrayの方法のどちらが速いかはわかりません。

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
)
于 2013-02-28T14:01:07.457 に答える
1

SQL Server2012ではLAGを使用できます。ここではUNIONALLを使用して、列を行にピボット解除しました。

フィルタリングの方法とグループレベルに応じて、PARTITIONBYを追加/変更します。

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
于 2013-02-28T14:17:43.400 に答える
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のデモ

于 2013-02-28T14:12:43.473 に答える