当前 + 前 X N 行的总和

Sum of Current + Previous X Nth Rows

我想求出当前 + 最后 X N 行的总和。我可以使用以下查询来执行此操作,但它的可扩展性不是很好。

SELECT [id], [amount] + LAG([amount],6) OVER(ORDER BY [id]) + LAG([amount],12) OVER(ORDER BY [id]) + LAG([amount],18) OVER(ORDER BY [id])

在这个例子中,我找到了“金额”的当前值,加上最后 3 个“金额”分成 6 个:

我将在动态查询中使用这些,并且不想每次都构建如此复杂的查询。某些查询中可能存在许多“滞后”。是否有另一种编写此查询的方法更具可扩展性?

源数据

ID Amount
1 107.35
2 105.41
3 104.63
4 106.7
5 108.7
6 110.21
7 108.8
8 108.91
9 108.5
10 106.66
11 105.2
12 106.5
13 108.27
14 109.72
15 111.53
16 112.8
17 109.03
18 115.31
19 115.56
20 116.85
21 116.08
22 117.61
23 118.31
24 119.25
25 118.45
26 118.43
27 120.16
28 122.5
29 125.57
30 125.65

预期结果

ID SUM OF LAST 4
1 NULL
2 NULL
3 NULL
4 NULL
5 NULL
6 NULL
7 NULL
8 NULL
9 NULL
10 NULL
11 NULL
12 NULL
13 NULL
14 NULL
15 NULL
16 NULL
17 NULL
18 NULL
19 439.98
20 440.89
21 440.74
22 443.77
23 441.24
24 451.27
25 451.08
26 453.91
27 456.27
28 459.57
29 458.11
30 466.71

最好的猜测,你想要的似乎是这样的:

DECLARE @X int = 3,
        @N int = 6;

SELECT YT.ID,
       YT.Amount,
       CASE WHEN ROW_NUMBER() OVER (PARTITION BY G.Grp ORDER BY ID) < @X+1 THEN NULL
            ELSE SUM(Amount) OVER (PARTITION BY G.Grp ORDER BY ID
                                   ROWS BETWEEN 3 PRECEDING AND CURRENT ROW)
       END
FROM dbo.YourTable YT
     CROSS APPLY (VALUES(ID % @N))G(Grp)
ORDER BY YT.ID;

但是,您会注意到,3 被硬编码在一处,因为您不能为 ROWS BETWEEN 子句使用变量。如果你需要参数化这个,你需要使用动态 SQL:

DECLARE @X int = 3,
        @N int = 6;

DECLARE @SQL nvarchar(MAX),
        @CRLF nchar(2) = NCHAR(13) + NCHAR(10);

SET @SQL = CONCAT(N'SELECT YT.ID,', @CRLF,
                  N'       YT.Amount,', @CRLF,
                  N'       CASE WHEN ROW_NUMBER() OVER (PARTITION BY G.Grp ORDER BY ID) < @X+1 THEN NULL', @CRLF,
                  N'            ELSE SUM(Amount) OVER (PARTITION BY G.Grp ORDER BY ID', @CRLF,
                  N'                                   ROWS BETWEEN ',@X,N' PRECEDING AND CURRENT ROW)', @CRLF, --I don't like injecting raw values, but if @X is an int, it is "safe"
                  N'       END', @CRLF,
                  N'FROM dbo.YourTable YT', @CRLF,
                  N'     CROSS APPLY (VALUES(ID % @N))G(Grp)', @CRLF,
                  N'ORDER BY YT.ID;');
PRINT @SQL; --Your best debugging friend

EXEC sys.sp_executesql @SQL, N'@X int, @N int', @X, @N;

db<>fiddle