获取 SQL 中没有搜索到的 id 的兄弟姐妹的直接层次结构

Get direct hierarchy in SQL without siblings of searched id

我有一个非常简单的 table 类型,它包含 ID、ParentID 和 Name。我需要的是从一个 ID 获取完整的层次结构,但不包括所搜索 ID 的兄弟姐妹。我写了以下 SQL,

;WITH cte AS ( 
   SELECT ID, ParentID, [Name]
   FROM   [Types]
   WHERE  ID=246
   UNION ALL 
   SELECT t1.ID, t1.ParentID, t1.[Name]
   FROM   [Types] t1 
   INNER JOIN cte ON cte.ID=t1.ParentID 
    ) 
SELECT * FROM cte 

这给了我 table 的完整层次结构(最顶层的父级是 id '246'):

到目前为止,还不错。我现在想从查询中获得的是 ID 的完整层次结构:1384,但没有 ID 1384 的兄弟姐妹(以及兄弟姐妹的子女、孙子女等)。所以它应该 return 以下结果:

+------+----------+------------------+
| ID   | ParentID | Name             |
+------+----------+------------------+
| 246  | 2        | Approvals        |
+------+----------+------------------+
| 1384 | 246      | ProductStatus    |
+------+----------+------------------+
| 1517 | 1384     | NewStatus        |
+------+----------+------------------+
| 1520 | 1384     | NewSiblingStatus |
+------+----------+------------------+
| 1519 | 1517     | NewNewStatus     |
+------+----------+------------------+

我已经阅读了各种关于检索层次结构的文章,但到目前为止还没有进一步解决这个问题,也没有找到有类似问题的人。

一种方法是使用两个递归通用 table 表达式。一个获得 parents,另一个获得 children。然后你可以 union 他们得到你想要的结果 - union(而不是 union all)是为了消除初始节点上的重复项。

WITH 
    cte_children AS ( 
       SELECT ID, ParentID, [Name], 0 lvl
       FROM [Types]
       WHERE ID = 1384
       UNION ALL 
       SELECT t.ID, t.ParentID, t.[Name], lvl - 1
       FROM [Types] t
       INNER JOIN cte_children c ON c.ID = t.ParentID 
    ) 
    cte_parents AS ( 
       SELECT ID, ParentID, [Name], 0 lvl
       FROM [Types]
       WHERE  ID = 1384
       UNION ALL 
       SELECT t.ID, t.ParentID, t.[Name], lvl + 1
       FROM [Types] t
       INNER JOIN cte ON cte.ParentID = t.ID 
    ) 
SELECT * FROM cte_parents
UNION
SELECT * FROM cte_children  
ORDER BY lvl

请注意,我在查询中添加了一个名为 lvl 的列,用于计算每个节点的深度(初始注释有 0,parents 有负数 lvls, 和 children 有积极的 lvls) - 这很方便对最终结果集进行排序。