简体   繁体   English

SQL交叉申请

[英]SQL cross apply

I have a SQL table which contains audit information: 我有一个包含审计信息的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

and trying show the differences between the audit records: 并尝试显示审计记录之间的差异:

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

I am using the following SQL query: 我使用以下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;

Is it possible to merge two select queries to improve the performance? 是否可以合并两个选择查询以提高性能?

You can eliminate both subqueries entirely by using lag() : 您可以使用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 . 这是相关文档

Update: However, this is only available in SQL Server 2012, unfortunately. 更新:但是,不幸的是,这仅适用于SQL Server 2012。 If you have an earlier version, you will need some sort of self join. 如果您有早期版本,则需要某种自联接。

If you can't use lag() , you should at least be able to reduce your code from 3 queries to 2: include the row number in your first select statement, and left join one subquery to it rather than having two subqueries. 如果你不能使用lag() ,你至少应该能够将你的代码从3个查询减少到2:在你的第一个select语句中包含行号,并将一个子查询连接到它而不是有两个子查询。 I'm not sure whether this way or Chris Moutray's way would be faster. 我不确定这种方式或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
)

Try this query 试试这个查询

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;

Demo on SQLFiddle SQLFiddle上演示

You can use LAG in SQL Server 2012. I've used UNION ALL here to unpivot columns into rows. 您可以在SQL Server 2012中使用LAG。我在这里使用UNION ALL将列拆分为行。

Depending on how you filter and what your group level is, add/modify the PARTITION BY 根据您的过滤方式和组级别,添加/修改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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM