在 Snowflake 中移动 window 不同大小的数字列求和

Summing over a numeric column with moving window of varying size in Snowflake

我有一个示例数据集,如下所示;

time  |  time_diff  | amount
time1 |  time1-time2 | 1000
time2 |  time2-time3 | 2000
time3 |  time3-time4 | 3000
time4 |  time4-time5 | 4500
time5 |   NULL       | 1000

快速解释;第一列给出交易时间,第二列给出与下一行的差异以获得交易间隔(以小时为单位),第三列给出在特定交易中赚取的钱。我们已使用时间列对数据进行升序排序。

一些值给出为;

time  |  time_diff  | amount
time1 |  2.         | 1000
time2 |  3.         | 2000
time3 |  1.         | 3000
time4 |  19.        | 4500
time5 |   NULL       | 1000

目标是查找给定时间的总交易,该交易发生在该交易的 24 小时内。例如,time1 的输出应该是; 1000+2000+3000=6000。因为如果我们加上 time4 的值,总的时间间隔就变成了 25,所以我们从总和中省略了 4500 的值。

示例输出:

time  |  amount
time1 | 6000       
time2 | 9500         
time3 | 7500         
time4 | 4500        
time5 | 1000

据我所知,Mong window sum 的概念应该有效,但此处 window 的宽度是可变的。这就是我面临的挑战 facing.Can 请在这里得到一些帮助?

您可以忽略 time_diff 列并使用基于时间戳范围的 theta 自连接,如下所示:

WITH srctab AS (    SELECT TO_TIMESTAMP_NTZ('2020-04-15 00:00:00') AS "time", 1000::INT AS "amount"
          UNION ALL SELECT TO_TIMESTAMP_NTZ('2020-04-15 00:02:00'), 2000::INT
          UNION ALL SELECT TO_TIMESTAMP_NTZ('2020-04-15 00:05:00'), 3000::INT
          UNION ALL SELECT TO_TIMESTAMP_NTZ('2020-04-15 00:06:00'), 4500::INT
          UNION ALL SELECT TO_TIMESTAMP_NTZ('2020-04-16 00:01:00'), 1000::INT
          )
SELECT t1."time", SUM(t2."amount") AS tot
FROM srctab t1
JOIN srctab t2 ON t2."time" BETWEEN t1."time" AND TIMESTAMPADD(HOUR, +24, t1."time")
GROUP BY t1."time"
ORDER BY t1."time";

次要细节:如果您的第二列给出了与 下一个 行的时差,那么我会说第一个值应该是 10500(而不是 6000),因为它只是您的第 5 个超过 24 小时的 1000 笔交易...我猜您的实际时间戳是在 0、2、5、6 和 25 小时?

另一种选择可能是使用 sliding WINDOW 函数,方法是调整您的交易数据以包括每小时。

这可能有点矫枉过正,但可能是一种有用的技术。

首先使用时间戳为每个小时生成一个占位符。我利用 time_slice to map each timestamp into nice hour blocks and generator with dateadd 每小时回填,在没有交易发生的地方填入零。

所以现在我可以使用滑动 window 功能,因为我知道我可以安全地选择前 23 个小时。

复制|粘贴|运行

WITH SRCTAB AS (
SELECT  TO_TIMESTAMP_NTZ('2020-04-15 00:00:00') AS TRANS_TS,   1000::INT AS AMOUNT
UNION ALL   SELECT  TO_TIMESTAMP_NTZ('2020-04-15 02:00:00'),  2000::INT
UNION ALL SELECT  TO_TIMESTAMP_NTZ('2020-04-15 05:00:00'), 3000::INT
UNION ALL SELECT TO_TIMESTAMP_NTZ('2020-04-15 06:00:00'),  4500::INT
UNION ALL  SELECT  TO_TIMESTAMP_NTZ('2020-04-16 01:00:00'), 1000::INT
)
SELECT 
    TRANS_TIME_HOUR 
    ,SUM(AMOUNT) OVER ( ORDER BY TRANS_TIME_HOUR ROWS BETWEEN 23 PRECEDING AND 0 PRECEDING ) OVERKILL FROM (
SELECT
    TRANS_TIME_HOUR,
    SUM(AMOUNT) AMOUNT
FROM
    (
    SELECT
        DATEADD(HOUR, NUMBER, TRANS_TS) TRANS_TIME_HOUR,
        DECODE( DATEADD(HOUR, NUMBER, TRANS_TS), TIME_SLICE(TRANS_TS, 1, 'HOUR', 'START'), AMOUNT,0) AMOUNT
    FROM
        SRCTAB,
        (SELECT SEQ4() NUMBER FROM TABLE(GENERATOR(ROWCOUNT => 24)) ) G
)
GROUP BY
    TRANS_TIME_HOUR
)