Мне немного неясно, какие именно узлы вы хотите отобразить ... но, если я правильно понимаю, главный вопрос здесь состоит в том, как упорядочить результирующие узлы. Основная трудность заключается в том, что критерии упорядочения имеют переменную длину: узел должен быть упорядочен на основе всей последовательности OrderId
значений для узла и всех его предков. Например, последовательность заказа для узла 6 равна «2, 1, 1».
SQL плохо обрабатывает такие последовательности переменной длины. Я предлагаю использовать значение NVARCHAR (MAX) для последовательности упорядочения. Для узла 6 мы будем использовать «0002.0001.0001». В этом виде узлы можно упорядочить тривиально, используя сравнение строк. Обратите внимание, что значения идентификатора должны быть дополнены нулями, чтобы обеспечить правильное упорядочение (я произвольно выбрал заполнение до 4 цифр - для реального приложения может потребоваться другой выбор).
Так что это подводит нас к болтам. Мы начнем с создания таблицы с именем NavigationData
для хранения наших тестовых данных:
SELECT NULL AS NavId, NULL AS OrderId, NULL AS ParentId, NULL AS NavName
INTO NavigationData WHERE 1=0
UNION SELECT 1, 1, 0, 'Home'
UNION SELECT 2, 2, 0, 'About'
UNION SELECT 3, 3, 0, 'Contact Us'
UNION SELECT 4, 1, 2, 'About Us Page'
UNION SELECT 5, 2, 2, 'About Us Page 2'
UNION SELECT 6, 1, 4, 'Another SubPage'
Теперь мы создадим вспомогательное представление, которое для каждого возможного желаемого узла перечисляет все связанные узлы вместе с их вычисленными строками пути. Как я уже говорил в начале, я чувствую, что критерии выбора связанных узлов недостаточно заданы, поэтому может потребоваться скорректировать желаемое / связанное выражение JOIN для наборов данных с большим количеством узлов, чем в простом примере. С этой оговоркой, вот мнение:
CREATE VIEW NavigationHierarchy AS
WITH
hierarchy AS (
SELECT
NavId AS RootId
, 1 AS Depth
, NavId
, RIGHT('0000' + CAST(OrderId AS NVARCHAR(MAX)), 4) AS Path
, ParentId
, NavName
FROM NavigationData
WHERE ParentId = 0
UNION ALL
SELECT
parent.RootId
, parent.Depth + 1 AS Depth
, child.NavId
, parent.Path + '.'
+ RIGHT('0000' + CAST(child.OrderId AS NVARCHAR(MAX)), 4) AS Path
, child.ParentId
, child.NavName
FROM hierarchy AS parent
INNER JOIN NavigationData AS child
ON child.ParentId = parent.NavId
)
SELECT
desired.NavId AS DesiredNavId
, related.*
FROM hierarchy AS desired
INNER JOIN hierarchy AS related
ON related.Depth <= desired.Depth + 1
AND related.RootId IN (desired.RootId, related.RootId)
Большая часть запроса представляет собой прямое рекурсивное снижение иерархии с использованием общего табличного выражения. Суть решения - создание столбцов Path
. Естественно, вы можете предпочесть запекать этот запрос непосредственно в более крупный запрос или хранимый процесс, а не создавать представление. Однако представление удобно для тестирования.
Вооружившись видом, теперь мы можем генерировать желаемые результаты в запрошенном порядке. Я включил сгенерированный путь в результат запроса для наглядности. Вот запрос для узла 2:
SELECT NavName, Path
FROM NavigationHierarchy
WHERE DesiredNavId = 2
ORDER BY Path
получают:
Home 0001
About 0002
About Us Page 0002.0001
About Us Page 2 0002.0002
Contact Us 0003
и для узла 6:
SELECT NavName, Path
FROM NavigationHierarchy
WHERE DesiredNavId = 6
ORDER BY Path
получают:
Home 0001
About 0002
About Us Page 0002.0001
Another SubPage 0002.0001.0001
About Us Page 2 0002.0002
Contact Us 0003