【问题标题】:T SQL cursor calculation based on previous rowsT SQL 游标计算基于前几行
【发布时间】:2019-06-28 10:35:10
【问题描述】:

我使用的是 SQL Server 2016。

我有这张桌子:

CREATE TABLE [tblTEST] 
(
    RowID INT,
    SKU INT,
    Shop INT,
    Week INT,
    ShopPriority INT,    
    ShopStock INT,       
    Target_Stock INT,    
    Outbound INT,        
    Ration_Replen INT,   
    Open_Stk INT,        
    Closing_Stk INT,     
    Real_Open INT,       
    Unconst_Replen INT,     
    Rounded_Replen INT   
);

并填充值:

INSERT INTO dbo.tblTEST
VALUES (1, 111, 100, 1, 1, 50, 50, 50, 0, 5, 5, 5, 0, 0),
       (2, 111, 100, 1, 2, 50, 50, 50, 0, 0, 0, 0, 0, 0),
       (3, 111, 100, 1, 3, 50, 50, 50, 0, 0, 0, 0, 0, 0),
       (4, 111, 100, 1, 4, 50, 50, 50, 0, 0, 0, 0, 0, 0);

这将创建以下内容(由于此页面上的格式问题,我无法输入所有零:

RowID     SKU     Shop    Week   Prioirty   ShopStock    Target_Stock   Outbound     Ration_Replen    Open_Stk    Closing_Stk    Real_Open    Unconst_Replen   Rounded_Replen
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  1        111     100      1        1          50           50            50              0               5            5           5                               
  2        111     200      1        2          50           50            50              0                                                          
  3        111     300      1        3          50           50            50              0
  4        111     400      1        4          50           50            50      

但是,我需要执行计算来创建以下内容:

    RowID     SKU     Shop    Week   Prioirty   ShopStock    Target_Stock   Outbound     Ration_Replen    Open_Stk    Closing_Stk    Real_Open    Unconst_Replen   Rounded_Replen
    ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
      1        111     100      1        1          50           50            50              0               5            5           5                               
      2        111     200      1        2          50           50            50              0               5            5           5                    
      3        111     300      1        3          50           50            50              0               5            5           5
      4        111     400      1        4          50           50            50              0               5            5           5   

我正在使用下面的光标来尝试实现这一目标:

DECLARE @CurrentRow INT;
DECLARE @PreviousRow INT

DECLARE MinQty CURSOR FOR
    SELECT RowID
    FROM [tblTEST]
    WHERE [Week] IS NOT NULL
    ORDER BY [SKU], [Week], ShopPriority

OPEN MinQty

FETCH NEXT FROM MinQty INTO @CurrentRow

WHILE @@FETCH_STATUS = 0
BEGIN
    IF ((SELECT [Open_Stk]
         FROM [tblTEST]
         WHERE RowID = @CurrentRow) IS NULL)
    BEGIN
        UPDATE [tblTEST]
        SET [Open_Stk] = (SELECT [Closing_Stk]
                          FROM [tblTEST]
                          WHERE RowID = @PreviousRow)
        WHERE RowID = @CurrentRow

        UPDATE [tblTEST]
        SET [Real_Open] = (SELECT IIF([Open_Stk] >= 0, [Open_Stk], 0)
                           FROM [tblTEST]
                           WHERE RowID = @CurrentRow),          
            [Unconst_Replen] = (SELECT IIF(ShopStock + [Ration_Replen] < Target_Stock, IIF(Target_Stock - (ShopStock + [Ration_Replen]) < [Real_Open], Target_Stock - (ShopStock + [Ration_Replen]), [Real_Open]), 0)
                                FROM [tblTEST]
                                WHERE RowID = @CurrentRow),                 
            Rounded_Replen = (SELECT IIF(Unconst_Replen = 0, 0, IIF(Unconst_Replen < Outbound, Outbound, Unconst_Replen))
                              FROM [tblTEST]
                              WHERE RowID = @CurrentRow),
            Closing_Stk = (SELECT Open_Stk - IIF(Rounded_Replen > IIF(Open_Stk >= 0, Open_Stk, 0), 0, Rounded_Replen)
                           FROM [tblTEST]
                           WHERE RowID = @CurrentRow)
        WHERE RowID = @CurrentRow
    END

    SET @PreviousRow = @CurrentRow

    FETCH NEXT FROM MinQty INTO @CurrentRow
END

CLOSE MinQty
DEALLOCATE MinQty

但是,光标没有做任何事情 - 值保持不变并且 Open_Stk \ Closing_Stk 和 Real_Open 没有被计算 - 我错过了什么?

【问题讨论】:

  • 为什么首先使用CURSOR? RBAR 解决方案在 SQL Server 和其他 RDBMS 中非常缓慢。如果您想引用“上一个”行,为什么不使用LEAD/LAG
  • 游标只返回@CurrentRow,你的问题不应该出现在UPDATE [tblTEST]上。您是否针对单个 RowID 单独尝试过 UPDATE,并验证它是否符合您的预期?
  • @MarcGuillot 游标返回当前行但第一个 UPDATE 是 WHERE RowID = PreviousRow

标签: sql-server tsql database-cursor


【解决方案1】:

这种情况不需要使用游标,如果需要根据上一行进行计算,可以使用SQL server inbuild函数 - 参考下面的例子,你可以按照你的要求。

 SELECT tbl.RowID,
       tbl.SKU,
       tbl.Shop,
       tbl.Week,
       tbl.Prioirty,
       tbl.Replen,
       FIRST_VALUE(tbl.Open_Stk) OVER (PARTITION BY tbl.SKU ORDER BY tbl.RowID
                                     ROWS UNBOUNDED PRECEDING) -
       ISNULL(SUM(tbl.Replen) OVER (PARTITION BY tbl.SKU ORDER BY tbl.RowID
                                  ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING),0) AS OpenStk
FROM (VALUES (1,111,100,1,1,300,5000),           
             (2,111,200,1,2,200,NULL),
             (3,111,300,1,3,100,NULL),
             (4,111,400,1,4,250,NULL))tbl(RowID,SKU,Shop,[Week],Prioirty,Replen,Open_Stk);

【讨论】:

  • 这有帮助,但不仅是基于先前行的计算,这些先前的行也是计算
【解决方案2】:

如果有人感兴趣,我会开始工作。真傻——

我刚刚更改了以下块:

BEGIN
    IF ((SELECT [Open_Stk]
         FROM [tblTEST]
         WHERE RowID = @CurrentRow) IS NULL)

BEGIN
    IF (
            (
                SELECT [Open_Stk]
                FROM [tblTEST]
                WHERE RowID = @CurrentRow
                ) = 0

默认值为 0 而不是 NULL。哦,好的,感谢所有提供评论的人。

【讨论】:

    猜你喜欢
    • 2016-06-16
    • 2014-10-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-30
    • 1970-01-01
    • 2020-11-12
    • 1970-01-01
    相关资源
    最近更新 更多