SQL Server 2019 中的父子关系

Parent Child Relationship in SQL Server 2019

我有一个 table 存储这样的关系:

ParentName ParentID ChildName ChildId
-------------------------------------
Name1      Guid     NameA      Guid
Name2      Guid     NameB      Guid
Name3      Guid     NameC      Guid
NameA      Guid     NameY      Guid
NameB      Guid     NameX      Guid
NameC      Guid     NameZ      Guid
NameY      Guid     Name1A     Guid

我的目标是检索堆叠的数据,无论在层次结构中有多远,子列都显示最顶层的父项。

我知道这是一个递归 CTE,但我不知道如何在不破坏最大递归数的情况下将查询中的递归连接写回锚点。父查询使用 WHERE 子句有 78 条记录,但总级别不应超过 4 或 5。父查询可以有多个子查询。

这是此递归查询的一个工作示例。

CREATE TABLE parents (
    ParentName char(10),
    ParentID char(10),
    ChildName char(10),
    ChildId char(10) );
insert into parents values( 'a',1,'b',2);
insert into parents values( 'b',2,'c',3);
insert into parents values( 'c',3,'d',4);
insert into parents values( 'd',4,'e',5);
insert into parents values( 'e',5,'f',6);
insert into parents values( 'f',6,'g',7);
insert into parents values( 'g',7,'h',8);

select 
    p1.pname, p1.pid,
    p2.pname, p2.pid,
    p3.pname, p3.pid,
    p4.pname, p4.pid,
    p5.pname, p5.pid,
    p5.cname, p5.cid
from
    (select ParentName pname, ParentID pid, ChildName cname, ChildId cid from parents) p1 right join
    (select ParentName pname, ParentID pid, ChildName cname, ChildId cid from parents) p2 on p1.cid=p2.pid right join
    (select ParentName pname, ParentID pid, ChildName cname, ChildId cid from parents) p3 on p2.cid=p3.pid right join
    (select ParentName pname, ParentID pid, ChildName cname, ChildId cid from parents) p4 on p3.cid=p4.pid right join
    (select ParentName pname, ParentID pid, ChildName cname, ChildId cid from parents) p5 on p4.cid=p5.pid 
order by
    p1.pid,p2.pid,p3.pid,p4.pid,p5.pid;
DROP TABLE parents;
``

下面的查询应该有效。尽管它受数据库允许的最大递归限制,在 SQL 服务器的情况下默认为 100。所以它应该可以工作到那么多级别的嵌套 Parent-Child 关系。

WITH RECURSIVE cte AS (
    SELECT ChildID,ChildName,ParentID,ParentName, 1 AS Level FROM parents

    UNION ALL

    SELECT cte.ChildID,
        cte.ChildName,
        GrandParent.ParentID,
        GrandParent.ParentName,
        Level+1 
    FROM cte 
    INNER JOIN parents AS GrandParent 
    ON cte.ParentID=GrandParent.ChildID 
)
SELECT ChildID,ChildName,ParentID,ParentName 
FROM(
    SELECT cte.*,
        ROW_NUMBER() OVER(PARTITION BY ChildID,ChildName ORDER BY Level DESC) AS rnk 
    FROM cte
) Rank_Highest_Level
WHERE rnk=1
ORDER BY ChildID;

这是数据库 Fiddle 中的一个 working example