Die Lösung, die ich hier vorschlage, verwendet das Konzept des materialisierten Pfads. Das Folgende ist ein Beispiel für materialisierte Pfade unter Verwendung Ihrer Beispieldaten. Ich hoffe, es hilft Ihnen, das Konzept des materialisierten Pfads zu verstehen:
+----+--------------------------+----------+------------------+
| ID | Name | ParentID | MaterializedPath |
+----+--------------------------+----------+------------------+
| 1 | Parent 1 | 0 | 1 |
| 2 | Parent 2 | 0 | 2 |
| 4 | Parent 2 Child 1 | 2 | 2.4 |
| 6 | Parent 2 Child 1 Child 1 | 4 | 2.4.6 |
| 7 | Parent 2 Child 1 Child 2 | 4 | 2.4.7 |
| 3 | Parent 1 Child 1 | 1 | 1.3 |
| 5 | Parent 1 Child 1 Child | 3 | 1.3.5 |
+----+--------------------------+----------+------------------+
Jeder Knoten N
einen materialisierten Pfad hat, sagt Ihnen dieser Pfad, wie Sie vom Wurzelknoten zum Knoten N
gehen müssen . Es kann erstellt werden, indem die Knoten-IDs verkettet werden. Zum Beispiel, um den Knoten 5
zu erreichen Ausgehend von seinem Wurzelknoten besuchen Sie den Knoten 1
, Knoten 3
und Knoten 5
, also Knoten 5
materialisierter Pfad ist 1.3.5
Zufälligerweise kann die gesuchte Reihenfolge durch den materialisierten Pfad erreicht werden.
Im vorherigen Beispiel werden materialisierte Pfade durch Verketten von Strings erstellt, aber ich bevorzuge aus mehreren Gründen die binäre Verkettung.
Um die materialisierten Pfade zu erstellen, benötigen Sie den folgenden rekursiven CTE:
CREATE TABLE Tree
(
ID int NOT NULL CONSTRAINT PK_Tree PRIMARY KEY,
Name nvarchar(250) NOT NULL,
ParentID int NOT NULL,
)
INSERT INTO Tree(ID, Name, ParentID) VALUES
(1, 'Parent 1', 0),
(2, 'Parent 2', 0),
(3, 'Parent 1 Child 1', 1),
(4, 'Parent 2 Child 1', 2),
(5, 'Parent 1 Child 1 Child', 3),
(6, 'Parent 2 Child 1 Child 1', 4),
(7, 'Parent 2 Child 1 Child 2', 4)
GO
WITH T AS
(
SELECT
N.ID, N.Name, N.ParentID, CAST(N.ID AS varbinary(512)) AS MaterializedPath
FROM
Tree N
WHERE
N.ParentID = 0
UNION ALL
SELECT
N.ID, N.Name, N.ParentID, CAST( T.MaterializedPath + CAST(N.ID AS binary(4)) AS varbinary(512) ) AS MaterializedPath
FROM
Tree N INNER JOIN T
ON N.ParentID = T.ID
)
SELECT *
FROM T
ORDER BY T.MaterializedPath
Ergebnis:
+----+--------------------------+----------+----------------------------+
| ID | Name | ParentID | MaterializedPath |
+----+--------------------------+----------+----------------------------+
| 1 | Parent 1 | 0 | 0x00000001 |
| 3 | Parent 1 Child 1 | 1 | 0x0000000100000003 |
| 5 | Parent 1 Child 1 Child | 3 | 0x000000010000000300000005 |
| 2 | Parent 2 | 0 | 0x00000002 |
| 4 | Parent 2 Child 1 | 2 | 0x0000000200000004 |
| 6 | Parent 2 Child 1 Child 1 | 4 | 0x000000020000000400000006 |
| 7 | Parent 2 Child 1 Child 2 | 4 | 0x000000020000000400000007 |
+----+--------------------------+----------+----------------------------+
Der obige rekursive CTE beginnt mit den Wurzelknoten. Die Berechnung des materialisierten Pfads für einen Wurzelknoten ist trivial einfach, es ist die ID des Knotens selbst. Bei der nächsten Iteration verbindet der CTE Wurzelknoten mit seinen Kindknoten. Der materialisierte Pfad für einen untergeordneten Knoten CN
ist die Verkettung des materialisierten Pfades seines Elternknotens PN
und die ID des Knotens CN
. Nachfolgende Iterationen gehen im Baum eine Ebene nach unten, bis die Blattknoten erreicht sind.