1

Ich kann Rekursion erreichen, indem Sie den With-Befehl (CTE) von SQL Server verwenden.Reihenfolge der Rekursion (SQL Server CTE)

WITH MyCTE(ParentID,ID,Name,Level) 
AS 
(
SELECT ManagerID AS ParentID, UserID AS ID, UserName AS Name, 0 AS Level 
FROM USERS U  
WHERE U.ManagerID IS NULL 

UNION ALL 

SELECT U.ManagerID AS ParentID, U.UserID AS ID, U.UserName AS Name, H.Level+1 AS Level 
FROM USERS U 
INNER JOIN MyCTE H ON H.ID = U.ManagerID 
) 

SELECT ParentID,ID FROM MyCTE 

kehrt

ParentID ID 
NULL  1 
1   2 
1   3 
2   4 

Was ich erreichen will, ist dieses Ergebnis Satz umkehren. Das heißt, die Umkehr der Wurzelknoten und die tiefste Kindknoten als,

ParentID ID 
NULL  4 
4   2 
2   1 
3   1 

konnte nicht herausfinden, wie programmatisch dies zu implementieren (vorzugsweise durch CTE verwendet wird), wie durch einen Parameter mit Hilfe der Rekursion Reihenfolge etc. Jede bestimmen Hilfe wird sehr geschätzt, danke.

Edit:

Modified dieses ein wenig meine erste CTE Ergebnisse in eine temporäre Tabelle einfügen, dann eine weitere Rekursion ich die Reihenfolge umkehren, wie (ich weiß „WHERE T.ID = (SELECT MAX (ID) von @ tmp)“wird nicht funktionieren in einer realen Situation, ich muss auch den tiefsten Knoten mit der Bestimmung‚Pegel‘Spalte, habe gerade versucht, dies für dieses Beispiel zu vereinfachen),

INSERT INTO @tmp 
SELECT ParentID,ID,Level FROM MyCTE 
WITH MyCTE2(ParentID,ID,Level) 
AS 
(
SELECT NULL AS ParentID, ID AS ID, 0 AS Level FROM @tmp T 
WHERE T.ID = (SELECT MAX(ID) FROM @tmp) 

UNION ALL 

SELECT R2.ID AS ParentID, T.ParentID AS ID, R2.Level+1 FROM @tmp T 
INNER JOIN MyCTE2 R2 ON R2.ID = T.ID 
WHERE T.ParentID IS NOT NULL 
) 

Original-Ergebnisse (entfernt, um das 1,3 Paar)

ParentID ID Level 
    NULL  1  0 
    1  2  1 
    2  4  2 

Reversed Ergebnisse,

ParentID ID Level 
    NULL  4  0 
    4  2  1 
    2  1  2 

Edit 2:

Ich habe so etwas wie dies,

SELECT TTT.ParentID,TTT.ID,TTT.Level FROM 
(
SELECT ParentID,ID,Level FROM MyCTE2 
UNION ALL 
SELECT TT.ID AS ParentID,TT.ParentID AS ID,(SELECT Level+1 FROM @tmp WHERE ID=TT.ID) 
AS Level FROM 
(
SELECT ID FROM @tmp 
EXCEPT 
SELECT ID FROM MyCTE2 
)T INNER JOIN @tmp TT ON TT.ID = T.ID 
)TTT 
ORDER BY TTT.Level 

gibt,

ParentID ID Level 
NULL  4 0 
4   2 1 
2   1 2 
3   1 2 

Dieser Fehler, im nicht sicher, noch enthalten , wollte nur zeigen, um sicherzustellen, dass das Paar (3,1) stimmt mit Niveau 2? Nachdem ich schon eine ganze Weile darüber nachgedacht habe, könnte ich einige dumme Fehler machen.

+0

@MartinSmith, die nicht arbeiten, lesen Sie die Post sorgfältig. – JonH

+0

@MartinSmith erstellen die Hierarchie in umgekehrter Reihenfolge neu. – JonH

+0

Sie müssen zuerst die Hierarchie erstellen, also fügen Sie grundsätzlich ein weiteres CTE nach Ihrem vorhandenen CTE hinzu, um rückwärts zu gehen. Es gibt keine Möglichkeit zu wissen, wie viele Ebenen tief etwas ist, ohne zuerst den Baum zu bauen. – JNK

