CTE 从任意条目中提取整棵树

CTE to pull entire tree from arbitrary entry

我正在尝试构建一个 CTE,它将提取与数据库中给定的 任意 记录相关的所有记录。

Create table Requests (
  Id bigint,
  OriginalId bigint NULL,
  FollowupId bigint NULL
)

insert into Requests VALUES (1, null, 3)
insert into Requests VALUES (2, 1, 8)
insert into Requests VALUES (3, 1, 4)
insert into Requests VALUES (4, 3, null)
insert into Requests VALUES (5, null, null)
insert into Requests VALUES (6, null, 7)
insert into Requests VALUES (7, 6, null)
insert into Requests VALUES (8, 2, null)

OriginalId 始终是前一条记录的 Id(或 null)。 FollowupId 指向最近的跟进记录(反过来,通过 OriginalId 返回)并且可能会被忽略,但如果有帮助,它就在那里。

我可以使用以下 CTE 轻松拉回给定记录的所有祖先或所有后代

;With TransactionList (Id, originalId, followupId, Steps)
AS
(
    Select Id, originalId, followupId, 0 as Steps from requests where Id = @startId
    union all
    select reqs.Id, reqs.originalId, reqs.followupId, Steps + 1 from requests reqs
    inner join TransactionList tl on tl.Id = reqs.originalId --or tl.originalId = reqs.Id
)
SELECT Id from TransactionList

但是,如果我同时使用两个 where 子句,我 运行 进入递归,达到递归限制,它就会爆炸。即使组合两组,我也没有得到整棵树 - 只有它的一个分支。

除了 ID 列表,我不关心任何其他内容。它们不需要分类,也不需要显示它们的关系或其他任何东西。不痛,但没必要。但是我需要给定树中的每个 Id 在作为 @startId.

传递时拉回相同的列表

作为我希望看到的示例,当 @startId 设置为任何值 1-4 或 8 时,输出应该是这样的:

1
2
3
4
8

对于 6 或 7,我都会返回 6 和 7。

您只能创建 2 个 CTE。

第一个 CTE 将获取层次结构的 Root,第二个将使用 Root ID 获取 Root 的后代。

;WITH cteRoot AS (
    SELECT  *, 0 [Level]
    FROM    Requests
    WHERE   Id = @startId
    UNION ALL
    SELECT  r.*, [Level] + 1
    FROM    Requests r
            JOIN cteRoot cte ON r.Id = cte.OriginalID
),
cteDesc AS (
    SELECT  *
    FROM    cteRoot
    WHERE   OriginalId IS NULL
    UNION ALL
    SELECT  r.*, [Level] + 1
    FROM    Requests r
            JOIN cteDesc cte ON r.OriginalId = cte.Id  
)
SELECT * FROM cteDesc  

SQL Fiddle