I have a repayment table that looks like this below,
cus_id | due_date | principal | disbursed_date |
---|---|---|---|
1 | 01-01-2022 | 10 | 01-11-2021 |
1 | 01-02-2022 | 10 | 01-11-2021 |
1 | 01-03-2022 | 10 | 01-11-2021 |
2 | 15-03-2022 | 20 | 15-02-2022 |
1 | 01-04-2022 | 10 | 01-11-2021 |
3 | 01-04-2022 | 15 | 20-03-2022 |
2 | 15-04-2022 | 20 | 15-02-2022 |
3 | 01-05-2022 | 15 | 20-03-2022 |
2 | 30-05-2022 | 20 | 15-02-2022 |
1 | 30-05-2022 | 10 | 01-11-2021 |
3 | 01-06-2022 | 15 | 20-03-2022 |
2 | 15-06-2022 | 20 | 15-02-2022 |
2 | 30-06-2022 | 20 | 15-02-2022 |
3 | 01-07-2022 | 55 | 20-03-2022 |
One can pay any amount on any day of the month, there can also be 2 payments by the same customer within one month.
disbursed_day is the day of disbursement (could be any day before 1st EMI) and is the same for each cus_id. The total amount for each customer is thesum(principal) group by cus_id
i.e. for customers 1, 2, and 3 total amount is respectively 50, 100, and 100.
I want to calculate the outstanding as of each due_date. My expected results would look like below,
| date_as_of | outstanding | |
| ------------ | ----------- | ------------------------------------------ |
| 01-01-2022 | 40 | -- total outstanding as on 50, paid 10 |
| 01-02-2022 | 30 | -- cus1 paid emi 10 |
| 01-03-2022 | 120 | -- amt for 2 disbursed on 15-02, 20+100 |
| 15-03-2022 | 100 | -- cus2 paid emi of 20 |
| 01-04-2022 | 175 | -- amt for 3 disbursed on 20-03, 10+80+85 |
| 15-04-2022 | 155 | -- cus2 paid emi of 20 |
| 01-05-2022 | 140 | -- cus3 paid emi of 15 |
| 30-05-2022 | 110 | |
| 01-06-2022 | 95 | |
| 15-06-2022 | 75 | |
| 30-06-2022 | 55 | |
| 01-07-2022 | 0 | |
For 1st Feb EMI, cus1 paid 2 EMI of 10, so outstanding as of 1st Feb will be 50-(10+10) = 30.
For 1st Mar EMI, cus1 paid 3 EMI of 10. Cus2 disbursed amt of 100 on 15th of Feb, so outstanding as of 1st Mar will be (50-(10+10+10))+100 = 120
On 15th Mar, cus 2 paid EMI of 20, so outstanding is (50-(10+10+10))+ (100-20) = 100
For 1st Apr EMI, cus1 paid 4 EMI of 10. Cus 2 paid 1 EMI of 20 (on 15th of March). Amt for cus3 disbursed on 20th March, but also had paid EMI of 15. So outstanding will be (50-(10+10+10+10)) + (100-20) + (100-15) = 175
This is how the calculation of outstanding should be. I was trying this approach below,
select *, (osp_as_on - principal) balance from (
select due_date, principal, sum(net_repayment) over(order by due_date desc) osp_as_on from (
select due_date, principal, sum(principal) net_repayment
from repayments
group by 1
) t1
) t2 order by 1;
But my approach isn’t correct as my query isn’t considering the disbursed_date, as only after the disbursement date, I’ve to consider the remaining balance from the total to calculate the correct outstanding as of due date.
Any help from the community would be greatly appreciated. I’m using MySQL8.0.
2
Answers
One approach unpivots the columns to rows, so we can properly compute the window sum at any point in time, and then filters out unrelevant rows (ie those that correspond to "disbursed dates").
For your sample data, this returns:
Demo on DB Fiddle
This can be done in 3 steps:
Result: