Вычисление курсора SQL на основе предыдущих строк - PullRequest
0 голосов
/ 28 июня 2019

Я использую 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 не вычисляются - что мне не хватает?

Ответы [ 2 ]

1 голос
/ 28 июня 2019

Нет необходимости использовать курсор для такого сценария, если вам нужно выполнить расчет на основе предыдущей строки, вы можете использовать встроенные функции SQL-сервера - см. Пример ниже в качестве справки и вы можете изменить его согласноваше требование.

 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);
0 голосов
/ 28 июня 2019

Если кому-то интересно, я заставил его работать. Глупо на самом деле -

Я только что изменил приведенный ниже блок:

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. Ну что ж, спасибо всем, кто оставил комментарий.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...