2013-05-24 1 views
0

나는 MS SQL에서 CTE로 아래의 문제를 해결하기를 희망했지만 벽돌 벽을 때리고있다.CTE - 재고량 줄이기

여기 내 문제가 있습니다.

Orders 테이블 :

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

재고 테이블 : 첫 번째 순서는 1 로트 나오는 있도록

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

내가해야 할 것은 프로세스가 주문되고, 두 번째 순서는 나온다 lot 1과 lot 2 그리고 세 번째 주문은 lot 2와 lot 3 중 하나입니다.

어떤 주문이 ​​어떤 lot에서 비롯되었는지 알고 싶습니다. 즉 주문을 그룹화 할 수는 없습니다.

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를 함께 할 수있는 방법이 있나요 :

그래서 기본적으로 나는이 비슷한을해야합니까? 그렇지 않다면 무엇을 권하겠습니까?

답변

1

이런 종류의 문제 때문에 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 : 당신이 정말로 OrderIDInvID 연속 값이 틈없이 것을 의존 할 수 없기 때문에 - 내 예와 마찬가지로 (c2.OrderID = c1.OrderID + 1),의 추가 합병증3210이 완료되어야합니다. (고정)

편집 :

업데이트 솔루션은 여러 항목에서 작동합니다. 처음에는 CTE 몇 개를 계산하여 ROW_NUMBERS를 계산하여 항목 대신에 ID 대신 JOIN에서 항목을 사용했습니다.

+0

안녕하세요, 답장을 보내 주셔서 감사합니다. 이것은 훌륭한 해결책입니다. 웬일인지, 나는 더 많은 항목을 더할 수 없다. 그것은 오직 첫 번째 항목 '펜'에 대한 해결책을 제공 할 것입니다. 어떻게 생각해? 나는 그것이 애플리케이션 로직에서하는 것이 더 좋을 것이라고 동의하지만 불행히도 나는 SQL에만 국한되어있다. – LindaM

+0

아마도 어딘가에 결석이나 조건이 생겼을 것입니다 ... 찾을 수 있는지 보겠습니다 ... –

+0

@ user2417191 좋아요, 여러 항목으로 작업 할 수있는 솔루션을 업데이트했습니다. 처음에는 CTE 몇 개를 계산하여 ROW_NUMBERS를 계산하여 항목 대신에 ID 대신 JOIN에서 항목을 사용했습니다. 또한 마지막에 c1.item = c2.item을 추가하여 수정하십시오. –