Вы можете использовать рекурсивный CTE для вычисления промежуточной суммы.
declare @Sales table (PKId int, Qty int)
insert into @Sales values
(1, 100),
(2, 200),
(3, 750),
(4, 200)
declare @TotalMaxQty int = 1000
;with OrderedSales as
(
select PKId,
Qty,
row_number() over(order by PKId) as rn
from @Sales
--where "some where clause against Sales"
),
RunningSum as
(
select OS.PKId,
case when OS.Qty < @TotalMaxQty then OS.Qty
else @TotalMaxQty
end as Qty,
@TotalMaxQty - OS.Qty as Rest,
OS.rn
from OrderedSales OS
where rn = 1
union all
select OS.PKId,
case when OS.Qty < RS.Rest then OS.Qty
else RS.Rest
end as Qty,
RS.Rest - OS.Qty,
OS.rn
from OrderedSales as OS
inner join RunningSum as RS
on OS.rn = RS.rn + 1
where RS.Rest > 0
)
select PKId,
Qty
from RunningSum
option (maxrecursion 0)
Редактировать: Версия, в которой заказанные продажи хранятся в табличной переменной с rn
в качестве первичного ключа. Мои тесты показывают значительно улучшенную производительность.
declare @Sales table (PKId int, Qty int)
insert into @Sales values
(1, 100),
(2, 200),
(3, 750),
(4, 200)
declare @TotalMaxQty int = 1000
declare @OrderedSales table
(
rn int primary key,
PKId int,
Qty int
)
insert into @OrderedSales
select row_number() over(order by PKId),
PKId,
Qty
from @Sales
--where "some where clause against Sales"
;with RunningSum as
(
select OS.PKId,
case when OS.Qty < @TotalMaxQty then OS.Qty
else @TotalMaxQty
end as Qty,
@TotalMaxQty - OS.Qty as Rest,
OS.rn
from @OrderedSales OS
where rn = 1
union all
select OS.PKId,
case when OS.Qty < RS.Rest then OS.Qty
else RS.Rest
end as Qty,
RS.Rest - OS.Qty,
OS.rn
from @OrderedSales as OS
inner join RunningSum as RS
on OS.rn = RS.rn + 1
where RS.Rest > 0
)
select PKId,
Qty
from RunningSum
option (maxrecursion 0)