获取根节点的所有子节点

时间:2019-03-19 07:40:07

标签: sql sql-server tree sql-server-2008-r2

我有一个类似的数据库结构

------------------------------------------
NodeId  |   Parent
-----------------------------------------
1           0
2           0
3           1
4           1
5           2
6           2    
7           3
8           3
9           4
10          4
11          5
12          5
13          6    

形成像这样的树结构

1
->3
  -->7
  -->8
->4
  -->9
  -->10
2
->5
  -->11
  -->12
->6
  -->13

现在用户可以输入任何节点ID

获取

  • 该节点标识下的所有节点

联盟

  • 节点ID的根节点下的所有节点

例如:
如果用户单击节点ID 1,
结果应该是(我可以通过CTE实现)

1 0
3 1
4 1
7 3
8 3
9 4
10 4

但是如果用户单击任何中间节点(如4)
结果应该是

4 1
9 4
10 4

联合(节点根父节点下的所有节点) 节点的根父代4 = 1 所以结果应该是

1 0 
3 1
4 1 (Should be excluded as comes under first query)
7 3
8 3
9 4 (Should be excluded as comes under first query)
10 4 (Should be excluded as comes under first query) 

这是我到目前为止的代码:

declare @Node int;
Set @node=1
with [CTE] As
(
  Select [nodeid], [Parent]
  from [NodeTable]
  where [nodeid]=@nodeid

  union

  Select [
  from [Nodetable] [NT]
    inner join [CTE] on [CTE].[nodeid]=[NT].[Nodeid]
)

Select * from [CTE]

2 个答案:

答案 0 :(得分:0)

您可以首先使用第一个RootId检索指定节点的CTE,然后使用CTE2检索所检索的RootId的所有子节点:

    declare @node int;
Set @node=4;
with [CTE] As
(
  Select [nodeid] NodeId, [Parent] Parent
  from [NodeTable]
  where [nodeid]=@node

  union all

  Select [NT].[nodeid] ni, [NT].[Parent] pi
  from [Nodetable] [NT]
    inner join [CTE] 
    on  [CTE].Parent=[NT].NodeId
), [CTE2] As
(
  Select [nodeid] NodeId, [Parent] Parent
  from [NodeTable]
  where [nodeid]= (select top 1 NodeId from CTE order by NodeId)

  union all

  Select [NT].[nodeid] ni, [NT].[Parent] pi
  from [Nodetable] [NT]
    inner join [CTE2] 
    on [CTE2].NodeId=[NT].Parent
)


Select * from [CTE2]
order by NodeId

此外,如果要排除节点本身及其子节点,则可以添加CTE3来检索节点的子节点,并使用除以得到所需的输出:

declare @node int;
Set @node=4;
with [CTE] As
(
  Select [nodeid] NodeId, [Parent] Parent
  from [NodeTable]
  where [nodeid]=@node

  union all

  Select [NT].[nodeid] ni, [NT].[Parent] pi
  from [Nodetable] [NT]
    inner join [CTE] 
    on  [CTE].Parent=[NT].NodeId
), [CTE2] As
(
  Select [nodeid] NodeId, [Parent] Parent
  from [NodeTable]
  where [nodeid]= (select top 1 NodeId from CTE order by NodeId)

  union all

  Select [NT].[nodeid] ni, [NT].[Parent] pi
  from [Nodetable] [NT]
    inner join [CTE2] 
    on [CTE2].NodeId=[NT].Parent
), [CTE3] As
(
  Select [nodeid] NodeId, [Parent] Parent
  from [NodeTable]
  where [nodeid]=@node

  union all

  Select [NT].[nodeid] ni, [NT].[Parent] pi
  from [Nodetable] [NT]
    inner join [CTE3] 
    on  [CTE3].NodeId = [NT].Parent
)

Select * from [CTE2]
except
Select * from [CTE3]
order by NodeId

答案 1 :(得分:0)

一种方法是使用递归cte,该cte还将保留每次递归的根节点,然后根据所需节点的根查询该cte。

首先,创建并填充示例表:(在您将来的问题中为我们保存此步骤)

DECLARE @T AS TABLE
(
    NodeId int,
    Parent int
);

INSERT INTO @T (NodeId, Parent) VALUES
(1 , 0),
    (3 , 1),
        (7 , 3),
        (8 , 3),
    (4 , 1),
        (9 , 4),
        (10, 4),

(2 , 0),
    (5 , 2),
        (11, 5),
        (12, 5),
    (6 , 2),
        (13, 6);

递归cte:

WITH CTE AS
(
    SELECT NodeId, Parent, NodeId As Root
    FROM @T
    WHERE Parent = 0
    UNION ALL
    SELECT t.NodeId, t.Parent, Root
    FROM @T As t
    JOIN CTE 
        ON t.Parent = CTE.NodeId
)

查询:

SELECT NodeId, Parent
FROM CTE
WHERE Root = (SELECT Root FROM CTE WHERE NodeId = 4)

结果:

NodeId Parent
1       0
3       1
4       1
9       4
10      4
7       3
8       3

You can see a live demo on rextester.