Estou tentando criar uma consulta para calcular a quantidade "Disponível para Venda" de todos os itens no inventário. Nesse caso, um item pode ter estoque atual disponível, mas também pode ser um kit, que é composto de matérias-primas que podem ser montadas para formar esse bem acabado. Portanto, a quantidade disponível para venda é a quantidade atual disponível de Bens Acabados (FG) mais o mínimo dos componentes que podem ser feitos no FG.
Exemplo:
Digamos que estamos vendendo um kit de laptop composto por um laptop e uma bolsa de transporte. Se tivermos 2 kits já feitos e 6 laptops e 3 bolsas de transporte, nossa disponibilidade para venda desses kits é de 2 + 3 = 5 no total. As bolsas de transporte são o fator limitante neste caso. Apesar de termos 6 laptops, só podemos fazer mais 3 kits por causa das malas que nos limitam.
Cheguei até aqui e os cálculos funcionam do nível 2 mais baixo até o nível 1, mas o nível 0 não está correto. Então, neste caso, o cálculo para o kit de laptop está correto (11 em mãos + podemos fazer mais 4 = 15 disponíveis para vender). Mas o kit de laptop e bolsa de nível superior não está correto. O menor Avail to Sell dos filhos diretos do nível superior (Laptop & Bag Kit) é 15 + 3 desse kit está disponível = 18, não 14.
Estou pensando que talvez precise adicionar um segundo CTE recursivo em vez da junção esquerda que tenho na seleção final?
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
Desenrole a hierarquia em uma tabela temporária primeiro (observe a coluna computada):
Isso nos dá:
Agora calcule
MaxCanMake
por nível, começando com o mais profundo:A coluna computada na tabela temporária reflete automaticamente a alteração em
AvailToSell
.A consulta de exibição final é então:
dbfiddle