SQL交叉应用

SQL交叉应用,sql,tsql,cross-apply,Sql,Tsql,Cross Apply,我有一个包含审核信息的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

我有一个包含审核信息的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;

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

您可以使用lag完全消除两个子查询:

更新:但是,不幸的是,这仅在SQL Server 2012中可用。如果您有早期版本,则需要某种类型的自联接

如果不能使用lag,至少应该能够将代码从3个查询减少到2个:在第一个select语句中包含行号,并将一个子查询左键连接到它,而不是有两个子查询。我不确定这条路还是克里斯·莫塔利的路会更快

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
)
请尝试此查询

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;

演示

您可以在SQL Server 2012中使用LAG。我在这里使用UNION ALL将列解压成行

根据您的筛选方式和组级别,按添加/修改分区

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

您是否有性能问题,或者您只是希望在原则上尽可能快地使用它?您是否使用SQL Server 2012?您期望的结果是什么?谢谢Alexander。我也可以用实际的结果查询替换结果r左连接结果r2,将它们合并为一个查询。感谢回复,很遗憾,我使用的是SQL Server 2008,因此我不能使用lag,所以我必须使用您提到的自连接。感谢回复。我使用的是SQLServer2008,所以我不能使用LAG,但了解这样的功能很有用。
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