【问题标题】:Calculate running total per month计算每个月的运行总数
【发布时间】:2016-11-16 06:54:23
【问题描述】:

假设我有这张桌子:

id; date; units
1; Jan 1; 1
2; Jan 2; 4
3; Feb 9; 6
4; Mar 1; 1
5; Mar 4; 2

我现在如何相应地计算“accumulated_month”列?计算应该在每个新的月份重新开始。

id; date; units; accumulated_month
1; Jan 1; 1; 1
2; Jan 2; 4; 5
3; Feb 9; 6; 6
4; Mar 1; 1; 1
5; Mar 4; 2; 3

我得到的只是这个:

id; date; units; accumulated_month
1; Jan 1; 1; 5
2; Jan 2; 4; 5
3; Feb 9; 6; 6
4; Mar 1; 1; 3
5; Mar 4; 2; 3

【问题讨论】:

    标签: postgresql cumulative-sum


    【解决方案1】:
    create table t (id int, date date, units int);
    insert into t (id, date, units) values
    (1, '2016-01-01', 1),
    (2, '2016-01-02', 4),
    (3, '2016-02-09', 6),
    (4, '2016-03-01', 1),
    (5, '2016-03-04', 2);
    

    不清楚您是想要月份总计还是月份内的运行总计。当月总计:

    select
        id, date, units,
        sum(units) over (partition by date_trunc('month', date)) as acumm
    from t
    order by 1,2
    ;
     id |    date    | units | acumm 
    ----+------------+-------+-------
      1 | 2016-01-01 |     1 |     5
      2 | 2016-01-02 |     4 |     5
      3 | 2016-02-09 |     6 |     6
      4 | 2016-03-01 |     1 |     3
      5 | 2016-03-04 |     2 |     3
    

    如果您想要一个月内的运行总计,则将 order by 添加到窗口函数:

    select
        id, date, units,
        sum(units) over (
            partition by date_trunc('month', date)
            order by id
        ) as acumm
    from t
    order by 1,2
    ;
     id |    date    | units | acumm 
    ----+------------+-------+-------
      1 | 2016-01-01 |     1 |     1
      2 | 2016-01-02 |     4 |     5
      3 | 2016-02-09 |     6 |     6
      4 | 2016-03-01 |     1 |     1
      5 | 2016-03-04 |     2 |     3
    

    【讨论】:

    • 也许你可以解释一下这个查询,所以其他人会更好地从你的回答中受益
    • 不幸的是,这对我不起作用,因为我一直在获得一个月中每一天的每月 YTD 总值。不确定我是否做错了什么?
    • @user3716424 为我工作。用数据检查更新的答案。
    【解决方案2】:

    运行这个:

    SELECT
        t1.id, 
        t1.date, 
        t1.units,
        SUM(t2.units) accumulated_month
    FROM t t1 
        JOIN t t2 
            ON date_trunc('month', t1.date) = date_trunc('month', t2.date)
                AND t2.date <= t1.date
    GROUP BY t1.id, t1.date, t1.units
    ORDER BY t1.id
    

    编辑:

    简化 SQL:

    SELECT
        t1.*, SUM(t2.units) accumulated_month
    FROM t t1 
        JOIN t t2 
            ON date_trunc('month', t1.date) = date_trunc('month', t2.date)
                AND t2.date <= t1.date
    GROUP BY t1.id
    ORDER BY t1.id
    

    逻辑

    背后的逻辑是JOIN 与自己的表。然后对于t1JOIN中的每一行t2中满足两者的所有行(AND):

    1. 同年/同月
    2. t2.date

    有了这些ON 约束,t1 中的每一行将是 JOIN,到目前为止该月累计。所以如果没有分组,你会得到类似的东西:

    ╔════╦════════════╦═══════╦════════════╦══════════╗
    ║ id ║    date    ║ units ║  t2_date   ║ t2_units ║
    ╠════╬════════════╬═══════╬════════════╬══════════╣
    ║  1 ║ 2016-01-01 ║     1 ║ 2016-01-01 ║        1 ║
    ║  2 ║ 2016-01-02 ║     4 ║ 2016-01-01 ║        1 ║
    ║  2 ║ 2016-01-02 ║     4 ║ 2016-01-02 ║        4 ║
    ║  3 ║ 2016-02-09 ║     6 ║ 2016-02-09 ║        6 ║
    ║  4 ║ 2016-03-01 ║     1 ║ 2016-03-01 ║        1 ║
    ║  5 ║ 2016-03-04 ║     2 ║ 2016-03-01 ║        1 ║
    ║  5 ║ 2016-03-04 ║     2 ║ 2016-03-04 ║        2 ║
    ╚════╩════════════╩═══════╩════════════╩══════════╝
    

    GROUP BY t1.id 之后,您可以通过SUM(t2.units) 获得您所期望的。

    【讨论】:

    • 太棒了!那行得通。你能解释一下背后的逻辑吗?非常感谢!
    猜你喜欢
    • 2019-06-02
    • 2019-01-24
    • 1970-01-01
    • 1970-01-01
    • 2020-05-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多