OK, trudno to wyjaśnić.
W każdym dniu dla każdego statusu należy policzyć dwie wartości:
- Liczba klientów, którzy zaczynają z tym statusem.
- Liczba klientów, którzy odchodzą z tym statusem.
Pierwsza wartość jest łatwa. To tylko agregacja transakcji według daty i statusu.
Druga wartość jest prawie tak prosta. Otrzymasz poprzedni kod statusu i policz, ile razy ten kod statusu „opuszcza” w danym dniu.
Następnie kluczem jest skumulowana suma pierwszej wartości minus skumulowana suma drugiej wartości.
Swobodnie przyznaję, że poniższy kod nie jest testowany (gdybyście mieli SQL Fiddle, chętnie bym go przetestował). Ale tak wygląda wynikowe zapytanie:
select status_dte, status_cd,
(sum(inc_cnt) over (partition by status_cd order by status_dt) -
sum(dec_cnt) over (partition by status_cd order by status_dt)
) as dateamount
from ((select t.status_dt, t.status_cd, count(*) as inc_cnt, 0 as dec_cnt
from transactions t
group by t.status_dt, t.status_cd
) union all
(select t.status_dt, prev_status_cd, 0, count(*)
from (select t.*
lag(t.status_cd) over (partition by t.account_id order by status_dt) as prev_status_cd
from transactions t
) t
where prev_status_cd is null
group by t.status_dt, prev_status_cd
)
) t;
Jeśli masz daty, w których nie ma zmian dla co najmniej jednego statusu i chcesz uwzględnić je w danych wyjściowych, to powyższe zapytanie będzie musiało użyć cross join
aby najpierw utworzyć wiersze w zestawie wyników. Nie jest jasne, czy jest to wymóg, więc pomijam tę komplikację.