【问题标题】:Sum of cummulative difference within group in postgrespostgres中组内累积差异的总和
【发布时间】:2022-01-17 01:03:24
【问题描述】:

我有一张如下图所示的表格。我想求目标值每日实际值的累计差值之和。

ID  | Date    | Target_value | Daily_Value
1   |01/10/20 |   200        |   5
2   |01/10/20 |   500        |   2
3   |05/10/20 |   600        |   10
1   |04/11/20 |   200        |   50
2   |05/11/20 |   500        |   80
3   |05/11/20 |   600        |   40
1   |06/12/20 |   200        |   50
4   |06/12/20 |   400        |   30
5   |07/12/20 |   300        |   20

Expected output

Date     | Target_value - monthly_cummulative daily_value          |
   10/20 | (200 + 500 + 600) - (5 + 2 + 10) =   1283               |
   11/20 | (200 + 500 + 600) - (17 + 50 + 80 + 40) = 1113          |
   12/20 | (200 + 500 + 600 + 400 + 300) - (17 + 170 + 100) = 1713 |


这与Calculating Cumulative Sum in PostgreSQL 相似,但不完全相同。

【问题讨论】:

    标签: sql postgresql


    【解决方案1】:

    我们可以分两步完成。首先,按年和月汇总并生成目标值和每日值的总和。然后,使用SUM() 作为解析函数,在整个中间表上滚动窗口以生成差异。

    WITH cte AS (
        SELECT DATE_TRUNC('month', Date), SUM(Target_value) AS Target_value,
               SUM(Daily_Value) AS Daily_Value
        FROM yourTable
        GROUP BY 1
    )
    
    SELECT ym, Target_value,
           Target_Value - SUM(Daily_Value) OVER (ORDER BY ym) AS output
    FROM cte
    ORDER BY ym;
    

    Demo

    【讨论】:

    • 酷。之前没用过 date_trunc。
    • DATE_TRUNC('month', Date), 在 CTE 中需要为 DATE_TRUNC('month', Date) ym,,就像您处理累积总和的方式一样。
    【解决方案2】:

    按截断日期分组。

    然后对每日总和求和。

    但目标需要单独处理。

    WITH CTE_TARGETS AS (
      SELECT ID
      , MAX(Target_Value) AS Target_Value
      , MIN(DATE_TRUNC('month', Date)) as month_first
      FROM your_table
      GROUP BY ID
    ), CTE_MONTHLY AS
    (
      SELECT 
        DATE_TRUNC('month', Date) AS month_first
      , SUM(SUM(Daily_Value)) OVER (ORDER BY DATE_TRUNC('month', Date)) AS month_daily
      FROM your_table t
      GROUP BY DATE_TRUNC('month', Date)
    ) 
    SELECT 
      TO_CHAR(mon.month_first, 'MM/YY') AS Month
    , SUM(Target_Value) - month_daily AS monthly_cummulative
    FROM CTE_MONTHLY mon
    JOIN CTE_TARGETS tgt ON tgt.month_first <= mon.month_first
    GROUP BY mon.month_first, month_daily
    ORDER BY mon.month_first
    
    month monthly_cummulative
    10/20 1283
    11/20 1113
    12/20 1713

    db小提琴here

    【讨论】:

    • @TimBiegeleisen 哎呀,您说得对,先生。谢谢指出。现已修复。
    【解决方案3】:

    与 Postgres 不同,AWS Redshift 在使用 "over (order by ...)" 时需要一个框架子句。

    以下是 LukStorms 答案的更新版本。

    SELECT 
      TO_CHAR(DATE_TRUNC('month', date), 'MM/YY') AS MonthYear
    , SUM(Target_value) 
      - SUM(SUM(Daily_Value)) OVER (ORDER BY MonthYear ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS monthly_cumulative
    FROM yourtable
    GROUP BY MonthYear
    ORDER BY MonthYear;
    

    这里添加的框架子句是"ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW"。

    为简洁起见,我还将除第一次使用之外的所有DATE_TRUNC 替换为别名MonthYear。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-17
      • 1970-01-01
      • 2022-10-02
      • 1970-01-01
      • 2016-03-16
      • 1970-01-01
      • 2015-09-11
      • 1970-01-01
      相关资源
      最近更新 更多