이런 종류의 문제 때문에 C# 또는 다른 응용 프로그램 계층 솔루션이 최선의 방법 일 수 있습니다.
하지만 다소 복잡하지만 SQL로 할 수 있습니다.
재귀 CTE의
첫 부분 걸릴에 OrderID = 1 인비 = 1의 결과 그것을 계산하거나> 0 LeftInLot
또는 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 DEMO - old
SQLFiddle DEMO - fixed
PS : 당신이 정말로 OrderID
및 InvID
연속 값이 틈없이 것을 의존 할 수 없기 때문에 - 내 예와 마찬가지로 (c2.OrderID = c1.OrderID + 1
),의 추가 합병증3210이 완료되어야합니다. (고정)
편집 :
업데이트 솔루션은 여러 항목에서 작동합니다. 처음에는 CTE 몇 개를 계산하여 ROW_NUMBERS를 계산하여 항목 대신에 ID 대신 JOIN에서 항목을 사용했습니다.
안녕하세요, 답장을 보내 주셔서 감사합니다. 이것은 훌륭한 해결책입니다. 웬일인지, 나는 더 많은 항목을 더할 수 없다. 그것은 오직 첫 번째 항목 '펜'에 대한 해결책을 제공 할 것입니다. 어떻게 생각해? 나는 그것이 애플리케이션 로직에서하는 것이 더 좋을 것이라고 동의하지만 불행히도 나는 SQL에만 국한되어있다. – LindaM
아마도 어딘가에 결석이나 조건이 생겼을 것입니다 ... 찾을 수 있는지 보겠습니다 ... –
@ user2417191 좋아요, 여러 항목으로 작업 할 수있는 솔루션을 업데이트했습니다. 처음에는 CTE 몇 개를 계산하여 ROW_NUMBERS를 계산하여 항목 대신에 ID 대신 JOIN에서 항목을 사용했습니다. 또한 마지막에 c1.item = c2.item을 추가하여 수정하십시오. –