SQL: эффективное использование кредитов (платежей) между дебетами (счетами) - PullRequest
3 голосов
/ 16 декабря 2011

Я пытаюсь сгенерировать отчет о "кассовой задержке" из готовой финансовой системы. У меня есть доступ к базе данных (Oracle). В отчете должны применяться кредиты к дебетам, первым по возрасту, и рассчитываться разница в днях между моментом создания счета и получения платежа. Все дебеты и кредиты хранятся в одном столбце таблицы финансовых транзакций. Применимые столбцы:

Column Name  Type
-----------  -------------
AMOUNT       NUMERIC(15,2)   --debits are positive, credits are negative
FT_ID        CHAR(10)
ACCOUNT_ID   CHAR(10)
ACCEPTED_DT  DATETIME

Таким образом, для таблицы, как:

ACCOUNT_ID  FT_ID  AMOUNT   ACCEPTED_DT
---------------------------------------
         1  12345  100.00   12/01/2011
         1  12346  -75.00   12/11/2011
         1  12347  100.00   12/12/2011
         1  12348  -50.00   12/16/2011

Я хотел бы получить обратно что-то вроде следующего ( edit: обновлено для отображения примененных сумм. Я хочу получить реальную сумму кредита, но ее можно найти на основе FT ID для кредита ):

ACCOUNT_ID  DEBIT_ID  DEBIT_AMOUNT  CREDIT_ID  CREDIT_AMOUNT  AGE
------------------------------------------------------------------
         1     12345         75.00      12346         -75.00   10
         1     12345         25.00      12348         -25.00   15
         1     12347         25.00      12348         -25.00    4
         1     12347         75.00      NULL            NULL  NULL

РЕДАКТИРОВАТЬ : прелесть стандартной системы, которую выбрала моя компания, заключается в том, что платежное приложение настраивается, то есть нет прямой связи кредита с дебетом. Сначала мы применяем денежные средства к самому старому долгу, что я и пытался показать в примере. Первый платеж полностью применяется к самой старой задолженности. Второй платеж распределяется между самым старым и вторым самым старым долгом. Это продолжается до тех пор, пока не будут применены все кредиты.

РЕДАКТИРОВАТЬ 2 : извините, мне кажется, что это трудно объяснить :) Глядя на данные примера, FT 12346 полностью относится к FT 12345, оставляя 25 долларов долга на счете. Следующий платеж будет также применяться к этому долгу, а любая оставшаяся сумма будет применена к следующему самому старому долгу. Промежуточный итог не совсем соответствует тому, что я пытаюсь выполнить, потому что мне нужно знать, сколько лет каждому «срезу» матча:

РЕДАКТИРОВАТЬ 3 : Таблица выше не совсем ясна, извините. Я обновил таблицу.

                 Debits                 Credits
        +-----------------------+-------------------------+
        |     FT 12345          |      FT 12346           |
        |                       |                         |
        |     $100.00           |       $75.00            |
        |                       |                         |
        |                       |                         |
        |                       |                         |
        |                       |                         |
        |                       |                         |
        |                       |                         |
        |                       +-------------------------+
        |                       |      FT 12348           |
        |                       |       $50.00            |
        |                       |                         +----->$25.00 towards 12345
        +-----------------------|.........................|
        |    FT 12347           |                         |
        |                       |                         +----->$25.00 towards 12347
        |      $100.00          +-------------------------+
        |                       |                         |
        |                       |                         |
        |                       |                         |
        |                       |                         |
        |                       |                         |
        |                       |                         |
        |                       |                         |
        |                       |                         |
        |                       |                         |
        +-----------------------+-------------------------+

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

1 Ответ

1 голос
/ 16 декабря 2011

Если вы правильно поняли, что вы хотите, вы можете сделать это с помощью аналитики:

create table cred_deb (account_id integer, transaction_date date, amount number);


insert into cred_deb values (1, sysdate - 10, 100.00); -- bill of 100
insert into cred_deb values (1, sysdate - 9, -10.00); -- payment of 10
insert into cred_deb values (1, sysdate - 8, -80.00); -- payment of 80
insert into cred_deb values (1, sysdate - 5, 80.00); -- bill of 80
insert into cred_deb values(1, sysdate - 3, -80.00); -- payment of 80

-- 2nd account
insert into cred_deb values(2, sysdate - 3, 80.00); -- bill of 80
insert into cred_deb values(2, sysdate - 3, -80.00); -- payment of 80



select account_id, 
       transaction_date,
       amount,
       sum(amount) over( partition by account_id order by transaction_date) running_total
from cred_deb
order by account_id, transaction_date;

ACCOUNT_ID             TRANSACTION_DATE          AMOUNT                 RUNNING_TOTAL          
---------------------- ------------------------- ---------------------- ---------------------- 
1                      06-DEC-11                 100                    100                    
1                      07-DEC-11                 -10                    90                     
1                      08-DEC-11                 -80                    10                     
1                      11-DEC-11                 80                     90                     
1                      13-DEC-11                 -80                    10                     
2                      13-DEC-11                 80                     80                     
2                      13-DEC-11                 -80                    0                     

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

EDIT - добавлен возраст в днях.

select account_id, 
       transaction_date,
       amount,
       sum(amount) over( partition by account_id order by transaction_date) running_total,
       trunc(transaction_date) - max(case 
                                      when amount > 0 then 
                                        trunc(transaction_date)
                                      else
                                        null
                                      end) over (partition by account_id order by transaction_date)  age_in_days
from cred_deb
order by account_id, transaction_date
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...