我有一个关于使用递归SQL的问题,其中我有以下表格结构
产品可以分为多组(为了清楚起见,我不使用int)
-i
现在问题我想了解所有相关产品 所以,如果我通过产品1 ,那么我需要以下结果
CREATE TABLE ProductGroups(ProductName nvarchar(50), GroupName nvarchar(50))
INSERT INTO ProductGroups(ProductName, GroupName) values
('Product 1', 'Group 1'),
('Product 1', 'Group 2'),
('Product 2', 'Group 1'),
('Product 2', 'Group 6'),
('Product 3', 'Group 7'),
('Product 3', 'Group 8'),
('Product 4', 'Group 6')
+-----------+---------+
| Product | Group |
+-----------+---------+
| Product 1 | Group 1 |
| Product 1 | Group 2 |
| Product 2 | Group 1 |
| Product 2 | Group 6 |
| Product 3 | Group 7 |
| Product 3 | Group 8 |
| Product 4 | Group 6 |
+-----------+---------+
所以基本上我想首先找出产品1的所有组,然后为每个组找出所有产品等等......
答案 0 :(得分:4)
可以使用递归查询来完成,但它不是最佳的,因为SQL Server不允许您将递归表作为集引用。因此,您最终必须保留路径字符串以避免无限循环。如果使用整数,则可以使用hierarchyid
替换路径字符串。
with r as (
select ProductName Root, ProductName, GroupName, convert(varchar(max), '/') Path from ProductGroups
union all
select r.Root, pg.ProductName, pg.GroupName, convert(varchar(max), r.Path + r.ProductName + ':' + r.GroupName + '/')
from r join ProductGroups pg on pg.GroupName=r.GroupName or pg.ProductName=r.ProductName
where r.Path not like '%' + pg.ProductName + ':' + pg.GroupName + '%'
)
select distinct ProductName, GroupName from r where Root='Product 1'
答案 1 :(得分:3)
我不认为使用递归CTE可以实现这一点,因为每个递归定义只允许一个递归引用。
我确实设法使用while
循环来实现它,这可能不如cte:
declare @related table (ProductName nvarchar(50), GroupName nvarchar(50))
-- base case
insert @related select * from ProductGroups where ProductName='Product 1'
-- recursive step
while 1=1
begin
-- select * from @related -- uncomment to see progress
insert @related select p.*
from @related r
join ProductGroups p on p.GroupName=r.GroupName or p.ProductName=r.ProductName
left join @related rr on rr.ProductName=p.ProductName and rr.GroupName=p.GroupName
where rr.ProductName is null
if @@ROWCOUNT = 0
break;
end
select * from @related
在部署之前,你一定要小心上面的实际尺寸数据基准!
答案 2 :(得分:2)
这并不容易。您正在建模equivalence classes。 SQL是一个设置语言,您正在查看一个类 - 一组集:
答案 3 :(得分:2)
你可以这样做。
DECLARE @ProductGroups AS TABLE (
ProductName NVARCHAR(50) ,
GroupName NVARCHAR(50)
)
INSERT INTO @ProductGroups
( ProductName, GroupName )
VALUES ( 'Product 1', 'Group 1' ),
( 'Product 1', 'Group 2' ),
( 'Product 2', 'Group 1' ),
( 'Product 2', 'Group 6' ),
( 'Product 3', 'Group 7' ),
( 'Product 3', 'Group 8' ),
( 'Product 4', 'Group 6' );
;
WITH cte
AS ( SELECT a.ProductName
FROM @ProductGroups a
WHERE a.GroupName IN ( SELECT x.GroupName
FROM @ProductGroups x
WHERE x.ProductName = 'Product 1' )
),
cte2
AS ( SELECT GroupName
FROM @ProductGroups
WHERE ProductName IN ( SELECT x.ProductName
FROM cte x )
)
SELECT *
FROM @ProductGroups
WHERE GroupName IN ( SELECT x.GroupName
FROM cte2 x )