I want to achieve the following calculation highlighted in the Desired Output column:
highlighted row has a running total of 6.4 M, that exceeds the 5 M hard limit so the SQL should return the previous row value 3.64M
(thus in Excel the formula would be I9=IF(I8+F9 > $H$2, I8, I8+F9)
)
same logic should happen for the following rows when ever the Running total breaches the Hard limit
F | G | H | I | |
---|---|---|---|---|
SaleAmount | RunningTotal | Hard limit | Desired output | |
2 | 8,778.52 | 8,778.52 | 5,000,000 | 8,778.52 |
3 | 1,496,692.06 | 1,505,470.58 | 1,505,470.58 | |
4 | 1,849,601.42 | 3,355,072 | 3,355,072 | |
5 | 445.41 | 3,355,517.41 | 3,355,517.41 | |
6 | 109.98 | 3,355,627.39 | 3,355,627.39 | |
7 | 3,933.56 | 3,359,560.95 | 3,359,560.95 | |
8 | 280,915.44 | 3,640,476.39 | 3,640,476.39 | |
9 | 2,778,827.65 | 6,419,304.04 | 3,640,476.39 | |
10 | 1,349,832.28 | 7,769,136.32 | 4,990,308.67 | |
11 | 2,881.94 | 7,772,018.26 | 4,993,190.61 | |
12 | 145,824.06 | 7,917,842.32 | 4,993,190.61 | |
13 | 316.97 | 7,918,159.29 | 4,993,507.58 | |
14 | 1,181,685.55 | 9,099,844.84 | 4,993,507.58 | |
15 | 2,568.51 | 9,102,413.35 | 4,996,076.09 | |
16 | 3,000 | 9,105,413.35 | 4,999,076.09 | |
17 | 1,286,983.8 | 1,039,2,397.15 | 4,999,076.09 | |
18 | 2,735.87 | 1,039,5,133.02 | 4,999,076.09 | |
19 | 1,442,096.02 | 1,183,7,229.04 | 4,999,076.09 |
request you to please help me out with Ideas to achieve this.
Your best bet will be to use a recursive Common Table Expression.
I voluntarily chose the simplest use (row-by-row iterations), because it will be a lot to learn at first,
but you will then be able to optimize it (for example by using a windowed sum() over ()
to make a first pass containing "everything surely under the cutoff" instead of the row-by-row iterations),
or use RDBMS specific functions (PostgreSQL User-Defined Aggregates).
Here is it with PostgreSQL (you didn't tell which RDBMS you use, so I choose the one I prefer…):
with recursive
-- Give each row its position, we'll need it to iterate from row to row:
p as (select row_number() over() pos, * from t),
-- Now "recurse" (iterate) over rows:
r as
(
-- Init our recursion with the first amount, use its amount as the first value of the running sum, and as the capped sum if it's less than the cap:
select *, amount rs, case when amount > 5000000 then 0 else amount end capped from p where pos = 1
-- Now the recursive part:
union all
select p.*, rs + p.amount, capped + case when capped + p.amount > 5000000 then 0 else p.amount end
-- Use r itself (the previous iteration of our recursive CTE) to have the pos of the last iteration, and fetch the row having the next pos
from r join p on p.pos = r.pos + 1
)
select * from r order by pos;
pos | amount | rs | capped |
---|---|---|---|
1 | 8778.52 | 8778.52 | 8778.52 |
2 | 1496692.06 | 1505470.58 | 1505470.58 |
3 | 1849601.42 | 3355072 | 3355072 |
4 | 445.41 | 3355517.41 | 3355517.41 |
5 | 109.98 | 3355627.39 | 3355627.39 |
6 | 3933.56 | 3359560.95 | 3359560.95 |
7 | 280915.44 | 3640476.39 | 3640476.39 |
8 | 2778827.65 | 6419304.04 | 3640476.39 |
9 | 1349832.28 | 7769136.32 | 4990308.67 |
10 | 2881.94 | 7772018.260000001 | 4993190.61 |
11 | 145824.06 | 7917842.32 | 4993190.61 |
12 | 316.97 | 7918159.29 | 4993507.58 |
13 | 1181685.55 | 9099844.84 | 4993507.58 |
14 | 2568.51 | 9102413.35 | 4996076.09 |
15 | 3000 | 9105413.35 | 4999076.09 |
16 | 1286983.8 | 10392397.15 | 4999076.09 |
17 | 2735.87 | 10395133.02 | 4999076.09 |
18 | 1442096.02 | 11837229.04 | 4999076.09 |
I've put it running on your data in an example fiddle you can play with.