Пропорциональное распределение на основе открытой суммы - PullRequest
0 голосов
/ 26 июня 2018

Следующие данные представляют входящие и исходящие транзакции двух займов.Идентификатор транзакции (t_id) представляет порядок, в котором происходят события транзакции.

+---------+------+-----+--------+
| loan_id | t_id | amt | t_type |
+---------+------+-----+--------+
|       1 |    1 | 100 | OUT    |
|       1 |    2 |  20 | IN     |
|       1 |    3 |  30 | IN     |
|       1 |    4 | 150 | OUT    |
|       1 |    5 |  15 | IN     |
|       1 |    6 |  25 | IN     |
|       1 |    7 |  40 | OUT    |
|       1 |    8 | 200 | IN     |
|       2 |    1 | 150 | OUT    |
|       2 |    2 |  50 | OUT    |
|       2 |    3 | 120 | IN     |
|       2 |    4 |  20 | OUT    |
|       2 |    5 | 100 | IN     |
+---------+------+-----+--------+

Цель - пропорционально распределить входящие суммы на исходящие суммы на основе суммы открытия исходящей транзакции во время события транзакции входящей суммы.Каждый заем должен обрабатываться отдельно.
Должна применяться следующая логика:
loan_id: 1
1) Входящие транзакции 2 и 3 должны быть на 100% распределены для исходящей транзакции 1, поскольку в данный момент это только исходящая транзакция.
2) Входящей транзакции 5 следует распределить 25% / 75% между исходящими транзакциями 1 и 4. (открытая сумма транзакции 1 равна 50, потому что 50 погашается транзакциями 2 и 3, а открытая сумма транзакции 4 равна 150)
3) Входящая транзакция 6 должна быть распределена на 25% / 75% между исходящими транзакциями 1 и 4. (открытая сумма транзакции 1 составляет 46,25, а открытая сумма транзакции 4 - 138,75)
4) Входящая транзакция 8 должна быть распределена на 20%60% / 20% между исходящими транзакциями 1;4 и 7. (транзакции 1; 4 и 7 открытых сумм: 40, 120 и 40)

Можно предположить, что общая входящая сумма и текущая общая входящая сумма всегда меньше или равна общей открытой исходящей сумме.

Вот так должен выглядеть итоговый результат:

+---------+---------+----------+---------------+
| loan_id | in_t_id | out_t_id | allocated_amt |
+---------+---------+----------+---------------+
|       1 |       2 |        1 | 20            |
|       1 |       3 |        1 | 30            |
|       1 |       5 |        1 | 3.75          |
|       1 |       5 |        4 | 11.25         |
|       1 |       6 |        1 | 6.25          |
|       1 |       6 |        4 | 18.75         |
|       1 |       8 |        1 | 40            |
|       1 |       8 |        4 | 120           |
|       1 |       8 |        7 | 40            |
|       2 |       3 |        1 | 90            |
|       2 |       3 |        2 | 30            |
|       2 |       5 |        1 | 60            |
|       2 |       5 |        2 | 20            |
|       2 |       5 |        4 | 20            |
+---------+---------+----------+---------------+

Ссылка на скрипту SQL: http://www.sqlfiddle.com/#!17/9eecb/16623
Все комбинации из 14 строк генерируются, но не размещаются по адресу__ *.

В настоящее время я не уверен, возможно ли создать SQL для генерации такой логики.
Я попытался реализовать это с помощью оконных функций, но безуспешно, потому что всегда нужнознать исходящие открытые суммы на основе предыдущего пропорционального распределения.
Может быть, возможно создать рекурсивный запрос, чтобы покрыть эту логику.

1 Ответ

0 голосов
/ 26 июня 2018

Я думаю, было бы проще, если бы вы создали таблицу истории для хранения распределений после каждой транзакции IN, чтобы следующая транзакция IN могла повторно использовать вычисленные значения вместо попытки вычислить их на лету.Для этого вам понадобится триггер INSERT - посмотрите на SQLfiddle

-- INSERT INTO distribution(loan_id,t_in,t_out,amount)
-- we compute the distributions for the current IN transaction and store them in table DISTRIBUTIONS 
-- to be used by the next IN transaction
SELECT current.loan_id,6 AS t_in,current.t_id AS t_out,25 * (current.amt - paid) / (total_due - total_paid) AS distributed
FROM 
-- first we get the amount paid for each existing OUT transaction
(SELECT t.loan_id,t.t_id,t.amt,SUM(d.amount) AS paid
FROM transactions AS t
LEFT JOIN distribution AS d ON t.loan_id = d.loan_id AND t.t_id = d.t_out
WHERE t_type = 'OUT' AND t.t_id < 6 -- only OUT transactions before the current IN transaction
GROUP BY t.loan_id,t.t_id,t.amt) AS current
LEFT JOIN
-- next we get the total amount due for the given loan
(SELECT loan_id,SUM(amt) AS total_due
FROM transactions
WHERE t_type = 'OUT' AND t_id < 6 -- only OUT transactions before the current IN transaction
GROUP BY loan_id) AS t_due                                                                   
ON current.loan_id = t_due.loan_id
LEFT JOIN
-- next we get the total amount paid for the given loan
(SELECT loan_id,COALESCE(SUM(amount),0) AS total_paid
FROM distribution AS d
WHERE t_out < 6 -- only OUT transactions before the current IN transaction
GROUP BY loan_id) AS t_paid
ON current.loan_id = t_paid.loan_id
WHERE current.loan_id = 1 -- the loan ID of the current IN transaction
...