【问题标题】:LAG/LEAD equivalent with grouping (SQL Server 2008 R2)LAG/LEAD 等效于分组 (SQL Server 2008 R2)
【发布时间】:2016-01-21 20:39:13
【问题描述】:

注意:我使用的是 SQL Server 2008 R2,内置的 LEAD/LAG 函数不可用。

我需要更新表的列以包含 ProductID 的“上一个”和“下一个”值 - 该表需要存储 PrevProductID (LAG)、ProductID 和 NextProductID (LEAD)。下面的代码很好地做到了这一点,并改编自 Geri Reshef 对http://blog.sqlauthority.com/2011/11/24/sql-server-solution-to-puzzle-simulate-lead-and-lag-without-using-sql-server-2012-analytic-function/的回答

USE AdventureWorks2008R2
GO
WITH T1 AS
(   SELECT Row_Number() OVER(ORDER BY SalesOrderID,ProductID) N,
        s.SalesOrderID,
        s.ProductID
    FROM Sales.SalesOrderDetail s
    WHERE SalesOrderID IN (43670, 43667, 43663)
)
SELECT SalesOrderID,
    CASE WHEN N%2=1 
    THEN MAX(CASE WHEN N%2=0 
            THEN ProductID 
        END) OVER (Partition BY N/2) 
        ELSE MAX(CASE WHEN N%2=1 
            THEN ProductID 
        END) OVER (Partition BY (N+1)/2) 
    END PrevProductID,
ProductID,
CASE WHEN N%2=1 
    THEN MAX(CASE WHEN N%2=0 
            THEN ProductID 
        END) OVER (Partition BY (N+1)/2) 
        ELSE MAX(CASE 
            WHEN N%2=1 THEN ProductID 
        END) OVER (Partition BY N/2) 
    END NextProductID
FROM T1
ORDER BY 
    t1.SalesOrderID,
    t1.ProductID

这些是结果,滞后/领先应用于所有行。

SalesOrderID PrevProductID ProductID   NextProductID
------------ ------------- ----------- -------------
43663        NULL          760         710
43667        760           710         773
43667        710           773         775
43667        773           775         778
43667        775           778         709
43670        778           709         710
43670        709           710         773
43670        710           773         776
43670        773           776         NULL

我需要做的是按 SalesOrderID 对 Lag/Lead 值进行分组,第一次出现指向 NULL 的 Lag,最后一次出现指向 SalesOrderID 组中的 Lead NULL。

SalesOrderID PrevProductID ProductID   NextProductID
------------ ------------- ----------- -------------
43663        NULL          760         NULL
43667        NULL          710         773
43667        710           773         775
43667        773           775         778
43667        775           778         NULL
43670        NULL          709         710
43670        709           710         773
43670        710           773         776
43670        773           776         NULL

【问题讨论】:

    标签: sql-server sql-server-2008-r2 lag lead


    【解决方案1】:

    您只需将SalesOrderID 添加到查询中的每个PARTITION BY 子句中即可(ROW_NUMBER() OVER(),然后是 4 x MAX() OVER()):

    WITH T1 AS
    (   SELECT  SalesOrderID, 
                ProductID, 
                N = ROW_NUMBER() OVER(PARTITION BY SalesOrderID ORDER BY SalesOrderID, ProductID)
        FROM    (VALUES 
                    (43663, 760), (43667, 710), (43667, 773), (43667, 775), (43667, 778), 
                    (43670, 709), (43670, 710), (43670, 773), (43670,  776),
                    (43680,  1), (43680,  2), (43680,  3), (43680,  4), (43680,  5),
                    (43680,  6), (43680,  7), (43680,  8), (43680,  9), (43680,  10),
                    (43681,  1), (43681,  2), (43681,  3), (43681,  4), (43681,  5),
                    (43681,  6), (43681,  7), (43681,  8), (43681,  9), (43681,  10)
                ) x (SalesOrderID, ProductID)
    )
    SELECT  T1.SalesOrderID,
            PrevProductID = CASE WHEN N % 2 = 1
                                THEN MAX(CASE WHEN N % 2 = 0 THEN T1.ProductID END)
                                        OVER(PARTITION BY T1.SalesOrderID, N / 2)
                                ELSE 
                                    MAX(CASE WHEN N % 2 = 1 THEN ProductID END)
                                        OVER(PARTITION BY T1.SalesOrderID, (N + 1) / 2)
                            END,
            T1.ProductID,
            NextProductID = CASE WHEN N % 2 = 1
                                THEN MAX(CASE WHEN N % 2 = 0 THEN T1.ProductID END)
                                        OVER(PARTITION BY T1.SalesOrderID, (N + 1) / 2)
                                ELSE 
                                    MAX(CASE WHEN N % 2 = 1 THEN ProductID END)
                                        OVER(PARTITION BY T1.SalesOrderID, N / 2)
                            END
    FROM    T1;
    

    其中(不包括我为进一步测试添加的其他行)产生:

    SalesOrderID    PrevProductID   ProductID   NextProductID
    ---------------------------------------------------------------
    43663           NULL            760             NULL
    43667           NULL            710             773
    43667           710             773             775
    43667           773             775             778
    43667           775             778             NULL
    43670           NULL            709             710
    43670           709             710             773
    43670           710             773             776
    43670           773             776             NULL    
    

    【讨论】:

    • 谢谢,别名后面的列列表有什么作用吗?还是只是为了文档? FROM (VALUES ...) x (SalesOrderID, ProductID)
    • 它是table value constructor 的一部分,我只是用它来生成一些用于测试目的的数据,因为我没有你的表可以使用。
    猜你喜欢
    • 1970-01-01
    • 2018-12-12
    • 2014-08-02
    • 1970-01-01
    • 2011-06-19
    • 1970-01-01
    • 1970-01-01
    • 2011-06-26
    • 1970-01-01
    相关资源
    最近更新 更多