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;

是否可以合并两个选择查询以提高性能?

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

这是相关文档

更新:但是,不幸的是,这仅在 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
)
于 2013-02-28T14:01:07.457 回答
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 回答
1

您可以在 SQL Server 2012 中使用 LAG。我在这里使用 UNION ALL 将列取消透视为行。

根据您的过滤方式和组级别,添加/修改 PARTITION 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
于 2013-02-28T14:17:43.400 回答