在庫にあるすべてのアイテムの「販売可能」数量を計算するクエリを作成しようとしています。この場合、アイテムは現在利用可能な在庫を持つことができますが、完成品を形成するために組み立てることができる原材料で構成されるキットにすることもできます。したがって、販売可能なのは、現在利用可能な完成品(FG)の数量とFGにできるコンポーネントの最小数です。
例:
ラップトップとキャリングバッグで構成されるラップトップキットを販売しているとします。すでに2つのキットが作成されており、ラップトップ6つとキャリングバッグ3つがある場合、これらのキットを販売できるのは合計2 + 3 = 5です。この場合、キャリーバッグが制限要因になります。ラップトップは6つありますが、バッグの制限により、キットはあと3つしか作成できません。
ここまで来て、計算は最低レベル2からレベル1まで機能しますが、レベル0は正しくありません。したがって、この場合、ラップトップキットの計算は正しいです(手元に11個+さらに4個= 15個を販売に利用できます)。しかし、トップレベルのラップトップ&バッグキットは正しくありません。トップレベルの直接の子(ラップトップ&バッグキット)の販売可能な最小のアベイルズは、そのキットの15 + 3 = 14ではなく、18です。
最終選択で持っている左結合の代わりに、2番目の再帰CTEを追加する必要があると思いますか?
CREATE TABLE Item (
Id INT,
ParentId INT,
DisplaySeq INT,
DisplayText VARCHAR(30),
OnHandQty INT
);
INSERT INTO Item (Id, ParentId, DisplaySeq, DisplayText, OnHandQty) VALUES
(9, NULL, 0, 'Laptop & Bag Kit', 3),
(8, 9, 5, 'Laptop Kit', 11),
(7, 8, 10, 'Laptop', 5),
(6, 8, 15, 'Power Supply', 4),
(26, 9, 20, 'Bag', 23)
;
;WITH items AS (
SELECT
Id
, 0 as ParentId
, Id as RootId
, 0 AS Level
, CAST(DisplaySeq AS VARCHAR(255)) AS Path
, CAST('---' AS varchar(100)) AS LVL
, CAST(DisplayText as VARCHAR(255)) as DisplayText
, OnHandQty
FROM Item
WHERE ParentId IS NULL
UNION ALL
SELECT
child.Id
, child.ParentId
, parent.RootId
, Level + 1
, CAST(parent.Path + '.' + CAST(child.DisplaySeq AS VARCHAR(255)) AS VARCHAR(255)) AS Path
, CAST('---' + parent.LVL AS varchar(100)) AS LVL
, CAST(parent.LVL + child.DisplayText as VARCHAR(255)) as DisplayText
, child.OnHandQty
FROM
Item child
INNER JOIN items parent
ON parent.Id = child.ParentId
)
SELECT
t.Path
, t.RootId
, t.Id
, t.ParentId
, t.Level
, t.DisplayText
, t.OnHandQty
, COALESCE(s.MaxCanMake, t.OnHandQty) as MaxCanMake
, t.OnHandQty + COALESCE(s.MaxCanMake, 0) as AvailToSell
FROM
items t
left join (
Select
ParentId,
MIN(OnHandQty) as MaxCanMake
FROM items
GROUP BY ParentId
) as s
ON t.Id = s.ParentId
ORDER BY t.Path
最初に階層を一時テーブルに展開します(計算列に注意してください)。
CREATE TABLE #Items
(
Id integer PRIMARY KEY,
MPath varchar(255) NOT NULL,
DisplayText varchar(30) NOT NULL,
OnHandQty integer NOT NULL,
[Level] integer NOT NULL,
ParentId integer NOT NULL,
MaxCanMake integer NULL,
AvailToSell AS OnHandQty + MaxCanMake
);
WITH Items AS
(
SELECT
I.Id,
MPath = CONVERT(varchar(255), I.DisplaySeq),
I.DisplayText,
I.OnHandQty,
0 AS [Level],
0 AS ParentId
FROM dbo.Item AS I
WHERE I.ParentId IS NULL
UNION ALL
SELECT
I.Id,
CONVERT(varchar(255), Parent.MPath + '.' + CONVERT(varchar(11), I.DisplaySeq)),
I.DisplayText,
I.OnHandQty,
Parent.[Level] + 1,
I.ParentId
FROM Items AS Parent
JOIN dbo.Item AS I WITH (FORCESEEK)
ON I.ParentId = Parent.Id
)
INSERT #Items
(Id, MPath, DisplayText, OnHandQty, [Level], ParentId)
SELECT
I.Id, I.MPath, I.DisplayText, I.OnHandQty, I.[Level], I.ParentId
FROM Items AS I
OPTION (MAXRECURSION 0);
-- Useful index
CREATE INDEX i
ON #Items (ParentId, AvailToSell);
それは私たちに与えます:
╔════╦════════╦══════════════════╦═══════════ ╦═══════╦══════════╦════════════╦═════════════╗ ║Id║MPath║DisplayText║OnHandQty║Level║ParentId║MaxCanMake║AvailToSell║ ╠════╬════════╬═══════════ ═══════╬═══════════╬═══════╬══════════╬═══════════ ═╬═════════════╣ ║9║0║ラップトップ&バッグキット║3║0║0║NULL║NULL║ ║26║0.20 ║バッグ║23║1║9║NULL║NULL║ ║8║0.5║ラップトップキット║11║1║9║NULL║NULL║ ║7║0.5.10║ラップトップ║ 5║2║8║NULL║NULL║ ║6║0.5.15║電源║4║2║8║NULL║NULL║ ╚════╩════ ════╩══════════════════╩═══════════╩═══════╩══════ ════╩════════════╩═════════════╝
次に、最も深いところから始めて、レベルごとにMaxCanMake
を計算します。
DECLARE @Level integer =
(
SELECT MAX(I.[Level])
FROM #Items AS I
);
WHILE @Level >= 0
BEGIN
UPDATE I
SET I.MaxCanMake =
ISNULL
(
(
SELECT TOP (1)
I2.AvailToSell
FROM #Items AS I2
WHERE I2.ParentId = I.Id
ORDER BY
I2.AvailToSell ASC
),
0
)
FROM #Items AS I
WHERE I.[Level] = @Level;
SET @Level -= 1;
END;
一時テーブルの計算列には、AvailToSell
の変更が自動的に反映されます。
最終的な表示クエリは次のとおりです。
SELECT
DisplayText = REPLICATE('---', I.[Level]) + I.DisplayText,
I.OnHandQty,
I.MaxCanMake,
I.AvailToSell
FROM #Items AS I
ORDER BY
I.MPath;
╔════════════════════╦═══════════╦═══════════ ═╦═════════════╗ ║DisplayText║OnHandQty║MaxCanMake║AvailToSell║ ╠══════════════ ══════╬═══════════╬════════════╬═════════════╣ ║ラップトップ&バッグキット║3║15║18║ ║---バッグ║23║0║23║ ║---ラップトップキット║11║4║15║ ║------ラップトップ║5║0║5║ ║------電源║4║0║4║ ╚═════ ═══════════════╩═══════════╩════════════╩═════════ ════╝