【问题标题】:cummulative sum with reset value and then resum带复位值的累积和然后恢复
【发布时间】:2017-11-01 22:55:48
【问题描述】:

我有以下数据:

lbid | lbdate     | lbtype        | lbamount
-----+------------+---------------+---------
   1 | 2017-11-01 | Add Plafon    |     20
   2 | 2017-11-02 | Use Balance   |      5
   3 | 2017-11-03 | Add Balance   |      1
   4 | 2017-11-04 | Reduce Plafon |     10
   5 | 2017-11-06 | Use Balance   |      8
   6 | 2017-11-07 | Add Balance   |      2
   7 | 2017-11-08 | Reduce Plafon |      5
   8 | 2017-11-10 | Add Plafon    |     10
   9 | 2017-11-11 | Use Balance   |      1
  10 | 2017-11-12 | Reduce Plafon |      5

基本上我期望的最终结果是这样的:

lbid | lbdate     | lbtype        | lbamount  | sumplafon | sumbalance
-----+------------+---------------+-----------+-----------+-------------
   1 | 2017-11-01 | Add Plafon    |     20    |       20  |        20
   2 | 2017-11-02 | Use Balance   |      5    |       20  |        15
   3 | 2017-11-03 | Add Balance   |      1    |       20  |        16
   4 | 2017-11-04 | Reduce Plafon |     10    |       10  |        10
   5 | 2017-11-06 | Use Balance   |      8    |       10  |         2
   6 | 2017-11-07 | Add Balance   |      2    |       10  |         4
   7 | 2017-11-08 | Reduce Plafon |      5    |        5  |         4
   8 | 2017-11-10 | Add Plafon    |     10    |       15  |        14
   9 | 2017-11-11 | Use Balance   |      1    |       15  |        15
  10 | 2017-11-12 | Reduce Plafon |      5    |       10  |        10

sumplafon 是所有 lbamount 的总和,其中 lbtype 是 Add Balance(正)和 Reduce Balance(负,减去 sumplafon)。

我已经这样做了。

sum(
    case
        when "lbtype" = 'Add Plafon' then "lbamount"
        when "lbtype" = 'Reduce Plafon' then -1 * "lbamount"
        else 0
    end
) over (order by "lbdate") sumplafon

而 sumbalance 是所有 lbamount 的总和,其中 lbtype 是 Add Plafon(正)、Use Balance(正)、Use Balance(负),但是每次找到 lbtype Reduce Plafon 时,sumbalance 将重置为 sumplafon,如果sumbalance 大于 sumplafon。

例如lbtype为Reduce Plafon的lbid 4,sumbalance为16且大于sumplafon 10,因此sumbalance需要重置为其sumplafon为10,然后再继续sumbalance的累计和。

我尝试通过先在 cte 中使用这样的计数来准备组。

count(
   case when "lbtype" = 'Reduce Plafon' then 1 else null end
) over (order by "lbdate") countplafon

然后在第二个 cte 中,我通过在第一个 cte 中使用 countplafon 的分区来求和,如下所示:

sum(
    case
        when "lbtype" = 'Add Plafon' or "lbtype" = 'Add Balance' then "lbamount"
        when "lbtype" = 'Use Balance' then -1 * "lbamount"
        else 0
    end
) over (partition by "countplafon" order by "lbdate") sumbalance

但结果只是从头开始重置 sumbalance,因为它使用 group by countplafon。

lbid | lbdate     | lbtype        | lbamount  | countplafon |sumplafon  | sumbalance
-----+------------+---------------+-----------+-----------+-------------|-----------
   1 | 2017-11-01 | Add Plafon    |     20    |           0 |       20  |        20
   2 | 2017-11-02 | Use Balance   |      5    |           0 |       20  |        15
   3 | 2017-11-03 | Add Balance   |      1    |           0 |       20  |        16
   4 | 2017-11-04 | Reduce Plafon |     10    |           1 |       20  |         0
   5 | 2017-11-06 | Use Balance   |      8    |           1 |       20  |        -8
   6 | 2017-11-07 | Add Balance   |      2    |           1 |       20  |        -6
   7 | 2017-11-08 | Reduce Plafon |      5    |           2 |       20  |         0
   8 | 2017-11-10 | Add Plafon    |     10    |           2 |       20  |        10
   9 | 2017-11-11 | Use Balance   |      1    |           2 |       20  |         9
  10 | 2017-11-12 | Reduce Plafon |      5    |           3 |       20  |         0

这里是sqlfiddle

这里是sql。

with
    cte_runningnumbers1
    as (
        select
            "lbid",
            "lbdate",
            "lbtype",
            "lbamount",
            count(
                case when "lbtype" = 'Reduce Plafon' then 1 else null end
            ) over (order by "lbdate") countplafon,
            sum(
                case
                    when "lbtype" = 'Add Plafon' then "lbamount"
                    when "lbtype" = 'Reduce Plafon' then -1 * "lbamount"
                    else 0
                end
            ) over (order by "lbdate") sumplafon
        from    "lb"
    ),
    cte_runningnumbers2 as (
        select
            *,
            sum(
                case
                    when "lbtype" = 'Add Plafon' or "lbtype" = 'Add Balance' then "lbamount"
                    when "lbtype" = 'Use Balance' then -1 * "lbamount"
                    else 0
                end
            ) over (partition by "countplafon" order by "lbdate") sumbalance
        from    "cte_runningnumbers1"
    )
select  *
from    cte_runningnumbers2

我一直在关注这个SO question,但我仍然对如何解决我的问题感到困惑。

我需要做的最后一步是将它与之前的 sumbalance 或 sumplafon 相加(如果 sumbalance 大于 sumplafon),但我不知道该怎么做。谁能帮帮我?

【问题讨论】:

    标签: sql postgresql sum window-functions


    【解决方案1】:

    创建一个custom aggregate function. 将逻辑放在一个状态转换函数中:

    create or replace function lb_agg_fun(sumbalance numeric, lbtype text, lbamount numeric)
    returns numeric language sql as $$
        select case
            when lbtype in ('Add Plafon', 'Add Balance') then sumbalance + lbamount
            when lbtype = 'Use Balance' then sumbalance - lbamount
            else case
                when lbamount < sumbalance then lbamount
                else sumbalance
            end
        end;
    $$;
    

    Create an aggregate:

    create aggregate lb_agg(text, numeric) (
        sfunc = lb_agg_fun,
        stype = numeric,
        initcond = 0
    );
    

    并使用它:

    select *, lb_agg(lbtype, lbamount) over (order by lbdate) as sumbalance
    from lb;
    
     lbid |   lbdate   |    lbtype     | lbamount | sumbalance 
    ------+------------+---------------+----------+------------
        1 | 2017-11-01 | Add Plafon    |       20 |         20
        2 | 2017-11-02 | Use Balance   |        5 |         15
        3 | 2017-11-03 | Add Balance   |        1 |         16
        4 | 2017-11-04 | Reduce Plafon |       10 |         10
        5 | 2017-11-06 | Use Balance   |        8 |          2
        6 | 2017-11-07 | Add Balance   |        2 |          4
        7 | 2017-11-08 | Reduce Plafon |        5 |          4
        8 | 2017-11-10 | Add Plafon    |       10 |         14
        9 | 2017-11-11 | Use Balance   |        1 |         13
       10 | 2017-11-12 | Reduce Plafon |        5 |          5
    (10 rows)
    

    【讨论】:

      猜你喜欢
      • 2021-09-12
      • 1970-01-01
      • 2016-01-04
      • 2020-11-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-08-10
      • 1970-01-01
      相关资源
      最近更新 更多