SQL脚本根据条件将数据行拆分为多行

时间:2011-08-25 04:13:43

标签: sql-server-2005 tsql

我希望根据最佳批量(OLQ)拆分订单以生成多个工单,这意味着工单中的数量不会超过OLQ。

这是我的订单表样本数据:

Order   Item    Product Qty
OR-01   I-001   PRD-01  70
OR-01   I-001   PRD-02  15
OR-01   I-001   PRD-03  55

此订单的OLQ为30,因此工单数量的总和不应超过30.但工单可以包含同一商品的多个产品(商品为产品的父产品)。
以下是我希望将此订单拆分为基于OLQ创建工单的方式:

Order   WorkOrd Seq Item    Product Qty
OR-01   WO-0001 001 I-001   PRD-01  30
OR-01   WO-0002 001 I-001   PRD-01  30
OR-01   WO-0003 001 I-001   PRD-01  10
OR-01   WO-0003 002 I-001   PRD-02  15
OR-01   WO-0003 003 I-001   PRD-03  5
OR-01   WO-0004 001 I-001   PRD-03  30
OR-01   WO-0005 001 I-001   PRD-03  20

请注意,WO-0003有三种产品,分别为10,15和5,总数为30.另请注意,最后的工作订单WO-0005只有20个数量(剩下的数量)。

在附件中,我突出显示了不同颜色的工单,以便于理解。Order to Work Order conversion

请帮助我实现这一目标。

提前致谢。

2 个答案:

答案 0 :(得分:3)

由于item在这里没有意义,我从sql中删除了它。

declare @t table(order1 varchar(5), product varchar(6), seqcheck int)

insert @t values('OR-01','PRD-01',70) 
insert @t values('OR-01','PRD-02',15) 
insert @t values('OR-01','PRD-03',55) 

;with 
b as
(
select order1, product, seqcheck - 30 seqcheck, case when seqcheck > 30 then 30 else seqcheck end quantity, 1 seq, 1 workorder
from @t
where product = 'PRD-01'
union all
select order1, product, seqcheck - 30, case when seqcheck > 30 then 30 else seqcheck end quantity, 1 seq, workorder + 1
from b
where seqcheck > 0
union all
select t.order1, t.product, t.seqcheck + b.seqcheck, case when t.seqcheck + b.seqcheck >= 0 then -b.seqcheck else t.seqcheck end quantity, seq + 1, workorder
from b join @t t on 
cast(stuff(b.product, 1,4, '') as int) = cast(stuff(t.product, 1,4, '') as int) - 1
where b.seqcheck <= 0
)
select order1 [order], 'WO-' + left('000'+ cast(workorder as varchar(4)), 4) workord, right('000'+ cast(seq as varchar(3)), 3) seq, product, quantity from b
option(MAXRECURSION 0)

结果:

order workord seq  product quantity
----- ------- ---- ------- -----------
OR-01 WO-0001 001  PRD-01  30
OR-01 WO-0002 001  PRD-01  30
OR-01 WO-0003 001  PRD-01  10
OR-01 WO-0003 002  PRD-02  15
OR-01 WO-0003 003  PRD-03  5
OR-01 WO-0004 001  PRD-03  30
OR-01 WO-0005 001  PRD-03  20

答案 1 :(得分:1)

我不喜欢使用游标,但有时它们很方便。

你走了:

-- Test data
declare @orders table 
    (Order_a varchar(20),
     Item varchar(20),
     Product varchar(20),
     Qty int)

insert into @orders
select 'OR-01',   'I-001',   'PRD-01',  70
union all
select 'OR-01',   'I-001',   'PRD-02',  15
union all
select 'OR-01',   'I-001',   'PRD-03',  55

-- End test data

declare @workorders table 
    (Order_a varchar(20),
     WorkOrd varchar(20),
     Seq int,
     Item varchar(20),
     Product varchar(20),
     Qty int)


declare @olq int
set @olq = 30

declare @qty_left int
set @qty_left = @olq

declare @wo int
set @wo = 1

declare @seq int
set @seq = 1

declare @Order_a varchar(20)  
  ,@Item varchar(20)
  ,@Product varchar(20)
  ,@Qty int

-- Declare and set the cursor    
declare qtycursor cursor for    
select Order_a  
  ,Item  
  ,Product  
  ,Qty  
from @orders

open qtycursor    
fetch next from qtycursor into @Order_a, @Item, @Product, @Qty    
while @@fetch_status = 0     
begin    

    while @Qty <> 0
    begin
        if @Qty < @qty_left
        begin
            insert into @workorders
            select @Order_a, 'WO-'+CAST(@wo as varchar), @seq, @Item, @Product, @Qty

            set @seq = @seq + 1 
            set @qty_left = @qty_left - @Qty
            set @Qty = 0
        end
        else
        begin
            insert into @workorders
            select @Order_a, 'WO-'+CAST(@wo as varchar), @seq, @Item, @Product, @qty_left

            set @Qty = @Qty - @qty_left
            if @Qty > 0
            begin
                set @seq = 1    
            end
            set @wo = @wo + 1
            set @qty_left = @olq

        end
    end




fetch next from qtycursor into @Order_a, @Item, @Product, @Qty    
end    
close qtycursor    
deallocate qtycursor    

select * from @workorders