在多父级层次结构数据模型中查找两个节点之间的所有可能关系[SQL Server]

时间:2019-03-28 13:58:23

标签: sql-server database

我有一个数据模型来定义多父级层次数据。每条记录将代表两个节点的关系,其中一个将是父节点,另一个将是子节点。就我而言,一个节点可以有多个父节点。我需要找到两个节点之间的所有可能的关系。

例如以下表为例。

---------------------------------
| id | parent_node | child_node |
---------------------------------
| 1  | NULL        | A          |
| 2  | NULL        | B          |
| 3  | A           | C          |
| 4  | A           | D          |
| 5  | B           | D          |
| 6  | B           | E          |
| 7  | C           | G          |
| 8  | C           | H          |
| 10 | D           | I          |
| 11 | E           | I          |
| 12 | E           | J          |
---------------------------------

这将形成如下图

        A   B
       / \ / \    
      C   D   E
    /  \   \ / \
   G    H   I   J

在上述模型中,A和B将是顶级节点,每个节点都有两个子节点。节点D被指定为节点A和B的子代。节点I也被指定为节点D和节点E的子代。所有其他节点恰好具有一个父代。

我需要写一个查询来显示一个节点与另一个节点的所有可能关系。 例如,

  1. A和C有关系,因为C是节点A的子节点。
  2. A和D有关系,因为D是节点A的子节点。
  3. A和G有关系,因为G是节点A的孙子。
  4. 这将适用于任何级别。
  5. 如果一个节点不是另一个节点的子级或第n级孙代,则两个节点没有任何关系。

如果两个节点没有任何关系,它将不会显示。

上图的最终结果如下,

----------------------------
| parent_node | child_node |
----------------------------
| A           | C          |
| A           | D          |
| C           | G          |
| C           | H          |
| D           | I          |
| A           | G          |
| A           | H          |
| A           | I          |
| B           | D          |
| B           | E          |
| B           | I          |
| E           | I          |
| E           | J          |
| B           | J          |
----------------------------

我是SQL Server的新手。请帮助我解决此查询。

1 个答案:

答案 0 :(得分:1)

通过研究,我自己可以编写查询。正如@SeanLange在评论中指出的那样,这种查询称为递归CTE。

如果表名是nodes,则以下查询将创建新表relationship并按照我的问题中的说明在其中存储所有可能的关系。

;with cte as (
    select  child_node
    ,       parent_node
    ,       child_node as root
    from    nodes
    union all
    select  child.child_node
    ,       child.parent_node
    ,       parent.root
    from    cte parent
    join    nodes child
    on      parent.parent_node = child.child_node
)
select parent_node,
       root as child_node
into   relationship
from   cte
where  parent_node is not null;

select * from relationship;