【问题标题】:Selecting the last day price by using LAG() function使用 LAG() 函数选择最后一天的价格
【发布时间】:2021-01-27 09:45:47
【问题描述】:

我有一个用户事务表,其中包含用户 ID、日期、项目 ID、价格和 prev_day_price 列。 示例是:

userid date itemid price prev_day_price
1 2020-12-26 archicad 1400.0
1 2020-12-26 archicad 1400.0
1 2020-12-24 archicad 1200.0
1 2020-12-23 archicad 1240.0
1 2020-12-23 archicad 1240.0
1 2020-12-21 archicad 1100.0

我需要找到每件商品的前一天(最后一天)价格。我想应用滞后功能,但也想应用 group by,这样我就可以通过 userid 和 itemid 找到以前的价格。因为我的桌子有些日子有一个以上的行\按项目的价格,它不会在 24-12-2020 - 25-12-2020 - 26-12-2020 继续。

userid date itemid price prev_day_price
1 2020-12-26 archicad 1400.0
1 2020-12-26 archicad 1400.0

现在,它开始让我对使用延迟功能感到困惑和融化。在更新 prev_day_price 列之前,我尝试按滞后函数查看预览结果:

SELECT*,
  lag(price) OVER (PARTITION BY itemid, date, userid) AS prev_day_price 
FROM userlog

但结果是:

userid date itemid price prev_day_price prev_day_price
1 2020-12-21 archicad 1100.0
1 2020-12-24 archicad 1200.0
1 2020-12-24 archicad 1200.0 1200.0
1 2020-12-24 archicad 1200.0 1200.0
1 2020-12-26 archicad 1400.0
1 2020-12-26 archicad 1400.0 1400.0

看来我的查询无法正常工作。我想所以我错过了一些重要的事情。我的预期结果如下:

userid date itemid price prev_day_price
1 2020-12-26 archicad 1400.0 1200
1 2020-12-26 archicad 1400.0 1200
1 2020-12-24 archicad 1200.0 1240
1 2020-12-23 archicad 1240.0 1100
1 2020-12-23 archicad 1240.0 1100
1 2020-12-21 archicad 1100.0 1100

我尝试使用 lag(price,1) 而不是 lag(price) 来抵消 0 并将默认设置为 0,但它也不起作用。输出格式不是太重要,只要我最终能把它变成一个数组。我正在使用 Postgres。提前致谢。

【问题讨论】:

    标签: postgresql


    【解决方案1】:

    为什么您的解决方案不能正常工作?

    lag() 以及所有其他窗口函数都在您定义的窗口上工作。在您的情况下,您可以定义一个分区窗口,一个组。 lag() 函数仅在该组内执行,而不是在组上执行。因此,它返回分区的先前值。例如。对于2020-12-26,它为第一条记录返回NULL(因为在第一条记录之前没有前一条记录)以及第二条记录中第一条记录的值。但这在每个 date 组中单独发生。这解释了你的结果。


    Postgres 11+ 的解决方案:

    demo:db<>fiddle

    SELECT
        *,
        first_value(price) OVER (
            ORDER BY itemid, userid, mydate 
            GROUPS BETWEEN 1 PRECEDING AND CURRENT ROW
        ) AS prev_day_price 
    FROM userlog
    

    您必须定义另一个窗口,您可以在其上执行操作。最好将当前日期组和上一个日期组中的所有记录捆绑在一起,而不是单独窗口化所有日期。这正是GROUPS 窗口的用途。使用该组,您可以按日期对记录进行排序并获取第一个值。这正是您所期望的。


    Postgres 版本 的解决方案:

    (不支持GROUPS windows 和PRECEDING != UNBOUNDED

    step-by-step demo:db<>fiddle

    SELECT
        u.itemid,
        u.mydate,
        u.userid,
        s.price                                          -- 5
    FROM userlog u
    JOIN (                                               -- 4
        SELECT
            itemid, mydate, userid,
            COALESCE(                                    -- 3
                 lag(price) OVER (PARTITION BY itemid, userid ORDER BY mydate),  -- 2
                 price
            ) as price
        FROM (
            SELECT
                itemid, mydate, userid,
                MAX(price) as price                      -- 1
            FROM userlog
            GROUP BY itemid, mydate, userid
        ) s
    ) s USING (itemid, mydate, userid)
    
    1. 将所有组减少到一条记录,例如与组和聚合。另一个机会可能是使用SELECT DISTINCT ON (itemid, mydate, userid)
    2. 使用lag() 函数在每个组中移动前一个price(好吧,只有itemid/userid 组,mydate 列必须仅用于排序!)使用lag() 函数
    3. 因为第一个记录没有以前的记录,所以将采用当前记录。这就是 COALESCE() 函数的作用。
    4. 将此结果加入您的原始表并...
    5. ... 从中返回“滞后”price

    【讨论】:

    • 很抱歉,我对您非常完美的答案的回复晚了。工作有点忙。是的,这就是我想要的。我只需要进行一些更改即可用于更新单元格。我将尝试使用 UPDATE 运算符来做到这一点。
    猜你喜欢
    • 1970-01-01
    • 2019-01-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-16
    • 2016-11-30
    • 2011-08-30
    • 1970-01-01
    相关资源
    最近更新 更多