Search code examples
sql-serversql-server-2008t-sqlcumulative-sumfulfillment

How to show order fulfilment in a SQL Server 2008 query


I am trying to think of a way on a SQL Server 2008 database to run through a sales order table and get open demand for a part, order it by due date, then look at a purchase order table and fulfill the sales orders by PO, ordering the PO supply by due date as well. At the same time, I need to show what PO(s) are fulfilling the sales order.

For example:

SO table

SO#     DueDate     Part Number  Required QTY
---------------------------------------------
100     9/3/16      1012          2
101     9/12/16     1012          1
107     10/11/16    1012          4
103     10/17/16    1012          7

PO table:

PO#     DueDate     Part Number  Ordered QTY
--------------------------------------------
331     9/1/16      1012          1
362     9/2/16      1012          1
359     9/24/16     1012          5
371     10/1/16     1012          3
380     10/10/16    1012          10

With this data, I would like to see this result:

SO#  DueDate     Part Number  Required QTY  PO number  QTY Used  QTY Remain
 --------------------------------------------------------------------------
100  9/3/16      1012          2             331         1         0 
100  9/3/16      1012          1             362         1         0
101  9/12/16     1012          1             359         1         4
107  10/11/16    1012          4             359         4         0
103  10/17/16    1012          7             371         3         0
103  10/17/16    1012          7             380         4         6

I have done this sales order fulfillment process before, but not to the point of breaking down what PO(s) are fulfilling the order, only to the point of summing all open supply, then running through and subtracting the supply from each sales order to get a running balance of supply left.

Many thanks in advance for your help.


Solution

  • I found a bit weird solution, hope it helps you. Maybe later I could optimize it, but now I post it as is:

    ;WITH cte AS (
        SELECT 1 as l
        UNION ALL
        SELECT l+1
        FROM cte
        WHERE l <= 1000000
    ), SO_cte AS (
        SELECT  *,
                ROW_NUMBER() OVER (ORDER BY DueDate ASC) as rn
        FROM SO s
        CROSS JOIN cte c
        WHERE c.l <= s.[Required QTY]
    ), PO_cte AS (
        SELECT  *,
                ROW_NUMBER() OVER (ORDER BY DueDate ASC) as rn
        FROM PO p
        CROSS JOIN cte c
        WHERE c.l <= p.[Ordered QTY]
    ), almost_done AS (
        SELECT DISTINCT     
                s.SO#,
                s.DueDate,
                s.[Part Number],
                p.PO#,
                s.[Required QTY],
                p.[Ordered QTY]
        FROM SO_cte s
        LEFT JOIN PO_cte p
            ON p.rn = s.rn
    ), final AS (
        SELECT  *,
                ROW_NUMBER() OVER (ORDER BY DueDate) AS RN
        FROM almost_done
    )
    
    SELECT  f.SO#,
            f.DueDate,
            f.[Part Number],
            f.[Required QTY],
            f.PO#,
            CASE WHEN f.[Ordered QTY]>f.[Required QTY] 
                    THEN ISNULL(ABS(f1.[Required QTY]-f1.[Ordered QTY]),f.[Required QTY]) 
                    ELSE f.[Ordered QTY] END 
                            as [QTY Used],
            f.[Ordered QTY] - 
            CASE WHEN f1.PO# = f.PO# 
                    THEN f1.[Ordered QTY]
                    ELSE
                        CASE WHEN f.[Ordered QTY]>f.[Required QTY] 
                                THEN ISNULL(ABS(f1.[Required QTY]-f1.[Ordered QTY]),f.[Required QTY]) 
                                ELSE f.[Ordered QTY] END
             END as [QTY Remain]
    FROM final f
    LEFT JOIN final f1
        ON f.RN = f1.RN+ 1
            AND (f.SO# = f1.SO# OR f.PO# = f1.PO#)
    OPTION(MAXRECURSION 0)
    

    Output for data you provided:

    SO# DueDate     Part Number Required QTY    PO# QTY Used    QTY Remain
    100 2016-09-03  1012        2               331 1           0
    100 2016-09-03  1012        2               362 1           0
    101 2016-09-12  1012        1               359 1           4
    107 2016-10-11  1012        4               359 4           0
    103 2016-10-17  1012        7               371 3           0
    103 2016-10-17  1012        7               380 4           6