在不规则时间序列上使用 LEAD 和 LAG

问题描述 投票:0回答:1

我有一个大数据集,想要检索小窗口的先前和后续观察结果。以下是有关感兴趣窗口的片段(2024-09-23 至 2024-09-27)。

item    date    price
A   2024-09-20   $106.59 
A   2024-09-23   $91.84 
A   2024-09-24   $92.66 
A   2024-09-25   $107.87 
A   2024-09-26   $98.47 
A   2024-09-27   $91.65 
A   2024-09-30   $108.10 
B   2024-07-29   $120.71 
B   2024-08-13   $87.80 
B   2024-09-04   $115.80 
B   2024-09-26   $94.06 
B   2024-09-27   $120.88 

在上面的示例中,“A”每个工作日都有价格,但“B”的价格不常见。正如预期(但不是期望),下面的代码在所需窗口的开头和结尾处生成 NULL 值(在 WHERE 语句中指定)。

SELECT item, date, price,
    lag(price) OVER (PARTITION BY item ORDER BY date) as prevprice,
    lead(price) OVER (PARTITION BY item ORDER BY date) as nextprice
FROM dailytable
WHERE date BETWEEN date'2024-09-23' AND date'2024-09-27'
;

结果 - 不想要

item    date    price   prevprice   nextprice
A   2024-09-23   $91.84      NULL    $92.66 
A   2024-09-24   $92.66      $91.84      $107.87 
A   2024-09-25   $107.87     $92.66      $98.47 
A   2024-09-26   $98.47      $107.87     $91.65 
A   2024-09-27   $91.65      $98.47      NULL 
B   2024-09-26   $94.06      NULL    $120.88 
B   2024-09-27   $120.88     $94.06      NULL 

显然,我可以在子查询中对整个数据集运行 LEAD() 和 LAG(),然后使用 WHERE 语句从中进行选择,如下所示。

SELECT * 
FROM 
(   SELECT item, date, price,
        lag(price) OVER (PARTITION BY item ORDER BY date) as prevprice,
        lead(price) OVER (PARTITION BY item ORDER BY date) as nextprice
    FROM dailytable
)
WHERE date BETWEEN date'2024-09-23' AND date'2024-09-27'
;

期望的结果

item    date    price   prevprice   nextprice
A   2024-09-23   $91.84      $106.59     $92.66 
A   2024-09-24   $92.66      $91.84      $107.87 
A   2024-09-25   $107.87     $92.66      $98.47 
A   2024-09-26   $98.47      $107.87     $91.65 
A   2024-09-27   $91.65      $98.47      $108.10 
B   2024-09-26   $94.06      $115.80     $120.88 
B   2024-09-27   $120.88     $94.06      NULL 

但是,这是非常昂贵的并且需要很长时间。整个数据集有超过 50 年的数据,但所需的超前和滞后期从来没有那么长。

有没有一种方法可以获取窗口的先前和后续价格,而无需运行在数据集的整个历史上运行的子查询?当然,如果一个物品没有下一个价格,就像上面例子中的 B 一样,我不指望有什么神奇的效果; NULL 是合适的。

sql time-series lag trino lead
1个回答
0
投票

我建议使用 case 表达式,当 prevprice 为空时运行相关子查询,并且该子查询查找紧邻的前一个价格,尽管应用了总体日期范围。例如:

SELECT
      item
    , DATE
    , price
    , CASE 
        WHEN prevprice IS NULL
            THEN (
                    select t.price FROM dailytable as t
                    where t.item = dailytable.item
                    and t.DATE < dailytable.DATE
                    order by t.DATE DESC
                    limit 1
                    )
        ELSE prevprice
        END AS prevprice
    , nextprice
FROM (
    SELECT
          item
        , DATE
        , price
        , lag(price) OVER (PARTITION BY item ORDER BY DATE) AS prevprice
        , lead(price) OVER (PARTITION BY item ORDER BY DATE) AS nextprice
    FROM dailytable
    WHERE DATE BETWEEN DATE '2024-09-23'
            AND DATE '2024-09-27'
    ) subquery

nb 我不确定 trino 语法将有序子查询限制到第一行,并且无法测试上面的查询。

© www.soinside.com 2019 - 2024. All rights reserved.