2015-05-20 3 views
5

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

Предположения:

  • Bills принадлежат к одному счету
  • Платежи применяются к каждому законопроекту в порядке его ID

Учитывая Bills стол:

ID Amount 
1 500 
2 500 
3 500 

Сценарий 1:

Платежи таблица

ID Amount 
1 750 
2 750 

с вышеприведенной таблицей Bills, и таблица сценария 1 платежей, я хотел бы видеть этот вывод:

Bill ID | Payment ID | Amount Applied 
1 1 500 
2 2 250 
3 2 500 
3 2 250 

Сценарий 2:

Payments table: 
1 300 
2 300 
3 300 
4 300 
5 300 

Учитывая выше Таблица счетов и сценарий 2 Таблица выплат, я хотел бы видеть результат:

Bill ID | Payment ID | Amount Applied 
1 1 300 
1 2 200 
2 2 100 
2 3 300 
2 4 100 
3 4 200 
3 5 300 

Я могу сделать это с помощью курсоров, но я хотел бы узнать, знает ли кто, как это сделать с помощью SQL-кода.

Спасибо!

+0

я мог думать только о том, возможно, с использованием рекурсивного ОТВ, но до сих пор не выяснили, как именно применять его –

+1

Есть ли таблица не соотносить платеж в счет? – TTeeple

+1

Можете ли вы изменить свои таблицы? Обычно у вас будет отношение к таблице платежей к таблице счетов, многие к одному. Для представления ваших данных требуется всего 2 таблицы - нормализованная нормализация. – Christopher

ответ

0

SQL 2005 требует еще нескольких шагов, поскольку ему не хватает функций SUM() OVER(ORDER BY...) и LAG(), но основная идея такая же: рассчитать общие суммы счетов и платежей.

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

SQL 2005

WITH 
    Bills_RunningTotal AS (
    SELECT 
     b_ID = b1.ID 
     ,b_Amount = b1.Amount 
     ,b_RunningTotal = SUM(b2.Amount) 
    FROM Bills b1 
    INNER JOIN Bills b2 
     ON (b2.ID <= b1.ID) 
    GROUP BY b1.ID,b1.Amount 
) 
,Payments_RunningTotal AS (
    SELECT 
     p_ID = p1.ID 
     ,p_Amount = p1.Amount 
     ,p_RunningTotal = SUM(p2.Amount) 
    FROM Payments p1 
    INNER JOIN Payments p2 
     ON (p2.ID <= p1.ID) 
    GROUP BY p1.ID,p1.Amount 
) 
,Bills_Payments_RemainderDue AS (
    SELECT 
     b_ID 
    ,p_ID 
    ,b_Previous_Remainder_Due = CASE 
     WHEN b_RunningTotal + p_Amount < p_RunningTotal THEN 0 
     WHEN b_RunningTotal + p_Amount > p_RunningTotal + b_Amount THEN b_Amount 
     ELSE b_RunningTotal + p_Amount - p_RunningTotal 
    END 
    ,b_Current_Remainder_Due = CASE 
     WHEN b_RunningTotal < p_RunningTotal THEN 0 
     WHEN b_RunningTotal > p_RunningTotal + b_Amount THEN b_Amount 
     ELSE b_RunningTotal - p_RunningTotal 
    END 
    FROM Bills_RunningTotal b 
    CROSS JOIN Payments_RunningTotal p 
) 
SELECT 
    [Bill ID] = b_ID 
,[Payment ID] = p_ID 
,[Amount Applied] = b_Previous_Remainder_Due - b_Current_Remainder_Due 
FROM Bills_Payments_RemainderDue 
WHERE b_Previous_Remainder_Due - b_Current_Remainder_Due > 0 
ORDER BY [Bill ID],[Payment ID] 

SQL 2008+

Использование заказанные оконных функций, запрос может быть более эффективным.

WITH 
    Bills_Payments_RunningTotal AS (
    SELECT 
     b_ID = b.ID 
     ,p_ID = p.ID 
     ,b_Amount = b.Amount 
     ,p_Amount = p.Amount 
     ,b_RunningTotal = SUM(b.Amount) OVER(PARTITION BY p.ID ORDER BY b.ID) 
     ,p_RunningTotal = SUM(p.Amount) OVER(PARTITION BY b.ID ORDER BY p.ID) 
    FROM Bills b 
    CROSS JOIN Payments p 
) 
,Bills_Payments_RemainderDue AS (
    SELECT b_ID,p_ID,b_Amount,p_Amount 
    ,b_Current_Remainder_Due = CASE 
     WHEN b_RunningTotal < p_RunningTotal THEN 0 
     WHEN b_RunningTotal > p_RunningTotal + b_Amount THEN b_Amount 
     ELSE b_RunningTotal - p_RunningTotal 
     END 
    FROM Bills_Payments_RunningTotal 
) 
,Bills_Payments_AmountApplied AS (
    SELECT 
     [Bill ID] = b_ID 
    ,[Payment ID] = p_ID 
    ,[Amount Applied] = ISNULL(LAG(b_Current_Remainder_Due) OVER(PARTITION BY b_ID ORDER BY p_ID),b_Amount) - b_Current_Remainder_Due 
    FROM Bills_Payments_RemainderDue 
) 
SELECT [Bill ID],[Payment ID],[Amount Applied] 
FROM Bills_Payments_AmountApplied 
WHERE [Amount Applied] > 0 
ORDER BY [Bill ID],[Payment ID] 
Смежные вопросы