没有明确根节点的 CTE 递归

CTE Recursion without clear root node

我在 SQL 服务器中有一个 table,如下所示:

ID  ParentID    ChildID
1   465         547
2   547         653
3   653         667
4   902         1005
5   1005        1009
6   1059        1080

注意:ParentID 和 ChildID 指的是另外 table 个人。

我的目标是识别根 parent 并统计 children 的数量。例如,预期的查询输出将是:

ParentID    NumChildren
465         3
902         2
1059        1 

我看到一些在 CTE 中使用递归的例子,当有一个 parent 的明确标识符时,例如 parentid = null 的条目。但是我的数据不是以这种方式构建的,所以我不知道从哪里开始。

您可以应用一个父项永远不是子项的检查。

with cte as (
select  ParentID, ChildID  
  from TABLE  
where parentid not in (select childid from TABLE ) -- the parent is never a child

  union all

  select  parent.ParentID, child.ChildID
  from TABLE child
  inner join cte parent
  on child.parentid =parent.ChildID
)
select ParentID,count(*) as NumChildren
from cte
group by ParentID

CTE 中的第一个 select 脚本,用于获取子 ID 中不存在的仅根父 ID 列表

CTE 中 UNION ALL 之后的第二个 select 脚本,要获取层次结构数据,请使用 UNION ALL 和 JOIN 与相同的 CTE 作为父子 ID,父 ID 列为主要 table 即#tblA

您需要使用聚合函数 COUNT() 来根据父 ID 获取子计数 您需要使用 GROUP BY 子句才能使用聚合函数 COUNT()

请检查以下脚本以获得您的预期结果。

SELECT
    A.*
    INTO #tblA
FROM
(
    SELECT 1 ID,465 ParentID,547 ChildID UNION ALL
    SELECT 2,547,653 UNION ALL
    SELECT 3,653,667 UNION ALL
    SELECT 4,902,1005 UNION ALL
    SELECT 5,1005,1009 UNION ALL
    SELECT 6,1059,1080
) A

;WITH CTE_REC
AS
(
    --Get Only Root Parent ID list which are not exists in Child ID
    SELECT
        A.ParentID,A.ChildID
    FROM #tblA A
    WHERE NOT EXISTS
    (
        SELECT
            1
        FROM #tblA c
        WHERE c.ChildID = A.ParentID
    )
    --to get Heirarchy data, use UNION ALL and JOIN with same CTE as a parent Child ID with Parent ID column of main table
    UNION ALL
    SELECT
        CR.ParentID,ta.ChildID
    FROM CTE_REC CR
    INNER JOIN #tblA ta ON ta.ParentID = CR.ChildID
)
SELECT
    c.ParentID,
    COUNT(c.ChildID) AS NumChildren --Use aggregate function count() to get child count against parent id
FROM CTE_REC c
GROUP BY c.ParentID; -- Use Group By Clause to use aggregate function count()

DROP TABLE #tblA;