Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql CTE-减少库存量_Sql_Sql Server_Common Table Expression - Fatal编程技术网

Sql CTE-减少库存量

Sql CTE-减少库存量,sql,sql-server,common-table-expression,Sql,Sql Server,Common Table Expression,我希望用MSSQL中的CTE解决以下问题,但我遇到了麻烦 这是我的问题 订单表: OrderID Item Quantity ------------------------ 1 pen 80 2 pen 30 3 pen 25 库存表: Inv ID Lot Item Quantity --------------------------- 1 001 pen 100 2

我希望用MSSQL中的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做到这一点?如果没有,您会推荐什么?

对于此类问题,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
PS:因为您不能真正相信OrderID和InvID是没有任何间隙的连续值——就像我的示例假设的c2.OrderID=c1.OrderID+1一样,应该对行数进行额外的复杂化。固定的

编辑:


更新了用于处理多个项目的解决方案。开始时还有两个CTE用于计算为项目划分的行数,并在联接中使用这些行数而不是ID。

Hi,感谢您的回复。这是一个绝妙的解决方案。由于某些原因,我无法添加更多项目。它只会为我提供第一项“笔”的解决方案。你怎么认为?我同意在应用程序逻辑中这样做会更好,但不幸的是我仅限于sql。可能在某个地方缺少一些连接或条件。。。我会看看我是否能找到它…@user2417191好的,我已经更新了解决方案来处理多个项目。开始时还有两个CTE用于计算为项目划分的行数,并在联接中使用这些行数而不是ID。另外,在结尾处添加c1.item=c2.item优秀的解决方案。非常感谢!