Search code examples
sqlsql-servert-sqlsql-server-2012cursor

How could I re-write this cursor to calculate running total?


So I have some code which drops and re-creates a table each time, then uses a cursor to go through and calculate a running total of stock amounts. The code for the cursor is as below (table names obscured):

DECLARE @Cust_Name nvarchar(250),
              @Cust_Postcode nvarchar(50),
              @MatchCode_Product nvarchar(50),
              --@Stock int,
              @DateKey nvarchar(8),
              @Ordered int

DECLARE StockCursor CURSOR 
  LOCAL STATIC READ_ONLY FORWARD_ONLY
FOR 
SELECT
       Cust_Name, Cust_Postcode, MatchCode_Product, DateKey
FROM
       WRK_TFT_DEPOT_STOCK
WHERE
    Cust_Name NOT LIKE {redacted}

OPEN StockCursor
FETCH NEXT FROM StockCursor INTO @Cust_Name, @Cust_Postcode, @MatchCode_Product, @DateKey

WHILE @@FETCH_STATUS = 0
BEGIN
       UPDATE
              WRK_TFT_DEPOT_STOCK
       SET

                     Ordered = isnull((
                                  SELECT
                                         sum(cast(MO.Quantity as int))
                                  FROM
                                         {redacted }DE
                                         INNER JOIN {redacted} MO
                                         ON DE.Order_No = MO.Order_No
                                  WHERE
                                         DE.Cust_Name = @Cust_Name
                                         AND
                                         DE.Cust_Postcode = @Cust_Postcode
                                         AND
                                         MatchCode_Product = @MatchCode_Product
                                         AND
                                         CAST(Year(DE.Delivery_Date) AS VARCHAR) + RIGHT('0' + CAST(Month(DE.Delivery_Date) AS VARCHAR), 2) + 
                                            RIGHT('0' + CAST(Day(DE.Delivery_Date) AS VARCHAR), 2)  <= @DateKey
                                         AND DE.Cust_Name NOT LIKE {redacted}
                                     ),0)
       WHERE
              Cust_Name = @Cust_Name
              AND
              Cust_Postcode = @Cust_Postcode
              AND
              MatchCode_Product = @MatchCode_Product
              AND
              DateKey = @DateKey 

       FETCH NEXT FROM StockCursor INTO @Cust_Name, @Cust_Postcode, @MatchCode_Product, @DateKey
END

CLOSE StockCursor
DEALLOCATE StockCursor

UPDATE
       WRK_TFT_DEPOT_STOCK
SET
       Stock = StartStock + Ordered

The code works fine but my issue with it is that it takes ages to run, and the time it takes to run is increasing over time as I'm loading daily data into the source tables.

Would anyone be able to help me out with re-writing this more efficiently? From looking around it looks like windowed functions would help a lot but I'm not familiar with them.

The column 'Stock' is the running total, 'StartStock' is the initial amount and 'Ordered' is what we need to add when it comes in.


Solution

  • An example with rows unbounded preceding:

    SELECT TOP 1000 [Dato]
          ,[Department]
          ,[Amount]
          ,runningtotal = SUM(amount) over(order by dato ROWS UNBOUNDED PRECEDING)
      FROM [LegOgSpass].[dbo].[amounts]
    

    Result

    enter image description here