I have two tables, one is a Product Customer mapping and another is a Product sharing table. Using SQL recursive CTE, given a product, I am trying to find all the products that are linked as a chain, mapped across the customers. In addition, if a Product is shared with another Product, I need to include it in the chain too. Hopefully, my example make more sense than the description
Product Customer Table
Product Customer
Milk Illinois
Milk Michigan
Butter Michigan
Cream Wisconsin
Honey Wisconsin
Cheese Minnesota
Product Sharing Table
Product SharedProduct
Butter Cream
Cream Cheese
For the above data, let's say my input Product is Milk, then the result set should include all the products - Milk, Butter, Cream, Honey & Cheese. Here Butter-Cream & Cream-Cheese are linked through the Product Sharing table.
My current SQL looks like this but doesn't really work more than one level deep.
WITH Product_CTE AS
(
SELECT DISTINCT [Product] FROM ProductCustomer
WHERE [Product] IN (SELECT DISTINCT p2.[Product]
FROM ProductCustomer p1 INNER JOIN ProductCustomer p2
ON p1.[Customer] = p2.[Customer] WHERE p1.[Product] = 'Milk')
UNION ALL
SELECT [SharedProduct] FROM ProductSharing b
INNER JOIN Product_CTE p ON p.[Product] = b.[Product]
)
Select [Product] from Product_CTE
A CTE has issues with multiple UNION
s. Although it may be possible, it wasn't working for me.
An alternative is to use a loop that stops when there are no more rows added to a working table:
declare @ProductCustomers as Table ( Product VarChar(16), Customer VarChar(16) )
insert into @ProductCustomers ( Product, Customer ) values
( 'Milk', 'Illinois' ),
( 'Milk', 'Michigan ' ),
( 'Butter', 'Michigan ' ),
( 'Cream', 'Wisconsin' ),
( 'Honey', 'Wisconsin' ),
( 'Cheese', 'Minnesota' )
declare @ProductSharing as Table ( Product VarChar(16), SharedProduct VarChar(16) )
insert into @ProductSharing ( Product, SharedProduct ) values
( 'Butter', 'Cream ' ),
( 'Cream', 'Cheese ' )
declare @TargetProduct as VarChar(16) = 'Milk'
declare @ProductChain as Table ( Product VarChar(16) )
insert into @ProductChain ( Product ) values ( @TargetProduct )
declare @NewRows as Int = 1
while @NewRows > 0
begin
set @NewRows = 0
-- Add products shared by the same customer.
insert into @ProductChain
select PCR.Product
from @ProductCustomers as PCL inner join
@ProductCustomers as PCR on
-- Shared customer.
PCR.Customer = PCL.Customer and
-- Different product.
PCR.Product <> PCL.Product
where not exists ( select 42 from @ProductChain where Product = PCR.Product )
set @NewRows = @NewRows + @@RowCount
-- Add products linked through the product sharing table.
insert into @ProductChain
select PS.SharedProduct
from @ProductSharing as PS inner join
@ProductChain as PC on PC.Product = PS.Product
where not exists ( select 42 from @ProductChain where Product = PS.SharedProduct )
set @NewRows = @NewRows + @@RowCount
end
select Product
from @ProductChain
order by Product
Assumed herein is that the @ProductSharing
table is unidirectional.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.