2013-08-27 34 views
1

我想根据批量qty分割客户订单。根据条件将单个数据行分割成多个数据行的SQL脚本

这是客户订单表。

Product   Size Purch. Qty Lot Qty 
----------------------------------------------- 
Addidas Shoe  8   30   25 
Addidas Shoe  9   15   25 
Addidas Shoe  10   50   25 
Puma Shoe   7   40   30 
Puma Shoe   8   60   30 

我有2个产品阿迪达斯鞋在劈裂在被分裂,这取决于它的地块数量30的多个行,如下所示根据其地块数量25和Puma鞋多行。

 
Lot No Sl. No Product Size Qty 
1000 1 Addidas Shoe 8 25 
1001 1 Addidas Shoe 8 5 
1001 2 Addidas Shoe 9 15 
1001 3 Addidas Shoe 10 5 
1002 1 Addidas Shoe 10 25 
1003 1 Addidas Shoe 10 20 
1004 1 Puma Shoe  7 30 
1005 1 Puma Shoe  7 10 
1005 2 Puma Shoe  8 20 
1006 1 Puma Shoe  8 30 
1007 1 Puma Shoe  8 10 

请帮我搞定。我正在使用SQL Server 2005.

+3

你使用的是什么RDBMS? SQL Server,PostgreSQL,MySQL?如果你显示给定的输入和期望的输出,它也会有所帮助。 –

+0

为什么每个'Product'的第一个都有一个'Lot Qty'?看来你想采取'采购。 Qty'并将该产品的所有订单拆分为'Lot Qty'批次,尽管我在您的输出中看到了多个模式,所以要弄清楚您的实际规则有些困难。 –

+0

产品'Addidas鞋'被拆分成多行,具体取决于其批量25和'Puma鞋',根据其批量数量30分成多行。 –

回答

2

我确定这不会给我很多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

+0

查看更新的答案和小提琴 –

+0

产品的一个小问题'彪马鞋'[批号..]是从1000 –

+0

开始看到更新:) –

相关问题