【问题标题】:Using lag and lead function for multiple partitions对多个分区使用滞后和领先功能
【发布时间】:2022-06-23 01:51:14
【问题描述】:

输入

month       seller product amount
2021-10-01    A     corn    20€
2021-10-02    A     corn    40€
2021-10-02    B     grain   30€  
2021-10-03    B     grain   10€     
2021-10-03    A     corn    null    
      .....

我想统计每个月与上个月农产品采购的增量(差异),并用以下事件标记它们:

(if cost purchase this month > cost purchase last month --> increase 
 if cost purchase this month < cost purchase last month --> decrease
 if cost purchase this month = x and cost purchase last month is null or 0 --> new
 if cost purchase this month is null or 0 and cost purchase last month is not null --> stop  
)

预期输出:

month       seller product amount  last_month_amount  delta   event
2021-10-01    A     corn    20€           null         20€     new
2021-10-02    A     corn    40€           20€          20€   increase
2021-10-02    B     grain   30€           null         30€     new
2021-10-03    B     grain   10€           30€         -20€   decrease
2021-10-03    A     corn    null          40€         -40€    stop     

如果只有一种产品, 我能做到:

select month 
  , seller
  , product
  , amount
  , lag(amount) over (partition by seller,product order by month) as last_month_amount
  , amount - last_month_amount as delta 
  , case when delta >0 and min(month) over (partition by seller) = month then 'new' 
         when delta >0 then 'increase' 
         when delta <0 then 'decrease'
         when (delta is null or delta = 0) then 'stop'
   end as event 

但是,在同一个月份生产多种农产品是不合逻辑的。 我怎样才能将一个产品的逻辑调整为多个产品?

我想如果我尝试获取玉米的 last_month_amount,它会返回上个月的谷物数量。我可以使用“case when”,但如果产品很多,它就不起作用了。

【问题讨论】:

    标签: postgresql


    【解决方案1】:

    你很接近。一些小问题可能会阻碍你。一方面,您不能在分配别名的同一查询中引用别名 last_month_amount。我的偏好是将第一部分拉入 CTE,然后在主查询中进行计算。

    其次,由于未始终如一地处理空值,您可能还会看到异常行为。如果您查看分区中的第一行,lag 可能会返回 null,delta 应该解决这种可能性。看来您知道delta 可能为空(根据您的event 案例语句中的逻辑),但delta 目前第一行为空,而不是最后一行,所以我认为您有@ 987654327@ 情况倒退。

    您还缺少FROM;也许您正在缩写或简化您的代码。

    最后,这篇文章中使用“月份”的方式令人困惑,部分原因是它对于DATE 列的名称很奇怪。当您说“同月”时,不清楚您是指同一日期还是一年中的同一月份。如果您可能有具有相同月份(日期)、卖方和产品的不同行,那么您将需要在您的 order by 中添加一个辅助列,否则您将获得不可预测的订单。在不知道这些的情况下,我假设您已经考虑过了,并且 order by month 已经足够好了。

    如果上个月的金额为零,您似乎还希望事件是“新的”,因为前一行将是“停止”。我已经进行了更改,但如果我的假设错误,请进行相应调整。

    这些更改的代码相同:

    with rows_in_context AS (
      select month 
      , seller
      , product
      , amount
      , lag(amount) over (partition by seller,product order by month) as last_month_amount
      from some_table
    )
    select *,
      , coalesce(amount,0) - coalesce(last_month_amount,0) as delta 
      , case when COALESCE(last_month_amount,0) = 0 then 'new' 
             when COALESCE(amount,0) = 0 then 'stop'
             when delta > 0 then 'increase' 
             when delta < 0 then 'decrease'
        end as event 
    from rows_in_context
    order by month, seller, product;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-09-25
      • 1970-01-01
      • 2020-04-20
      • 1970-01-01
      • 2022-01-10
      • 2018-02-25
      • 2023-04-04
      相关资源
      最近更新 更多