2011-10-20 3 views
9

注文数量が消費されるまで注文数量を再帰的に更新できるかどうかを判断しようとしているCTEを調査しています。ここ CTE - 消費される総量が再帰的に更新される

はテーブルとのレコードである:

CREATE TABLE [dbo].[myOrder](
    [Account] [float] NOT NULL, 
    [Item] [float] NOT NULL, 
    [Quantity] [float] NOT NULL 
) ON [PRIMARY] 

insert into dbo.myOrder values (12345, 1, 50) 

CREATE TABLE [dbo].[myInventory](
    [ID] [int] IDENTITY(1,1) NOT NULL, 
    [Account] [float] NOT NULL, 
    [InvDate] [numeric](18, 0) NOT NULL, 
    [Item] [float] NOT NULL, 
    [Quantity] [float] NOT NULL, 
    [QuantitySold] [float] NOT NULL 
) ON [PRIMARY] 

insert into dbo.myInventory values (12345, 111287, 1, 45, 40) 
insert into dbo.myInventory values (12345, 111290, 1, 40, 0) 
insert into dbo.myInventory values (12345, 111290, 1, 12, 0) 
insert into dbo.myInventory values (12345, 111291, 1, 25, 0) 

myOrderテーブルのレコードは、注文アイテム#1、数量50のアカウント12345のために作成されることを示す:

Account Item Quantity 
------- ---- -------- 
12345 1 50 

在庫表には、12345アカウントのアイテム1がたくさんあることがわかります。

ID Account InvDate Item Quantity QuantitySold 
-- ------- ------- ---- -------- ------------ 
1 12345 111287 1 45  40 
2 12345 111290 1 40  0 
3 12345 111290 1 12  0 
4 12345 111291 1 25  0 

ゴアlは、すべての50が消費されるまで、インベントリレコードに注文数量50を差し込むことです。インベントリレコードは、[InvDate]列の値によって順序付けられます。レコード1には5個の残量(45 - 40 = 5)があり、これにより、注文のために消費する量が45個増えます。あなたがしなければならない、在庫テーブルにQuantitySold、QuantityRemainingない、よう:

ID Account InvDate Item Quantity QuantitySold 
-- ------- ------- ---- -------- ------------ 
1 12345 111287 1 45  45 
2 12345 111290 1 40  40 
3 12345 111290 1 12  5 
4 12345 111291 1 25  0 

注:クエリは次のようになり、在庫レコードを完了すると40レコード3を消費することができますレコード2は、最後の5を消費することができます数量(Quantity - QuantitySold)を使用して、在庫レコードごとに残っている量を決定します。

CTEはほとんどどこにもありません。私はあなたのCTEに2つの部分(初期化部分と一緒に組み合わされた再帰部分)を持っている場所を選択するための例をたくさん見つけました。私はこれをカーソルで書くことができましたが、CTEで行うことは可能だと思います。

これは誰でもCTEで可能であることを確認したり、CTEの設定方法を説明してくれれば幸いです。ありがとう!

+3

+1 DDLスクリプトの場合 –

+3

トピックはありませんが、なぜ* float *を使用して数量を計っていますか?あなたは本当に* 2の1.47E-19を在庫に残しておきたいですか? –

+0

ダミアン - 公正な質問。私の会社は数量欄に浮動小数点を使用するERPとしてJDEdwardsを使用しています。私はそれを念頭に置いてこれらのテーブルを作りました。ああ、レガシーデータベース! – Brian

答えて

10
[email protected] table mimics inserted virtual table from AFTER INSERT triggers on [dbo].[myOrder] table 
DECLARE @inserted TABLE 
(
    [Account] [float] NOT NULL, 
    [Item] [float] NOT NULL, 
    [Quantity] [float] NOT NULL 
); 

INSERT @inserted 
VALUES (12345, 1, 50); 

WITH CteRowNumber 
AS 
(
    SELECT inv.ID 
      ,inv.Account 
      ,inv.Item 
      ,inv.Quantity 
      ,inv.QuantitySold 
      ,i.Quantity QuantityOrdered 
      ,ROW_NUMBER() OVER(PARTITION BY inv.Account,inv.Item ORDER BY inv.ID ASC) RowNumber 
    FROM myInventory inv 
    INNER JOIN @inserted i ON inv.Account = i.Account 
    AND  inv.Item = i.Item 
    WHERE inv.Quantity > inv.QuantitySold 
), CteRecursive 
AS 
(
    SELECT a.ID 
      ,a.Account 
      ,a.Item 
      ,a.RowNumber 
      ,CASE 
       WHEN a.Quantity - a.QuantitySold < a.QuantityOrdered THEN a.Quantity - a.QuantitySold 
       ELSE a.QuantityOrdered 
      END QuantitySoldNew 
      ,CASE 
       WHEN a.Quantity - a.QuantitySold < a.QuantityOrdered THEN a.Quantity - a.QuantitySold 
       ELSE a.QuantityOrdered 
      END RunningTotal 
    FROM CteRowNumber a 
    WHERE a.RowNumber = 1 
    UNION ALL 
    SELECT crt.ID 
      ,crt.Account 
      ,crt.Item 
      ,crt.RowNumber 
      ,CASE 
       WHEN prev.RunningTotal + (crt.Quantity - crt.QuantitySold) < crt.QuantityOrdered THEN crt.Quantity - crt.QuantitySold 
       ELSE crt.QuantityOrdered - prev.RunningTotal 
      END QuantitySoldNew 
      ,CASE 
       WHEN prev.RunningTotal + (crt.Quantity - crt.QuantitySold) < crt.QuantityOrdered THEN prev.RunningTotal + (crt.Quantity - crt.QuantitySold) 
       ELSE crt.QuantityOrdered 
      END RunningTotal 
    FROM CteRecursive prev 
    INNER JOIN CteRowNumber crt ON prev.Account = crt.Account 
    AND  prev.Item = crt.Item 
    AND  prev.RowNumber + 1 = crt.RowNumber 
    WHERE prev.RunningTotal < crt.QuantityOrdered 
) 
SELECT cte.ID 
     ,cte.Account 
     ,cte.Item 
     ,cte.QuantitySoldNew 
FROM CteRecursive cte; 
--or CteRecursive can be used to update QuantitySold column from [dbo].[myInventory] table 
--UPDATE myInventory 
--SET  QuantitySold = inv.QuantitySold + cte.QuantitySoldNew 
--FROM myInventory inv 
--INNER JOIN CteRecursive cte ON inv.ID = cte.ID; 
+0

ボグダン、これは素晴らしいです!どうもありがとうございました。私はそれがやっているすべてを理解するためにあなたのクエリを研究するのに時間を費やす必要がありますが、それは素晴らしい作品です。それが正常に実行され、注文数量を適切に消費するのは本当に涼しいです。再度、感謝します! – Brian

関連する問題