LAG/LEAD 相当于分组(SQL Server 2008 R2)

LAG/LEAD equivalent with grouping (SQL Server 2008 R2)

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

我需要更新 table 的列以包含 ProductID 的 'previous' 和 'next' 值 - table 需要存储 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

这些是结果,Lag/Lead 应用于所有行。

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 值进行分组,在 SalesOrderID 组中,第一次出现指向 NULL 的滞后,最后一次出现指向 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

您只需将 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