0

我希望用 MS SQL 中的 CTE 解决以下问题,但我遇到了障碍。

这是我的问题。

订单表:

OrderID Item    Quantity    
------------------------
1       pen     80      
2       pen     30      
3       pen     25

库存表:

Inv ID  Lot  Item  Quantity
---------------------------
1       001  pen   100
2       002  pen   20
3       003  pen   30

我需要做的是处理订单,以便第一个订单来自批次 1,第二个订单来自批次 1 和批次 2,第三个订单来自批次 2 和批次 3。

我需要知道哪个订单来自哪个批次,这意味着我不能只是将订单分组。

所以基本上我需要类似的东西:

OrderID Item  QuantityOrdered Lot  QuantityFromLot
--------------------------------------------------
1       pen   80              001  80
2       pen   30              001  20
2       pen   30              002  10
3       pen   25              002  10
3       pen   25              003  15  

有没有办法用 CTE 做到这一点?如果没有,你会推荐什么?

4

1 回答 1

1

对于这类问题,C# 或其他一些应用层解决方案可能是最好的方法。

但是可以用 SQL 来做,虽然有点复杂。

递归 CTE 的第一部分将采用 OrderID = 1 和 InvID =1 并对其进行计算,导致LeftInLot> 0 或LeftToServe> 0。

第二部分现在需要根据第一部分的结果使用两种不同的逻辑,这是通过子查询来完成的接着说。

它看起来像这样:

;WITH CTE_Orders AS 
(
    SELECT *, ROW_NUMBER() OVER (PARTITION BY Item ORDER BY OrderID) AS RN
    FROM dbo.Orders
)
, CTE_Inventory AS 
(
    SELECT *, ROW_NUMBER() OVER (PARTITION BY Item ORDER BY InvID) AS RN
    FROM dbo.Inventory
)
, CTE AS 
(
    SELECT  o.RN AS OrderRN,
            inv.RN AS InvRN,
            OrderID ,
            o.Item ,
            o.Quantity AS OrderedQuantity ,
            InvID ,
            Lot ,
            inv.Quantity AS InvQuantity,
            CASE WHEN inv.Quantity - o.Quantity > 0 THEN o.Quantity  ELSE inv.Quantity END AS ServedQuantity ,
            CASE WHEN inv.Quantity - o.Quantity > 0 THEN 0 ELSE o.Quantity - inv.Quantity END AS LeftToServe,
            CASE WHEN inv.Quantity - o.Quantity > 0 THEN inv.Quantity - o.Quantity ELSE 0 END AS LeftInLot
    FROM CTE_Orders o
    INNER JOIN CTE_Inventory inv ON o.Item = inv.Item
    --WHERE OrderID = 1 AND InvID = 1
    WHERE o.RN =1 AND inv.RN = 1

    UNION ALL

    SELECT  CASE WHEN c1.LeftInLot <=0 THEN c1.OrderRN ELSE c2.OrderRN END AS OrderRN
            ,CASE WHEN c1.LeftInLot <=0 THEN c2.InvRN ELSE c1.InvRN END AS InvRN
            ,CASE WHEN c1.LeftInLot <=0 THEN c1.OrderID ELSE c2.OrderID END AS OrderID
            ,CASE WHEN c1.LeftInLot <=0 THEN c1.Item ELSE c2.Item END AS Item
            ,CASE WHEN c1.LeftInLot <=0 THEN c1.OrderedQuantity ELSE  c2.OrderedQuantity END AS OrderedQuantity
            ,CASE WHEN c1.LeftInLot <=0 THEN c2.InvID ELSE c1.InvID END AS InvID
            ,CASE WHEN c1.LeftInLot <=0 THEN c2.Lot ELSE c1.Lot END AS Lot
            ,CASE WHEN c1.LeftInLot <=0 THEN c2.InvQuantity ELSE c1.LeftInLot END AS InvQuantity
            ,CASE WHEN CASE WHEN c1.LeftInLot <=0 THEN c2.InvQuantity ELSE c1.LeftInLot END - CASE WHEN c1.LeftInLot <=0 THEN c1.LeftToServe ELSE c2.OrderedQuantity END > 0
                  THEN CASE WHEN c1.LeftInLot <=0 THEN c1.LeftToServe ELSE c2.OrderedQuantity END
                  ELSE CASE WHEN c1.LeftInLot <=0 THEN c2.InvQuantity ELSE c1.LeftInLot END
             END AS ServedQuantity
            ,CASE WHEN CASE WHEN c1.LeftInLot <=0 THEN c2.InvQuantity ELSE c1.LeftInLot END - CASE WHEN c1.LeftInLot <=0 THEN c1.LeftToServe ELSE c2.OrderedQuantity END > 0
                  THEN 0
                  ELSE CASE WHEN c1.LeftInLot <=0 THEN c1.LeftToServe ELSE  c2.OrderedQuantity END - CASE WHEN c1.LeftInLot <=0 THEN c2.InvQuantity ELSE c1.LeftInLot END  
             END AS LeftToServe
            ,CASE WHEN CASE WHEN c1.LeftInLot <=0 THEN c2.InvQuantity ELSE c1.LeftInLot END - CASE WHEN c1.LeftInLot <=0 THEN c1.LeftToServe ELSE c2.OrderedQuantity END > 0
                  THEN  CASE WHEN c1.LeftInLot <=0 THEN c2.InvQuantity ELSE c1.LeftInLot END - CASE WHEN c1.LeftInLot <=0 THEN c1.LeftToServe ELSE  c2.OrderedQuantity END 
                  ELSE 0 
             END AS LeftInLot
    FROM CTE c1
    INNER JOIN 
    (
        SELECT  o2.RN AS OrderRN,
                inv2.RN AS InvRN,
                InvID ,
                Lot ,
                inv2.Item ,
                inv2.Quantity AS InvQuantity,
                OrderID ,
                o2.Quantity AS OrderedQuantity
        FROM 
        CTE_Inventory inv2 
        INNER JOIN CTE_Orders o2 ON inv2.Item = o2.Item
    ) c2
    ON c1.Item = c2.Item AND
    ((c2.InvRN = c1.InvRN + 1 AND c2.OrderRN = c1.OrderRN AND c1.LeftInLot <= 0 ) OR (c2.OrderRN = c1.OrderRN + 1 AND c2.InvRN = c1.InvRN AND c1.LeftInLot>0))

)
SELECT * FROM CTE
ORDER BY item,OrderID

SQLFiddle 演示 - 旧

SQLFiddle 演示 - 已修复

PS:因为你不能真正依赖它OrderID并且InvID是没有任何间隙的连续值 - 就像我的例子假设( )一样,应该做c2.OrderID = c1.OrderID + 1额外的复杂性。ROW_NUMBER(固定的)

编辑:

更新了处理多个项目的解决方案。开始时有几个 CTE 来计算 ROW_NUMBERS 为项目分区并在 JOIN 中使用这些而不是 ID。

于 2013-05-24T13:12:39.717 回答