所以我知道这个问题在典型的亲子关系中没有意义,但在这种情况下,父母和孩子类似于谷歌电子邮件组。每个组(父组)可以包含多个其他组(子组),并且这些子组还可以包括也链接到祖先之一的其他父组。这不是问题,因为目标只是确定哪些用户属于一个组,递归既不相关也不错误。
基本数据可在SqlFiddle
获取CREATE TABLE SQLTest (
Parent NVARCHAR(100) NULL
, Child NVARCHAR(100) NULL
)
INSERT INTO SQLTest
VALUES
('A','B'),
('B','C'),
('C','A'),
('A','D'),
('X','Y')
通过查询
with x (Parent,Child) as (
select Parent, Child
from SQLTest
where Parent = 'A'
union all
select T.Parent,T.Child
from SQLTest T
join x on x.Child = T.Parent
)
select *
from x;
我使用的是 PostgreSQL,因为之前找到的记录不会用于下一次连接迭代。但是在 SQL Server 中我遇到了无限循环。我知道如何停止循环,而且我也知道我可以创建一个具体化路径来检查循环,以供参考,请参阅Microsoft Forums。然而,我希望有一些更简单的东西,特别是因为我使用 byte[] ulids 作为 ids 并且并不真正想转换它们并加入然后这样做。希望有一些我所缺少的更简单、更高效的东西。
预期输出为
A
B
C
D
表示可以从 A 到达的所有节点(包括父节点和子节点)的所有 id。
我使用的是 2022 SQL Server 版本,fiddle 来自早期版本,以防万一。
将路径包含到递归中可以打破循环,因为我们可以测试当前行之前的路径中已经存在的值。例如:
WITH x(Parent, Child, Path) AS (
SELECT
Parent
, Child
, CAST(Parent + ',' + Child AS NVARCHAR(MAX))
FROM SQLTest
WHERE Parent = 'A'
UNION ALL
SELECT
T.Parent
, T.Child
, CAST(x.Path + ',' + T.Child AS NVARCHAR(MAX))
FROM SQLTest T
JOIN x ON x.Child = T.Parent
WHERE CHARINDEX(T.Child, x.Path) = 0
)
SELECT parent as node FROM x
UNION
SELECT child as node FROM x
节点 |
---|
A |
B |
C |
D |