2017-05-26 1 views
0

J'ai une table avec id et parent_id. J'ai vu beaucoup de CTE sur la façon de générer l'arbre. Cependant, je n'arrive pas à filtrer l'arbre afin de récupérer un arbre complet à partir de n'importe quel nœud.sql serveur comment récupérer un arbre complet donné à un enfant?

Compte tenu des valeurs

1, NULL 
2, 1 
3, 2 
4, 2 
5, NULL 
6, 5 
7, NULL 

Si je filtre par identifiant l'une des valeurs 1,2,3 ou 4 je devrais l'arbre

1, NULL 
2, 1 
3, 2 
4, 2 

pour 5 ou 6

5, NULL 
6, 5 

pour 7

7, NULL 

Est-ce que cela peut être réalisé en utilisant CTE?

Répondre

2

Utiliser un CTE pour localiser la racine de l'arbre, puis utiliser un second CTE pour exploser la structure arborescente:

declare @T table (ID int not null, Parent int null) 

insert into @T(ID,Parent) values 
(1, NULL), 
(2, 1 ), 
(3, 2 ), 
(4, 2 ), 
(5, NULL), 
(6, 5 ), 
(7, NULL) 

declare @Node int 
set @node = 3 

;With Root as (
    select t.ID,t.Parent from @T t where t.ID = @Node or t.Parent = @Node 
    union all 
    select t.ID,t.Parent 
    from 
     Root r 
      inner join 
     @t t 
      on 
       t.ID = r.Parent 
), Tree as (
    select ID,Parent from Root where Parent is null 
    union all 
    select t.ID,t.Parent 
    from @T t 
     inner join 
     Tree tr 
      on tr.ID = t.Parent 
) 
select * from Tree 

Résultat:

ID   Parent 
----------- ----------- 
1   NULL 
2   1 
3   2 
4   2 

Espérons que vous pouvez voir comment les deux Les CTE travaillent dans des directions opposées.

1

Vous pouvez utiliser un CTE récursif comme celui-ci. CTE retourne tous les arbres avec rootid, et vous pouvez obtenir tous les nœuds d'arbre par son rootid

DECLARE @SampleData AS TABLE 
(
    NodeId int, 
    ParentNodeId int 
) 

INSERT INTO @SampleData 
(
    NodeId, 
    ParentNodeId 
) 
VALUES 
(1, NULL), 
(2, 1), 
(3, 2), 
(4, 2), 
(5, NULL), 
(6, 5), 
(7, NULL) 

DECLARE @NodeId int = 4 

-- temp returns all child nodes of rootid (1,5,7) 
;WITH temp AS 
(
    SELECT sd.NodeId, sd.ParentNodeId, sd.NodeId AS RootId 
    FROM @SampleData sd 
    WHERE sd.ParentNodeId IS NULL 

    UNION ALL 

    SELECT sd.NodeId, sd.ParentNodeId, t.RootId 
    FROM temp t 
    INNER JOIN @SampleData sd ON t.NodeId = sd.ParentNodeId 
) 

SELECT t2.NodeId, t2.ParentNodeId 
FROM temp t 
INNER JOIN temp t2 ON t2.RootId = t.RootId 
WHERE t.NodeId = @NodeId 
OPTION (MAXRECURSION 0) 

lien de démonstration: http://rextester.com/PPPMXX4941