以2400为一个单位将数据拆分到不同区域中

目的:

将左边表数据变成右边数据,以2400为一个单位放到一个区域里面,一个区域只允许放一张SO,新的SO需要另外放一个区域

 

1.创建TB和插入测试数据

CREATE TABLE [dbo].[testtb](
    [Sonum] [varchar](10NULL,
    [ItemNum] [varchar](30NULL,
    [ItemQty] [int] NULL,
    [SoArea] [varchar](30NULL
ON [PRIMARY]

GO

SET ANSI_PADDING OFF
GO

ALTER TABLE [dbo].[testtb] ADD  CONSTRAINT [DF_testtb_Sonum]  DEFAULT (''FOR [Sonum]
GO

ALTER TABLE [dbo].[testtb] ADD  CONSTRAINT [DF_testtb_ItemNum]  DEFAULT (''FOR [ItemNum]
GO

ALTER TABLE [dbo].[testtb] ADD  CONSTRAINT [DF_testtb_ItemQty]  DEFAULT ((0)) FOR [ItemQty]
GO

ALTER TABLE [dbo].[testtb] ADD  CONSTRAINT [DF_testtb_SoArea]  DEFAULT (''FOR [SoArea]
GO



CREATE TABLE [dbo].[testtb2](
    [Sonum] [varchar](10NULL,
    [ItemNum] [varchar](30NULL,
    [ItemQty] [int] NULL,
    [SoArea] [varchar](30NULL
ON [PRIMARY]

GO

SET ANSI_PADDING OFF
GO

ALTER TABLE [dbo].[testtb2] ADD  CONSTRAINT [DF_testtb2_Sonum]  DEFAULT (''FOR [Sonum]
GO

ALTER TABLE [dbo].[testtb2] ADD  CONSTRAINT [DF_testtb2_ItemNum]  DEFAULT (''FOR [ItemNum]
GO

ALTER TABLE [dbo].[testtb2] ADD  CONSTRAINT [DF_testtb2_ItemQty]  DEFAULT ((0)) FOR [ItemQty]
GO

ALTER TABLE [dbo].[testtb2] ADD  CONSTRAINT [DF_testtb2_SoArea]  DEFAULT (''FOR [SoArea]
GO



CREATE TABLE [dbo].[testtb3](
    [Sonum] [varchar](10NULL,
    [ItemNum] [varchar](30NULL,
    [ItemQty] [int] NULL,
    [SoArea] [varchar](30NULL
ON [PRIMARY]

GO

SET ANSI_PADDING OFF
GO

ALTER TABLE [dbo].[testtb3] ADD  CONSTRAINT [DF_testtb3_Sonum]  DEFAULT (''FOR [Sonum]
GO

ALTER TABLE [dbo].[testtb3] ADD  CONSTRAINT [DF_testtb3_ItemNum]  DEFAULT (''FOR [ItemNum]
GO

ALTER TABLE [dbo].[testtb3] ADD  CONSTRAINT [DF_testtb3_ItemQty]  DEFAULT ((0)) FOR [ItemQty]
GO

ALTER TABLE [dbo].[testtb3] ADD  CONSTRAINT [DF_testtb3_SoArea]  DEFAULT (''FOR [SoArea]
GO



CREATE TABLE [dbo].[AreaDetail](
    [ID] [int] IDENTITY(1,1NOT NULL,
    [areaid] [varchar](5NOT NULL,
    [Emtry] [char](10NOT NULL
ON [PRIMARY]

GO

SET ANSI_PADDING OFF
GO

ALTER TABLE [dbo].[AreaDetail] ADD  CONSTRAINT [DF_AreaDetail_areaid]  DEFAULT (''FOR [areaid]
GO

ALTER TABLE [dbo].[AreaDetail] ADD  CONSTRAINT [DF_AreaDetail_Emtry]  DEFAULT ('Y'FOR [Emtry]
GO






insert into testtb values('SO1','Item1001','2000','')
insert into testtb values('SO1','Item1002','600','')
insert into testtb values('SO2','Item1003','3500','')
insert into testtb values('SO2','Item1004','1400','')
insert into testtb values('SO2','Item1005','1000','')
insert into testtb values('SO3','Item1006','7500','')

insert into testtb3 values('SO1','Item1001','2000','A1')
insert into testtb3 values('SO1','Item1002','400','A1')
insert into testtb3 values('SO1','Item1002','200','A2')
insert into testtb3 values('SO2','Item1003','2400','A3')
insert into testtb3 values('SO2','Item1003','1100','A4')
insert into testtb3 values('SO2','Item1004','1300','A4')
insert into testtb3 values('SO2','Item1004','100','A5')
insert into testtb3 values('SO2','Item1005','1000','A5')
insert into testtb3 values('SO3','Item1006','2400','A6')
insert into testtb3 values('SO3','Item1006','2400','A7')
insert into testtb3 values('SO3','Item1006','2400','A8')
insert into testtb3 values('SO3','Item1006','300','A9')



insert into AreaDetail(areaid,Emtry) values('A1','Y')
insert into AreaDetail(areaid,Emtry) values('A2','Y')
insert into AreaDetail(areaid,Emtry) values('A3','Y')
insert into AreaDetail(areaid,Emtry) values('A4','Y')
insert into AreaDetail(areaid,Emtry) values('A5','Y')
insert into AreaDetail(areaid,Emtry) values('A6','Y')
insert into AreaDetail(areaid,Emtry) values('A7','Y')
insert into AreaDetail(areaid,Emtry) values('A8','Y')
insert into AreaDetail(areaid,Emtry) values('A9','Y')

select * from testtb
select * from testtb3
select * from AreaDetail
View Code

2.方案一:

 

alter proc LandorSP
as
--CREATE TABLE [dbo].[Format_testtb](
--
[ID] int identity(1,1) primary key,
--
 [Sonum] [varchar](10) NULL,
--
 [ItemNum] [varchar](30) NULL ,
--
 [ItemQty] [int] NULL,
--
 [SoArea] [varchar](30) NULL
--
) ON [PRIMARY]

declare @ID int
declare @Sonum nvarchar(100
declare @ItemNum nvarchar(100
declare @ItemQty int
declare @NowSonum nvarchar(100)
declare @SumItemQty int    --用于循环记录当前SONUM货数累加数
declare @AllItemQty int    --用于记录累加当次货前的@SumItemQty数,循环时需要前后计后使用
declare @AreaId varchar(5)

truncate table [Format_testtb];
update AreaDetail set Emtry='Y'

-----1.处理大于2400
insert into [Format_testtb](Sonum,ItemNum,ItemQty,SoArea)
select Sonum,ItemNum,ItemQty,SoArea from [dbo].[testtb]  order by Sonum asc;

 

 while exists(select * from [Format_testtb] where ItemQty>2400)
 begin

     declare  @tb01 table(ID int);
     insert into  @tb01(ID) select ID from [Format_testtb] where ItemQty>2400;
     insert into [Format_testtb]    (    Sonum,ItemNum,ItemQty,SoArea)
        select Sonum,ItemNum,2400,SoArea from [dbo].[Format_testtb] --with(nolock) 
        where ID in (select ID from @tb01);

     update [Format_testtb] set ItemQty=(ItemQty-2400where ID in (select ID from @tb01);

     delete from  @tb01;
 end

update [Format_testtb]set SoArea='OK'where ItemQty=2400;

--select * from [Format_testtb];
--
select Sonum,ItemNum,ItemQty,SoArea from [dbo].[testtb]  order by Sonum asc;

--select Sonum,sum(ItemQty) as total 
--
from [Format_testtb] 
--
where  SoArea<>'OK' 
--
group by Sonum

update [Format_testtb]set SoArea='OK'where SoArea<>'OK' and Sonum in
(select Sonum from [Format_testtb] where  SoArea<>'OK' group by Sonum having sum(ItemQty) <=2400)




 ---2.将OK的逐个存入区位
--
select * from [Format_testtb] where soarea='OK'

declare Cursor_BIG cursor for 
    select  id,Sonum from [Format_testtb] where soarea='OK' order by ItemQty desc
open Cursor_BIG
fetch next from Cursor_BIG into @ID,@Sonum
while @@fetch_status=0
begin 
    select TOP 1 @AreaId=areaid from AreaDetail WHERE Emtry='Y' ORDER BY ID ---add 
    update [Format_testtb] set SoArea=@AreaId where ID=@ID
    update AreaDetail set Emtry='N' where areaid=@AreaId--填充区域后,要将它变成非空状态
    
    fetch next from Cursor_BIG into @ID,@Sonum
end 
close Cursor_BIG
DEALLOCATE Cursor_BIG
 

---3.处理小于2400的数据--
--
select  Sonum,ItemNum,ItemQty,SoArea from [Format_testtb];
--
select Sonum,ItemNum,ItemQty,SoArea from [dbo].[testtb]  order by Sonum asc;

 --select Sonum,sum(ItemQty) as total from [Format_testtb] where  SoArea<>'OK' group by Sonum

--SET @AllItemQty = 0
SET @SumItemQty = 0
set @NowSonum=''
SET @AreaId=''


declare Cursor_DBname cursor for 
select  id,Sonum,ItemNum,ItemQty from [Format_testtb] where soarea=''
open Cursor_DBname
fetch next from Cursor_DBname into @ID,@Sonum,@ItemNum,@ItemQty
while @@fetch_status=0
begin 
    if @NowSonum<>@Sonum    --开始新的SONUM,ItemQty值复位
    begin
        if @SumItemQty>0 --当前区域中的数量大于0,代表旧的SO已经有物料存放在此区域中,需要将状态更新为N
        begin 
            update AreaDetail set Emtry='N' where areaid=@AreaId
        end
        
        SET @SumItemQty = 0
        set @NowSonum=@Sonum    --将新的区名赋给@NowSonum,下次循环再判断是不是又换区域了
        
        select TOP 1 @AreaId=areaid from AreaDetail WHERE Emtry='Y' ORDER BY ID ---add 
        update [Format_testtb] set SoArea=@AreaId where ID=@ID
        SET @SumItemQty = 2400- @ItemQty --当前区域中还能放置了多少数量
        --break;
    end
    else
    begin
        if @SumItemQty>=@ItemQty  --当前区域中还能放置了多少数量 大于 物料数量直接放
        begin
            --select @ID
            --SELECT @AreaId
            --SELECT @SumItemQty
            update [Format_testtb] set SoArea=@AreaId where ID=@ID
            SET @SumItemQty=@SumItemQty-@ItemQty
            
        end
        else
        begin  --当前区域不够放
            select @ID
            SELECT @AreaId
            SELECT @ItemQty
            SELECT @SumItemQty
            update [Format_testtb] set SoArea=@AreaId , ItemQty=@SumItemQty where ID=@ID
            update AreaDetail set Emtry='N' where areaid=@AreaId--填充区域后,要将它变成非空状态
            
            select TOP 1 @AreaId=areaid from AreaDetail WHERE Emtry='Y' ORDER BY ID 
            insert into [Format_testtb](Sonum,ItemNum,ItemQty,SoArea) --新增另一条记录放到另一个格中
                select Sonum,ItemNum,@ItemQty-@SumItemQty,@AreaId from testtb where ID=@ID
            set @SumItemQty=2400-(@ItemQty-@SumItemQty )
            
            SELECT @SumItemQty
            --break;
        end
    end

    fetch next from Cursor_DBname into @ID,@Sonum,@ItemNum,@ItemQty
end 
close Cursor_DBname
DEALLOCATE Cursor_DBname

--exec LandorSP
--
select * from testtb
--
select * from Format_testtb  ORDER BY SONUM,SOAREA
View Code

3.方案二:

declare @b bit
set @b=0

declare @a int    --用于生成放置的新区域
select @a=cast(substring(MAX(soarea),2,100as intfrom testtb

declare @tempa nvarchar(100)

declare @i int    --用于生成新记录的主键ID号
select @i=MAX(id) from testtb

declare @AllItemQty int    --用于记录累加当次货前的@SumItemQty数,循环时需要前后计后使用
SET @AllItemQty = 0
declare @SumItemQty int    --用于循环记录当前SONUM货数累加数
SET @SumItemQty = 0

declare @NowSonum nvarchar(100--循环时判断不同的SONUM时 @SumItemQty归零
select top(1@NowSonum=Sonum  from testtb order by sonum    --该变量用于循环时判断是不是开始新的区域了,如果是那@SumItemQty等变量需要复位归零

declare @ID int
declare @Sonum nvarchar(100
declare @ItemNum nvarchar(100
declare @ItemQty int

declare Cursor_DBname cursor for 
select ID,Sonum,Itemnum,ItemQty from testtb --得到所有区,数量大于2400的,需要重新分派区域的记录
where sonum in
(
    select sonum from testtb
    group by sonum
    having SUM(itemqty)>2400
)
order by sonum,Itemnum asc

open Cursor_DBname
fetch next from Cursor_DBname into @ID,@Sonum,@ItemNum,@ItemQty
while @@fetch_status=0
begin 
    if @NowSonum<>@Sonum    --开始新的SONUM,ItemQty值复位
    begin
        SET @SumItemQty = 0
        SET @AllItemQty = 0
        set @b=0
        set @NowSonum=@Sonum    --将新的区名赋给@NowSonum,下次循环再判断是不是又换区域了
    end
    
    SET @SumItemQty = @SumItemQty + @ItemQty --当前区域中己放置了多少数量
    
    if @b=1
    UPDATE testtb SET soarea=@tempa WHERE ID=@ID    --如果@b为1,说明当前区己满,己存在的相同SONUM所放区必须使用新的区号
     
    if @SumItemQty>2400 
    begin
        if @SumItemQty-@AllItemQty>2400    --当前区域中的数量大于2400
        begin
            UPDATE testtb SET ItemQty=2400-@AllItemQty WHERE ID=@ID    --由于当批ItemQty总计己超过2400,必须分派新区
            set @b=1    --标识当前区域己满,以后相同的SONUM要用新区号了
            SET @SumItemQty=@SumItemQty-2400    --分派新区后,当前ItemQty还剩多少数量
            while (@SumItemQty>0)    --由于不知道剩多少数量,必须循环分区,每能循环一次加一个新分区,区中ItemQty数为2400,直到不够2400为止
            begin
                if @SumItemQty>2400    --判断是否还大于2400,以便能不能再分新的满ItemQty数区域
                BEGIN
                    insert into testtb(ID,Sonum,ItemNum,ItemQty,SoArea)values(@i+1,@Sonum,@ItemNum,2400,'A'+cast(@a+1 as varchar))    --加满货数区
                    set @SumItemQty=@SumItemQty-2400    --加了一个新满ItemQty区,剩余数量减2400
                    set @i=@i+1
                    set @a=@a+1
                END 
                else
                begin
                    insert into testtb(ID,Sonum,ItemNum,ItemQty,SoArea)values(@i+1,@Sonum,@ItemNum,@SumItemQty,'A'+ cast(@a+1 as varchar))    --把不够2400的数加入最新区
                    set @tempa='A'+ cast(@a+1 as varchar)
                    set @i=@i+1
                    set @a=@a+1
                    set @b=1
                    break
                end
            end
        end
        else
        begin
            UPDATE testtb SET ItemQty=2400-@AllItemQty WHERE ID=@ID        --当前区域还可以放多少数量货,下一条记录中的ItemQty数足够填满它
            insert into testtb(ID,Sonum,ItemNum,ItemQty,SoArea)values(@i+1,@Sonum,@ItemNum,@ItemQty-(2400-@AllItemQty),'A'+ cast(@a+1 as varchar))    --当次游标中的ItemQty数,在填满上一个区域后还剩多少,把这些剩数放入新区域
            --上面两条SQL举个例子,比如ItemQty数累加己2000时,下一条记录的ItemQty数为1000的话,那就必须拿出400来填充上一个区域,剩下的600放入一个新的区域。
            set @tempa='A'+ cast(@a+1 as varchar)
            set @i=@i+1
            set @a=@a+1
            set @b=1
            SET @SumItemQty=@ItemQty-(2400-@AllItemQty)    --记录上一个区域己放了多少数量了
        end
    end 
        
    SET @AllItemQty = @SumItemQty
    fetch next from Cursor_DBname into @ID,@Sonum,@ItemNum,@ItemQty
end 
close Cursor_DBname
DEALLOCATE Cursor_DBname
View Code
原文地址:https://www.cnblogs.com/Snowfun/p/4595875.html