简体   繁体   中英

cummulative sum with reset value and then resum

I have following data:

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

Basically the end result I expect look like this:

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 is sum of all lbamount which lbtype are Add Balance (positive) and Reduce Balance (negative, to substract the sumplafon).

I already did it by doing this.

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

And the sumbalance is sum of all lbamount which lbtype are Add Plafon (postive), Use Balance (postive), Use Balance (negative), but every time lbtype Reduce Plafon is found, the sumbalance will be reset to sumplafon if the sumbalance is greater than sumplafon.

For example lbid 4 which lbtype is Reduce Plafon, the sumbalance is 16 and it is greater than sumplafon 10, therefor the sumbalance need to be reset to its sumplafon which is 10, and then continue again the cummulative sum of the sumbalance.

I tried it by preparing the group by first in cte with count like this.

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

And then in the second cte I did sum by using partition by the countplafon in the first cte, like this:

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

But the result is just resetting the sumbalance from beginning because it uses 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

Here is the sqlfiddle .

Here is the 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

I was following this SO question , but I'm still confuse how to solve my problem.

The last step I need to do is to add it with the previous sumbalance or sumplafon (if the sumbalance is greater than sumplafon), but I don't know how to do it. Can anyone help me?

Create a custom aggregate function. Place the logic in a state transition 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
);

And use it:

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)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM