【问题标题】:How to use WHILE LOOP to add value to list with condition, SQL Server 2008如何使用 WHILE LOOP 将值添加到有条件的列表中,SQL Server 2008
【发布时间】:2015-07-08 07:45:47
【问题描述】:

我有一个循环查询,场景如下:

  • orderqty = 每个循环增加值 1
  • runningstock = 每个循环减少 1 个值
  • allocateqty = orderqty > 0 且 runningstock > 0 然后 1 else 的情况 0
  • 循环直到 runningstock=0 或 total allocation=stockqty

查询:

DECLARE @RESULT TABLE (priority int,partcode nvarchar(50),orderqty int, runningstock int, allocateqty int)
DECLARE @ORDER TABLE(priority int,partcode nvarchar(50),orderqty int)
DECLARE @STOCK TABLE(partcode nvarchar(50),stockqty int)

INSERT INTO @ORDER (priority,partcode,orderqty)
VALUES(1,'A',2),
    (2,'A',10),
    (3,'A',3),
    (4,'A',8);

INSERT INTO @STOCK(partcode,stockqty)
VALUES('A',20);

DECLARE @allocateqty int=1
DECLARE @runningstock int=(SELECT stockqty FROM @stock)

WHILE @runningstock>=0
BEGIN
    INSERT INTO @RESULT(priority,partcode,orderqty,runningstock,allocateqty)
    SELECT priority,
           partcode, 
           orderqty,
           @runningstock,
           CASE WHEN @runningstock > 0 AND orderqty > 0 THEN 1 ELSE 0 END
    FROM @order
    SET @runningstock -=1
 END

SELECT * FROM @Result

GO

结果:

priority    partcode    orderqty    runningstock    allocateqty
1   A   2   20  1
2   A   10  20  1
3   A   3   20  1
4   A   8   20  1
1   A   2   19  1
2   A   10  19  1
3   A   3   19  1
4   A   8   19  1
1   A   2   18  1
2   A   10  18  1
3   A   3   18  1
4   A   8   18  1
1   A   2   17  1
2   A   10  17  1
3   A   3   17  1
4   A   8   17  1
1   A   2   16  1
2   A   10  16  1
3   A   3   16  1
4   A   8   16  1
1   A   2   15  1
2   A   10  15  1
3   A   3   15  1
4   A   8   15  1
1   A   2   14  1
2   A   10  14  1
3   A   3   14  1
4   A   8   14  1
1   A   2   13  1
2   A   10  13  1
3   A   3   13  1
4   A   8   13  1
1   A   2   12  1
2   A   10  12  1
3   A   3   12  1
4   A   8   12  1
1   A   2   11  1
2   A   10  11  1
3   A   3   11  1
4   A   8   11  1
1   A   2   10  1
2   A   10  10  1
3   A   3   10  1
4   A   8   10  1
1   A   2   9   1
2   A   10  9   1
3   A   3   9   1
4   A   8   9   1
1   A   2   8   1
2   A   10  8   1
3   A   3   8   1
4   A   8   8   1
1   A   2   7   1
2   A   10  7   1
3   A   3   7   1
4   A   8   7   1
1   A   2   6   1
2   A   10  6   1
3   A   3   6   1
4   A   8   6   1
1   A   2   5   1
2   A   10  5   1
3   A   3   5   1
4   A   8   5   1
1   A   2   4   1
2   A   10  4   1
3   A   3   4   1
4   A   8   4   1
1   A   2   3   1
2   A   10  3   1
3   A   3   3   1
4   A   8   3   1
1   A   2   2   1
2   A   10  2   1
3   A   3   2   1
4   A   8   2   1
1   A   2   1   1
2   A   10  1   1
3   A   3   1   1
4   A   8   1   1
1   A   2   0   0
2   A   10  0   0
3   A   3   0   0
4   A   8   0   0

正确的应该是这样的:

priority    partcode    orderqty    runningstock    allocateqty
1   A   2   20  1
2   A   10  19  1
3   A   3   18  1
4   A   8   17  1
1   A   1   16  1
2   A   9   15  1
3   A   2   14  1
4   A   7   13  1
1   A   0   12  0
2   A   8   12  1
3   A   1   11  1
4   A   6   10  1
1   A   0   9   0
2   A   7   9   1
3   A   0   8   0
4   A   5   8   1
1   A   0   7   0
2   A   6   7   1
3   A   0   6   0
4   A   4   6   1
1   A   0   5   0
2   A   5   5   1
3   A   0   4   0
4   A   3   4   1
1   A   0   3   0
2   A   4   3   1
3   A   0   2   0
4   A   2   2   1
1   A   0   1   0
2   A   3   1   1
3   A   0   0   0

【问题讨论】:

    标签: sql sql-server while-loop


    【解决方案1】:

    您还可以遍历您的优先级并确保相应地更新 orderqty。我会做这样的事情:

    DECLARE @allocatedqty int = 0
    DECLARE @allocateqty int = 1
    DECLARE @runningstock int = (SELECT stockqty FROM @stock)
    
    WHILE @runningstock>=0
    BEGIN
        DECLARE @priority int
        SELECT TOP 1 @priority = priority FROM @order ORDER BY priority ASC
    
        WHILE @priority <= (SELECT MAX(priority) FROM @order)
        BEGIN
            DECLARE @orderqty int
            SELECT @orderqty = orderqty - @allocatedqty FROM @order WHERE priority = @priority
            SELECT @allocateqty = CASE WHEN @runningstock > 0 AND @orderqty > 0 THEN 1 ELSE 0 END
    
            INSERT INTO @RESULT(priority,partcode,orderqty,runningstock,allocateqty)
            SELECT @priority,
                   partcode, 
                   CASE WHEN @orderqty >= 0 THEN @orderqty ELSE 0 END AS orderqty,
                   @runningstock,
                   @allocateqty
            FROM @order 
            WHERE priority = @priority
    
            SET @priority += 1      
            SET @runningstock = @runningstock - @allocateqty
        END
        SET @allocatedqty += 1
    
        IF (@runningstock <= 0) BREAK 
     END
    
    SELECT * FROM @Result
    
    GO
    

    【讨论】:

    • 你让我开心:),这与一个部分代码完美配合,以防我有多个部分代码(A、B、C..)它错误:子查询返回超过 1 个值。当子查询跟随 =、!=、、>= 或子查询用作表达式时,这是不允许的。
    【解决方案2】:

    应尽可能避免在 sql 中循环。这将为您提供所描述的结果(除非您的倒计时中有 2 个错误):

    DECLARE @ORDER TABLE(priority int,partcode nvarchar(50),orderqty int)
    
    INSERT INTO @ORDER (priority,partcode,orderqty)
    VALUES(1,'A',2),
        (2,'A',10),
        (3,'A',3),
        (4,'A',8);
    
    DECLARE @runningstock INT = 20
    ;WITH CTE AS
    (
      SELECT 
        priority, 
        partcode, 
        orderqty, 
        @runningstock + 1 - priority runningstock, 
        sign(orderqty) allocateqty
      FROM @ORDER
      UNION ALL
      SELECT 
        priority, 
        partcode, 
        orderqty - sign(orderqty), 
        runningstock - 4, 
        sign(orderqty - sign(orderqty))
      FROM CTE
      WHERE runningstock > 3
    )
    SELECT 
      priority, partcode, orderqty, runningstock, allocateqty
    FROM CTE
    ORDER BY runningstock desc, priority
    

    结果:

    priority     partcode     orderqty     runningstock  allocateqty
    1            A            2            20            1
    2            A            10           19            1
    3            A            3            18            1
    4            A            8            17            1
    1            A            1            16            1
    2            A            9            15            1
    3            A            2            14            1
    4            A            7            13            1
    1            A            0            12            0
    2            A            8            11            1
    3            A            1            10            1
    4            A            6            9             1
    1            A            0            8             0
    2            A            7            7             1
    3            A            0            6             0
    4            A            5            5             1
    1            A            0            4             0
    2            A            6            3             1
    3            A            0            2             0
    4            A            4            1             1
    1            A            0            0             0
    

    【讨论】:

    • @t-clause.dk totalallocatedqty=15 其中运行库存=20 和 orderqty=23,如果 stockqty
    【解决方案3】:

    不是最好的方法,但你会得到预期的结果

    DECLARE @RESULT TABLE (priority int,partcode nvarchar(50),orderqty int, runningstock int, allocateqty int)
    DECLARE @ORDER TABLE(priority int,partcode nvarchar(50),orderqty int)
    DECLARE @STOCK TABLE(partcode nvarchar(50),stockqty int)
    
    INSERT INTO @ORDER (priority,partcode,orderqty)
    VALUES(1,'A',2),
          (2,'A',10),
          (3,'A',3),
          (4,'A',8);
    
    INSERT INTO @STOCK(partcode,stockqty)
    VALUES ('A',20);
    
    DECLARE @allocateqty int=1
    DECLARE @runningstock int=(SELECT stockqty FROM @stock)
    
    DECLARE @OutputTbl TABLE (orderqty INT)
    
    WHILE @runningstock>0
    BEGIN
        INSERT INTO @RESULT(priority,partcode,orderqty,runningstock,allocateqty)
        OUTPUT inserted.allocateqty INTO @OutputTbl
        SELECT priority,
               partcode, 
               orderqty,
               @runningstock,
               CASE WHEN @runningstock > 0 AND orderqty > 0 THEN 1 ELSE 0 END
        FROM @order
        WHERE priority = 1
        
        SELECT @runningstock -=  SUM(orderqty) FROM @OutputTbl
        UPDATE @order SET orderqty -= (SELECT SUM(orderqty) FROM @OutputTbl) WHERE priority = 1 
        DELETE FROM @OutputTbl
    
        INSERT INTO @RESULT(priority,partcode,orderqty,runningstock,allocateqty)
        OUTPUT inserted.allocateqty INTO @OutputTbl
        SELECT priority,
               partcode, 
               orderqty,
               @runningstock,
               CASE WHEN @runningstock > 0 AND orderqty > 0 THEN 1 ELSE 0 END
        FROM @order
        WHERE priority = 2
        
        SELECT @runningstock -=  SUM(orderqty) FROM @OutputTbl
        UPDATE @order SET orderqty -= (SELECT SUM(orderqty) FROM @OutputTbl) WHERE priority = 2
        DELETE FROM @OutputTbl
    
        INSERT INTO @RESULT(priority,partcode,orderqty,runningstock,allocateqty)
        OUTPUT inserted.allocateqty INTO @OutputTbl
        SELECT priority,
               partcode, 
               orderqty,
               @runningstock,
               CASE WHEN @runningstock > 0 AND orderqty > 0 THEN 1 ELSE 0 END
        FROM @order
        WHERE priority = 3
        
        SELECT @runningstock -=  SUM(orderqty) FROM @OutputTbl
        UPDATE @order SET orderqty -= (SELECT SUM(orderqty) FROM @OutputTbl) WHERE priority = 3
        DELETE FROM @OutputTbl
        
    
        INSERT INTO @RESULT(priority,partcode,orderqty,runningstock,allocateqty)
        OUTPUT inserted.allocateqty INTO @OutputTbl
        SELECT priority,
               partcode, 
               orderqty,
               @runningstock,
               CASE WHEN @runningstock > 0 AND orderqty > 0 THEN 1 ELSE 0 END
        FROM @order
        WHERE priority = 4
        
        SELECT @runningstock -=  SUM(orderqty) FROM @OutputTbl
        UPDATE @order SET orderqty -= (SELECT SUM(orderqty) FROM @OutputTbl) WHERE priority = 4
        DELETE FROM @OutputTbl
    
        print @runningstock
     END
    
    SELECT * FROM @Result
    
    GO
    

    如您所见,我将优先级分为 4 个步骤,在每个步骤中我都会降低 跑步机

    SELECT @runningstock -=  SUM(orderqty) FROM @OutputTbl
    

    订单数量

    UPDATE @order SET orderqty -= (SELECT SUM(orderqty) FROM @OutputTbl) WHERE priority = 1
    

    基于分配数量

    OUTPUT inserted.allocateqty INTO @OutputTbl
    

    【讨论】:

    • 谢谢。反正我的实际数据是超过 10,00 的优先级。有没有办法让它更容易和自动?我的意思是在这里您需要手动更新订单并设置 where 子句。
    【解决方案4】:
    WHILE @runningstock>=0
    BEGIN
        INSERT INTO @RESULT(priority,partcode,orderqty,runningstock,allocateqty)
        SELECT priority,
               partcode, 
               orderqty,
               @runningstock,
               CASE WHEN @runningstock > 0 AND orderqty > 0 THEN 1 ELSE 0 END
        FROM @ORDER
        
        SET @runningstock =@runningstock-1
     END
    

    【讨论】:

    • SET @runningstock -=1和@runningstock =@runningstock-1没有区别
    猜你喜欢
    • 1970-01-01
    • 2013-02-17
    • 2011-09-01
    • 2012-08-30
    • 2013-05-31
    • 2023-03-29
    • 1970-01-01
    • 2012-05-10
    • 2022-01-22
    相关资源
    最近更新 更多