zoukankan      html  css  js  c++  java
  • 以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
  • 相关阅读:
    GMA Round 1 数列求单项
    GMA Round 1 双曲线与面积
    多线程环境中安全使用集合API(含代码)
    使用synchronized获取互斥锁的几点说明
    ThreadPoolExecutor线程池
    线程状态转换
    volatile关键字
    守护线程与线程阻塞的四种情况
    线程挂起,恢复与终止
    线程中断
  • 原文地址:https://www.cnblogs.com/Snowfun/p/4595875.html
Copyright © 2011-2022 走看看