Antwort

4

Probendaten

declare @T table 
(
    ParentID int, 
    ID int 
) 

insert into @T values 
(NULL,  1), 
(1 ,  2), 
(1 ,  3), 
(2 ,  4) 

Rekursion von der Wurzel:

;with C as 
(
    select ParentID, ID 
    from @T 
    where ParentID is null 
    union all 
    select T.ParentID, T.ID 
    from @T as T 
    inner join C 
     on T.ParentID = C.ID 
) 
select * 
from C 

Ergebnis

ParentID ID 
----------- ----------- 
NULL  1 
1   2 
1   3 
2   4 

Rekursion von Blättern:

;with C as 
(
    select null as PParentID, ID, ParentID 
    from @T 
    where ID not in (select ParentID 
        from @T 
        where ParentID is not null) 
    union all 
    select C.ID, T.ID, T.ParentID 
    from @T as T 
    inner join C 
     on T.ID = C.ParentID 
) 
select distinct 
     PParentID as ParentID, 
     ID 
from C 

Ergebnis:

ParentID ID 
----------- ----------- 
NULL  3 
NULL  4 
4   2 
2   1 
3   1 

Wenn Sie viele Zweige haben Sie doppelte Zeilen haben als miteinander verschmelzen. Die Verwendung von distinct kümmert sich darum.

Um die Ebenen zu korrigieren, müssen Sie zuerst die Ebene von oben nach unten berechnen. Speichern Sie das in einer Tabellenvariablen (oder einer temporären Tabelle) und verwenden Sie diese als Quelle für die Leaf-> Root-Rekursion.

-- Primary key and unique is in there to get the indexes used in the recursion 
declare @T2 table 
(
    ParentID int, 
    ID int, 
    Level int, 
    primary key (ID), 
    unique(ParentID, ID) 
) 

;with C as 
(
    select ParentID, ID, 0 as Level 
    from @T 
    where ParentID is null 
    union all 
    select T.ParentID, T.ID, Level + 1 
    from @T as T 
    inner join C 
     on T.ParentID = C.ID 
) 
insert into @T2 
select ParentID, ID, Level 
from C 

;with C as 
(
    select null as PParentID, ID, ParentID, Level 
    from @T2 
    where ID not in (select ParentID 
        from @T2 
        where ParentID is not null) 
    union all 
    select C.ID, T.ID, T.ParentID, T.Level 
    from @T2 as T 
    inner join C 
     on T.ID = C.ParentID 
) 
select distinct 
     PParentID as ParentID, 
     ID, 
     max(Level) over() - Level as level 
from C 

Ergebnis:

ParentID ID   level 
----------- ----------- ----------- 
NULL  3   1 
NULL  4   0 
2   1   2 
3   1   2 
4   2   1 

Es ist möglich, aber eine wirklich schlechte Idee @ T2 mit einem Multi CTE-Abfrage zu ersetzen. Es wird die Leistung abbrechen, weil das erste CTE für jede Rekursion neu erstellt wird. Zumindest ist das meine Vermutung, was passiert, aber glauben Sie mir, es ist nicht schnell.

+0

Ja ziemlich genau die gleiche Logik wie ich meinen Beitrag aktualisiert habe. Zuerst habe ich versucht, dies mit einem einzigen CTE und mit einem Parameter, um die Reihenfolge der Rekursion zu bestimmen Danke für Ihre Zeit und Hilfe – OzanYukruk

+1

@OzanYukruk - Dies ** ist ** mit einem einzigen CTE Der erste ist von root und down (ignorieren Sie es) Der zweite findet die Knoten, die nicht ist Eltern und geht nach oben. –

+0

Ja, aber in Ihrem Beispiel verwenden Sie eine temporäre Tabelle als Referenz. In meinem Fall ist meine Referenztabelle jedoch eine Ergebnismenge, die mit einem CTE erhalten wurde. (Mit mehr als 1 "UNION ALL" in meinem Real Code, der 10 Tabellen mit einer Eltern-Kind-Hierarchie verknüpft. Also muss ich einen anderen Parameter senden, um zu bestimmen, ob er auch die umgekehrte Ergebnismenge benötigt. – OzanYukruk