我确定这不会给我很多upvotes,因为它的复杂性,但这仍然是一个有趣的任务。我认为这可以通过光标方法来完成,但也可以通过递归CTE来完成。我会尽量使其尽可能易读,预先计算值outer apply
在这里肯定有帮助。
我修改了一下你的模式。我认为你必须存储在Lot Qty
不同的表,是这样的:
create table Products ([Product] varchar(12), [Lot Qty] int);
insert into Products
values
('Addidas Shoe', 25),
('Puma Shoe', 30);
你仍然可以存储Lot Qty
您的订单表,但它不是标准化的。 至于这个问题,我觉得递归CTE可以帮助你在这里:基于光标
with cte1 as (
select
row_number() over(partition by c.[Product] order by c.size) as row_num,
c.*,
P.[Lot Qty]
from CustOrder as c
inner join Products as P on P.[Product] = c.Product
), cte2 as (
select
c.Product, c.Size,
0 as [Lot No],
1 as [Sl. No],
c.[Purch Qty] - c.[Lot Qty] as [Rem Qty],
case when c.[Purch Qty] > c.[Lot Qty] then c.[Lot Qty] else c.[Purch Qty] end as Qty,
case when c.[Purch Qty] > c.[Lot Qty] then c.row_num else c.row_num + 1 end as row_num2,
c.[Lot Qty]
from cte1 as c
where c.row_num = 1
union all
select
c.Product, c.Size,
CALC.[Lot No],
CALC.[Sl. No],
CALC.[Purch Qty] - CALC.[Lot Qty] as [Rem Qty],
case when CALC.[Purch Qty] > CALC.[Lot Qty] then CALC.[Lot Qty] else CALC.[Purch Qty] end as Qty,
case when CALC.[Purch Qty] > CALC.[Lot Qty] then c.row_num else c.row_num + 1 end as row_num2,
c.[Lot Qty]
from cte1 as c
inner join cte2 as c2 on c2.row_num2 = c.row_num and c2.Product = c.product
outer apply (
select
case when c2.[Rem Qty] < 0 then c2.[Lot No] else c2.[Lot No] + 1 end as [Lot No],
case when c2.[Rem Qty] < 0 then c2.[Sl. No] + 1 else 1 end as [Sl. No],
case when c2.[Rem Qty] < 0 and abs(c2.[Rem Qty]) < c.[Lot Qty] then abs(c2.[Rem Qty]) else c.[Lot Qty] end as [Lot Qty],
case when c2.[Rem Qty] > 0 and c2.[Rem Qty] < c.[Purch Qty] then c2.[Rem Qty] else c.[Purch Qty] end as [Purch Qty]
) as CALC
)
select
999 + dense_rank() over(order by c.Product, c.[Lot No]) as [Lot No],
c.[Sl. No],
c.Product, c.Size, c.Qty
from cte2 as c
order by product, [Lot No]
sql fiddle demo
解决方案:
declare @Lot table (ItemSize int, Product varchar(20), Qty int)
declare @RemQty int = 0, @curQty int, @curLotQty int
declare @ItemSize int, @Product varchar(20), @Qty int, @lotQty int, @oldProduct varchar(20)
declare table_cursor cursor local fast_forward for
select
ItemSize, Product, Qty, lotQty
from Custorders
order by Product, Itemsize
open table_cursor
while 1 = 1
begin
if @RemQty <= 0
begin
fetch table_cursor into @ItemSize, @Product, @Qty, @lotQty
if @@fetch_status <> 0 break
if @oldProduct <> @Product or @oldProduct is null
begin
select @oldProduct = @Product
select @RemQty = 0
end
end
if @RemQty < 0 and abs(@RemQty) < @lotQty
select @curLotQty = abs(@RemQty)
else
select @curLotQty = @lotQty
if @RemQty > 0 and @RemQty < @Qty
select @curQty = @RemQty
else
select @curQty = @Qty
select @RemQty = @curQty - @curLotQty
insert into @Lot
select @ItemSize, @Product, case when @curQty > @curLotQty then @curLotQty else @curQty end
end
close table_cursor
deallocate table_cursor
select * from @Lot order by Product, Itemsize
sql fiddle demo
你使用的是什么RDBMS? SQL Server,PostgreSQL,MySQL?如果你显示给定的输入和期望的输出,它也会有所帮助。 –
为什么每个'Product'的第一个都有一个'Lot Qty'?看来你想采取'采购。 Qty'并将该产品的所有订单拆分为'Lot Qty'批次,尽管我在您的输出中看到了多个模式,所以要弄清楚您的实际规则有些困难。 –
产品'Addidas鞋'被拆分成多行,具体取决于其批量25和'Puma鞋',根据其批量数量30分成多行。 –