CTE循环父子父关系,如何展平列表

问题描述 投票:0回答:1

所以我知道这个问题在典型的亲子关系中没有意义,但在这种情况下,父母和孩子类似于谷歌电子邮件组。每个组(父组)可以包含多个其他组(子组),并且这些子组还可以包括也链接到祖先之一的其他父组。这不是问题,因为目标只是确定哪些用户属于一个组,递归既不相关也不错误。

基本数据可在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 来自早期版本,以防万一。

sql sql-server tsql graph common-table-expression
1个回答
0
投票

将路径包含到递归中可以打破循环,因为我们可以测试当前行之前的路径中已经存在的值。例如:

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

dbfiddle.uk(sql server 2022)

© www.soinside.com 2019 - 2024. All rights reserved.