У меня есть иерархия, описываемая списком смежности. Существует не обязательно один корневой элемент, но у меня есть данные для идентификации элементов листа (терминала) в hiearchy. Итак, иерархия, которая выглядела так:Иерархия SQL - разрешить полный путь для всех предков данного узла
1
- 2
- - 4
- - - 7
- 3
- - 5
- - 6
8
- 9
... был бы описан таблицей, как это. ПРИМЕЧАНИЕ: У меня нет возможности изменить этот формат.
id parentid isleaf
--- -------- ------
1 null 0
2 1 0
3 1 0
4 2 0
5 3 1
6 3 1
7 4 1
8 null 0
9 8 1
здесь образец определение таблицы и данные:
CREATE TABLE [dbo].[HiearchyTest](
[id] [int] NOT NULL,
[parentid] [int] NULL,
[isleaf] [bit] NOT NULL
)
GO
INSERT [dbo].[HiearchyTest] ([id], [parentid], [isleaf]) VALUES (1, NULL, 0)
INSERT [dbo].[HiearchyTest] ([id], [parentid], [isleaf]) VALUES (2, 1, 0)
INSERT [dbo].[HiearchyTest] ([id], [parentid], [isleaf]) VALUES (3, 1, 0)
INSERT [dbo].[HiearchyTest] ([id], [parentid], [isleaf]) VALUES (4, 2, 0)
INSERT [dbo].[HiearchyTest] ([id], [parentid], [isleaf]) VALUES (5, 3, 1)
INSERT [dbo].[HiearchyTest] ([id], [parentid], [isleaf]) VALUES (6, 3, 1)
INSERT [dbo].[HiearchyTest] ([id], [parentid], [isleaf]) VALUES (7, 4, 1)
INSERT [dbo].[HiearchyTest] ([id], [parentid], [isleaf]) VALUES (8, NULL, 0)
INSERT [dbo].[HiearchyTest] ([id], [parentid], [isleaf]) VALUES (9, 8, 1)
GO
Исходя из этого, необходимо предоставить любой идентификатор и получить список всех предков, включая все потомок каждый. Так что, если я обеспечил вход ид = 6, я ожидал бы следующее:
id descendentid
-- ------------
1 1
1 3
1 6
3 3
3 6
6 6
- идентификатора 6 раз сам имеет
- родительские, идентификатор 3 будет иметь decendents 3 и 6
- его родитель, ID 1 будет иметь decendents 1, 3 и 6
Я буду использовать эти данные, чтобы обеспечить рулон вверх вычислений на каждом уровне в иерархии. Это хорошо работает, предполагая, что я могу получить набор данных выше.
Я выполнил это, используя два возвратных элемента - один, чтобы получить «терминал» для каждого узла в hiearchy. Затем, второй, где я получаю полную предков моего выбранного узла (так, 6 разрешается до 6, 3, 1), чтобы подняться и получить полный набор. Я надеюсь, что я что-то упустил и что это можно сделать за один раунд. Вот пример кода двойной рекурсии:
declare @test int = 6;
with cte as (
-- leaf nodes
select id, parentid, id as terminalid
from HiearchyTest
where isleaf = 1
union all
-- walk up - preserve "terminal" item for all levels
select h.id, h.parentid, c.terminalid
from HiearchyTest as h
inner join
cte as c on h.id = c.parentid
)
, cte2 as (
-- get all ancestors of our test value
select id, parentid, id as descendentid
from cte
where terminalid = @test
union all
-- and walkup from each to complete the set
select h.id, h.parentid, c.descendentid
from HiearchyTest h
inner join cte2 as c on h.id = c.parentid
)
-- final selection - order by is just for readability of this example
select id, descendentid
from cte2
order by id, descendentid
Дополнительная деталь: «реальная» иерархия будет гораздо больше, чем, например. Он может технически иметь бесконечную глубину, но реалистично он редко бывал более чем на 10 уровнях.
Таким образом, мой вопрос в том, могу ли я сделать это с помощью одного рекурсивного cте вместо того, чтобы дважды повторять иерархию.
https://msdn.microsoft.com/en-us/library/bb677173.aspx вот статья Microsoft о некоторых новых функциях иерархии, нацеленных именно на это. – Matt
@Matt - спасибо за предложение, но в моей заметке сказано, что у меня нет возможности изменять структуру данных (это не моя таблица). Таким образом, у меня нет возможности добавить столбец иерархии. Кроме того, по моему опыту с идентификатором иерархии, я не видел метода, который делает то, что я прошу.Вы заметите, что, основываясь на моем вводе id = 6, мне нужен полный список потомков всех предков этого id. –
получил это Я быстро прочитал :) рекурсивный cte, скорее всего, маршрут, который я прочитаю снова, и посмотреть, с чем я могу помочь. – Matt