Решение, которое я предлагаю здесь, использует концепцию материализованного пути. Ниже приведен пример материализованных путей с использованием ваших данных образца. Я надеюсь, что это поможет вам понять материализованное понятие пути:
+----+--------------------------+----------+------------------+
| 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 |
+----+--------------------------+----------+------------------+
Каждый узел N
имеет материализованного путь, этот путь указывает вам путь от корневого узла к узлу N
. Это может быть конкатенирование идентификатора узла. Например, чтобы достичь узла 5
, начиная с корневого узла, вы посетите узел 1
, узел 3
и узел 5
, поэтому узел 5
материализовались путь 1.3.5
совпадению, заказ вы ищете может быть достигнуто сортировка по материализованный путь.
В предыдущем примере материализованные пути представляют собой строки объединения строк, но я предпочитаю двоичную конкатенацию по ряду причин.
Чтобы построить материализованные пути вам понадобится следующее рекурсивное ОТВ:
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
Результат:
+----+--------------------------+----------+----------------------------+
| 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 |
+----+--------------------------+----------+----------------------------+
выше рекурсивной КТР начинается с корневых узлов. Вычисление материализованного пути для корневого узла тривиально просто, это идентификатор самого узла. На следующей итерации CTE соединяет корневые узлы с дочерними узлами. Материализованный путь для дочернего узла CN
является конкатенацией материализованного пути его родительского узла PN
и идентификатора узла CN
. Последующие итерации продвигаются на один уровень вниз по дереву до тех пор, пока не будут достигнуты узлы листа.