sql-servercommon-table-expressioninventory-management

SQL Server calculating the current stock of items with stock taking corrections


First of all, if this is answered somewhere, I apologize.

I'm trying to wrap my head around the following problem. I have a query that returns the following values from the inventory regarding one product:

RowId Entry Exit StockTaking
1 0 0 2880
2 1200 0 0
3 0 800 0
4 0 800 0
5 0 480 2000
6 600 0 0
7 0 800 0
8 0 1000 0

This part is easy but the result should look like this:

RowId ProductId Entry Exit StockTaking CurrentStock
1 3 0 0 2880 2880
2 3 1200 0 0 4080
3 3 0 800 0 3280
4 3 0 800 0 2480
5 3 0 480 2000 2000
6 3 600 0 0 2600
7 3 0 800 0 1800
8 3 0 1000 0 800

and from that the final value is 800 pcs on stock:

ProductID CurrentStock
3 800

In CurrentStock column is calculated value based on Entry, Sale and StockTaking columns. When we have stock-taking at the start is simple (for this sample let's say that all products start with stock-taking), in RowId = 1 we have CurrentStock identical to StockTaking value.

In RowId = 2 we have, entry of 1200 pcs, so CurrentStock is now 2880+1200 = 4080 pcs....

Now the problem arises in RowID = 5, CurrentStock before StockTaking was 2480 pcs, but we found only 2000 pcs

So we are taking StockTaking value as CurrentStock value so we can calculate from that value forward, and at the same time to level the columns we are making an exit for 480 pcs which are missing at that time.

I managed to handle this over some temp table and then iterating trough the records and updating the CurrentStock value but with larger dataset, it takes some time.

Any suggestions how to handle this with CTEs to avoid writing to temp tables is greatly appreciated.

Thanks


Solution

  • A bit quick n dirty solution:

    select  *
    ,   SUM(StockTaking + CASE WHEN StockTaking <= 0 THEN Entry - [Exit] ELSE 0 END) OVER(PARTITION BY StockGroup ORDER BY RowId) CurrentStock
    from (
        select  COUNT(CASE WHEN StockTaking > 0 THEN 1 END) OVER(ORDER BY RowID) AS StockGroup
        ,   *
        from 
        (
            VALUES  (1, 0, 0, 2880)
            ,   (2, 1200, 0, 0)
            ,   (3, 0, 800, 0)
            ,   (4, 0, 800, 0)
            ,   (5, 0, 480, 2000)
            ,   (6, 600, 0, 0)
            ,   (7, 0, 800, 0)
            ,   (8, 0, 1000, 0)
        ) t (RowId,Entry,[Exit],StockTaking)
    ) x
    

    First you create groups of rows by counting each inventory row as start of a group. Then you summarize changes to the stock sorted by rowID.

    Important that for rows where stocktaking is taken, we don't add Entry / Exit values. So if you first do inventory and then take stock on the same "row", it will display wrong results. Probably you have info that can solve this problem, but it's not in your example.