I’ve following data:
x
SELECT 1 note, 1000 amt FROM dual union all
SELECT 2 note, 2000 amt FROM dual union all
SELECT 3 note, 8000 amt FROM dual union all
SELECT 4 note, 3000 amt FROM dual union all
SELECT 5 note, 1500 amt FROM dual union all
SELECT 6 note, 1600 amt FROM dual union all
SELECT 7 note, 20000 amt FROM dual union all
SELECT 8 note, 20000 amt FROM dual union all
SELECT 9 note, 2100 amt FROM dual union all
SELECT 10 note, 4500 amt FROM dual union all
SELECT 11 note, 1000 amt FROM dual union all
SELECT 12 note, 16000 amt FROM dual
and I need sum the amount, but for every sum <= 15000, they will be grouped together. If the amount is > 15000, they will be on their own group like this:
NOTE | AMT | group |
---|---|---|
1 | 1000 | 1 |
11 | 1000 | 1 |
5 | 1500 | 1 |
6 | 1600 | 1 |
2 | 2000 | 1 |
9 | 2100 | 1 |
4 | 3000 | 1 |
10 | 4500 | 2 |
3 | 8000 | 2 |
12 | 16000 | 3 |
7 | 20000 | 4 |
8 | 20000 | 5 |
I need the solution in oracle sql, is it possible? I’m using oracle 11g
Advertisement
Answer
One method is a recursive subquery:
with tt(note, amt, seqnum) as (
select t.note, t.amt, row_number() over (order by amt) as seqnum
from t
),
cte(note, amt, seqnum, grp, running_amt) as (
select note, amt, seqnum, 1, amt
from tt
where seqnum = 1
union all
select tt.note, tt.amt, tt.seqnum,
(case when tt.amt + cte.running_amt > 15000 then cte.grp + 1 else cte.grp end),
(case when tt.amt + cte.running_amt > 15000 then tt.amt else tt.amt + cte.running_amt end)
from cte join
tt
on tt.seqnum = cte.seqnum + 1
)
select *
from cte;
Here is a db<>fiddle.
Note: This is ordering by amt
— as in your sample data. You can as easily order by note
(which also makes sense) just by adjusting seqnum
in tt
.