Вот один способ, которым это может быть сделано, с из таблиц и данных, так как мы не знаем, что ваш выглядеть. Я помещаю некоторые рассказы в местах, но весь код должен запускаться как один скрипт.
установка данных:
declare @bills table (billid int, balance decimal(38,4))
declare @payments table (paymentid int, balance decimal(38,4))
insert into @bills (billid, balance) values
(1,0), (2,22.50), (3,12.75), (4,19.20)
insert into @payments (paymentid,balance) values
(1,20.19),(2,5.50),(3,20)
declare @newpayments table (billid int, paymentid int,
paymentamount decimal(38,4))
я предполагал, что bills
и payments
таблицы есть столбец, называемый balance
, который показывает любые суммы, не раскрытые до сих пор. В качестве альтернативы вам, возможно, придется рассчитать это из нескольких столбцов. Но нет выборки данных в вашем вопросе не означает, что я получаю, чтобы составить простую структуру :-)
запроса для заполнения @newpayments
, с которой счета должны быть оплачены из которых (частичных) платежей :
; With unpaidbills as (
select billid,balance,
ROW_NUMBER() OVER (ORDER BY billid) as rn,
SUM(balance) OVER (ORDER BY billid
ROWS BETWEEN UNBOUNDED PRECEDING
AND CURRENT ROW) as endbalance,
SUM(balance) OVER (ORDER BY billid
ROWS BETWEEN UNBOUNDED PRECEDING
AND CURRENT ROW) - balance as startbalance
from @bills
where balance > 0
), unusedpayments as (
select paymentid,balance,
ROW_NUMBER() OVER (ORDER BY paymentid) as rn,
SUM(balance) OVER (ORDER BY paymentid
ROWS BETWEEN UNBOUNDED PRECEDING
AND CURRENT ROW) as endbalance,
SUM(balance) OVER (ORDER BY paymentid
ROWS BETWEEN UNBOUNDED PRECEDING
AND CURRENT ROW) - balance as startbalance
from @payments
where balance > 0
), overlaps as (
select
billid,paymentid,
CASE WHEN ub.startbalance < up.startbalance
THEN up.startbalance ELSE ub.startbalance END as overlapstart,
CASE WHEN ub.endbalance > up.endbalance
THEN up.endbalance ELSE ub.endbalance END as overlapend
from
unpaidbills ub
inner join
unusedpayments up
on
ub.startbalance < up.endbalance and
up.startbalance < ub.endbalance
)
insert into @newpayments(billid,paymentid,paymentamount)
select billid,paymentid,overlapend - overlapstart as paymentamount
from overlaps
на данный момент, @newpayments
может быть использован для создания истории транзакций, и т.д.
И затем, наконец, мы обновляем исходные таблицы, чтобы отметить суммы, используемые:
;With totalpaid as (
select billid,SUM(paymentamount) as payment from @newpayments
group by billid
)
update b
set b.balance = b.balance - tp.payment
from @bills b
inner join
totalpaid tp
on b.billid = tp.billid
;With totalused as (
select paymentid,SUM(paymentamount) as payment from @newpayments
group by paymentid
)
update p
set p.balance = p.balance - tu.payment
from @payments p
inner join
totalused tu
on p.paymentid = tu.paymentid
Ключевой частью было использовать SUM()
с window functions для расчета текущих сумм сумм, причитающихся (счетов) или доступных сумм (платежей), в обоих случаях с использованием столбца (billid или paymentid), чтобы определить, в каком порядке каждый из этих предметы должны быть рассмотрены. Например. unpaidbills
CTE производит набор результатов, как это:
billid balance rn endbalance startbalance
----------- --------- -------------------- ------------- -------------
2 22.5000 1 22.5000 0.0000
3 12.7500 2 35.2500 22.5000
4 19.2000 3 54.4500 35.2500
и unusedpayments
выглядит следующим образом:
paymentid balance rn endbalance startbalance
----------- ---------- -------------------- ------------ -------------
1 20.1900 1 20.1900 0.0000
2 5.5000 2 25.6900 20.1900
3 20.0000 3 45.6900 25.6900
Затем мы создаем overlaps
КТР, который находит перекрывается между счетами и платежами где (часть) платеж может быть использован для удовлетворения (части) счета. Область перекрытия - это фактическая сумма для оплаты этого счета.
не действительно Необходимы ROW_NUMBER()
звонки. В начале написания этого запроса я думал, что буду использовать их, но это оказалось ненужным. Но удаление их не сокращает все, чтобы позволить SO прекратить прокрутку этого запроса в любом случае, и поэтому я также могу оставить их (и не нужно редактировать приведенные ниже результаты также ниже)
Многие люди, пытающиеся найти совпадения, делают вещи абсурдно сложными и касаются многих особых случаев, чтобы найти все перекрытия. Обычно это можно сделать гораздо больше, просто в том, что я показываю в overlaps
КТРЕ - два диапазона перекрывается, если первый диапазон начинается до второго диапазон заканчивается, и второго диапазона начинается до первого диапазона заканчивается.
Единственная сложная задача - решить, хотите ли вы иметь дело с двумя диапазонами, которые примыкают (первое значение первого в точности равно второму началу или наоборот), но это просто приводит к решению о том, использовать <
или <=
в сравнении.
В данном случае нам неважно, выплачивается ли платеж только с предыдущего, поэтому мы используем <
, чтобы избежать таких ситуаций, как перекрытие.
Для этого вы можете определенно использовать наборный подход. Если вам нужна конкретная помощь, вам необходимо поделиться своей структурой таблиц и существующим кодом. – JNK