为 SQL 中的时间序列数据创建滚动 window

Creating rolling window for time series data in SQL

我有一个关于在 SQL 中添加滚动 window 列的问题。 TableA是24个月时间序列数据的样本。我需要添加列以了解每个月余额与上个月和上个月之前的一个月之间的差异。例如,对于 2020 年 3 月,我需要为每个 ID (Table B) 分别区分 Mar 和 Feb 以及 Mar 和 Jan 的存款和取款。我尝试在 sql 中使用 'window' 函数,但我不知道如何使用。

 **Table A**
 ID      | Date      |A      | B       |
+--------+-----------+-------+---------
| 1      | Jan 20    | 0  | 0    |
| 1      | Feb 20    | 0  | 0    |
| 1      | Mar 20    | 00 | 0    | 
+--------+-----------+-------+---------+

我想要这样的结果:

 **Table B**
 ID      | Date      |A      | B       | A(Mar-Feb)| A(Mar-Jan)| B(Mar-Feb)| B(Mar-Jan)|
+--------+-----------+-------+------------------------------------------------------
| 1      | Jan 20    | 0  | 0    |            |           |          |           |
| 1      | Feb 20    | 0  | 0    |            |           |          |           |
| 1      | Mar 20    | 00 | 0    | 0       |0       |0      |0       |
+--------+-----------+-------+---------+------------+-----------+----------+-----------+

如果有人能帮助我,我将不胜感激。

已编辑:根据来自 OP

的更多信息,请参阅底部的编辑以获取更正答案

我“认为”这就是您所要求的,它可能并不完全是您想要的,因为它也填充了其他行...

IF OBJECT_ID('tempdb..#TableA','U') IS NOT NULL DROP TABLE #TableA; --SELECT * FROM #TableA
CREATE TABLE #TableA (
    ID     int  NOT NULL,
    [Date] date NOT NULL,
    A      int  NOT NULL,
    B      int  NOT NULL,
)

INSERT INTO #TableA (ID, Date, A, B)
VALUES (1, '2020-01-01',  200, 100)
    ,  (1, '2020-02-01',  500, 250)
    ,  (1, '2020-03-01', 1000, 550)

SELECT ta.ID
    , [Date] = FORMAT(ta.[Date],'MMM yy')
    , ta.A, ta.B
    , A_DiffPrev  = ta.A - LAG(ta.A)         OVER (ORDER BY ta.[Date])
    , A_DiffFirst = ta.A - FIRST_VALUE(ta.A) OVER (ORDER BY ta.[Date])
    , B_DiffPrev  = ta.B - LAG(ta.B)         OVER (ORDER BY ta.[Date])
    , B_DiffFirst = ta.B - FIRST_VALUE(ta.B) OVER (ORDER BY ta.[Date])
FROM #TableA ta

Returns:

| ID | Date   | A    | B   | A_DiffPrev | A_DiffFirst | B_DiffPrev | B_DiffFirst | 
|----|--------|------|-----|------------|-------------|------------|-------------| 
| 1  | Jan 20 | 200  | 100 | NULL       | 0           | NULL       | 0           | 
| 1  | Feb 20 | 500  | 250 | 300        | 300         | 150        | 150         | 
| 1  | Mar 20 | 1000 | 550 | 500        | 800         | 300        | 450         | 

说明

  • LAG(ta.A) OVER (ORDER BY ta.[Date]) - 这将为您提供按提供的 ORDER BY 排序的先前值。所以在这种情况下,它是说,如果您按 [Date] 升序
  • 排序,请给我出现在当前行之前的值
  • FIRST_VALUE(ta.A) OVER (ORDER BY ta.[Date]) - 与 LAG() 类似的想法,除了它说的是获取第一个项目,而不是上一个项目。

编辑

你在评论中提到FIRST_VALUE()对你不起作用,因为你不想与第一个月比较,你想与上个月和两个月前比较。

在这种情况下,您可以使用此解决方案:

SELECT ta.ID
    , [Date] = FORMAT(ta.[Date],'MMM yy')
    , ta.A, ta.B
    , A_DiffPrev1 = ta.A - LAG(ta.A,1) OVER (ORDER BY ta.[Date])
    , A_DiffPrev2 = ta.A - LAG(ta.A,2) OVER (ORDER BY ta.[Date])
    , B_DiffPrev1 = ta.B - LAG(ta.B,1) OVER (ORDER BY ta.[Date])
    , B_DiffPrev2 = ta.B - LAG(ta.B,2) OVER (ORDER BY ta.[Date])
FROM #TableA ta

解释:

在此更改中,我对所有内容都使用 LAG()。但相反,我告诉 LAG() 我希望它回顾多少行。

因此,为了获取前一个月,我说 LAG(A, 1) 这意味着获取前一行,这是默认设置,我在这里提供它只是为了更明确地说明发生了什么。

然后我说 LAG(A, 2) 这意味着返回两行并获取该值。

注意:这一切都是假设您的数据没有差距。