Search code examples
postgresqlaggregate-functionswindow-functions

postgres aggregate subset from group by rows


I'm trying to evaluate user loyalty bonuses balance when bonuses burns after half-year inactivity. I want my sum consist of ord's 4, 5 and 6 for user 1.

create table transactions (
    user int,
    ord int, -- transaction date replacement
    amount int, 
    lag interval -- after previous transaction
);
insert into transactions values
    (1, 1, 10, '1h'::interval),
    (1, 2, 10, '.5y'::interval),
    (1, 3, 10, '1h'::interval),
    (1, 4, 10, '.5y'::interval),
    (1, 5, 10, '.1h'::interval),
    (1, 6, 10, '.1h'::interval),
    (2, 1, 10, '1h'::interval),
    (2, 2, 10, '.5y'::interval),
    (2, 3, 10, '.1h'::interval),
    (2, 4, 10, '.1h'::interval),
    (3, 1, 10, '1h'::interval),
;

select user, sum(
    amount -- but starting from last '.5y'::interval if any otherwise everything counts
) from transactions group by user 

 user | sum(amount)
--------------------
 1    | 30 -- (4+5+6), not 50, not 60
 2    | 30 -- (2+3+4), not 40
 3    | 10

Solution

  • try this:

    with cte as(
    select *, 
    case when (lead(lag) over (partition by user_ order by ord)) >= interval '.5 year'
    then 1 else 0  end  "flag" from test
    ),
    cte1 as (
    select *,
    case when flag=(lag(flag,1) over (partition by user_ order by ord)) then 0 else 1 end "flag1"  from cte
    )
    select distinct on (user_) user_, sum(amount) over (partition by user_,grp order by ord) from (
    select *, sum(flag1) over (partition by user_ order by ord) "grp" from cte1) t1
    order by user_ , ord desc
    

    DEMO

    Though it is very complicated and slow but resolve your problem