- •1. Основные понятия и определения 4
- •2. Три базовых способа моделирования иерархий 11
- •3. Два важных частных случая 125
- •1. Основные понятия и определения
- •1.1. Иерархическая модель данных
- •1.2. Реляционная модель данных
- •1.3. Задача моделирования
- •2. Три базовых способа моделирования иерархий
- •2.1. Рекурсивный способ представления иерархии1
- •Insert into @tree (Name, Level) values (@NodeName, @Level);
- •Insert into @tree (Name, Level) values
- •Insert @tree ([name], id, parent, [level], [order])
- •Insert @tree ([name], id, parent, [level], [order])
- •Insert @tree ([name], id, parent, [level], [order])
- •Insert @tree ([name], id, parent, [level], [order])
- •Insert @tree ([name], id, parent, [level], [order])
- •Insert into t(Parent, Data) values(1, 'b');
- •Id int not null,
- •Insert into @tree ([Name], id, Parent, [Level], [Check], [Path])
- •Values (@NodeName, @id, @Parent, @Level, @Check, @Path);
- •Insert into @tree ([Name],
- •Values (@NodeName,
- •Id int not null,
- •Id not in (select distinct Parent from t);
- •Insert into @tree ([Name],
- •Задачи повышенной сложности
- •2.2. Способ правого и левого коэффициентов
- •Задачи повышенной сложности
- •2.3. Способ вспомогательной таблицы
- •Insert into t_Base(Node) values (@NewRoot);
- •Insert into t_Helper(uid, ParentId, [Level])
- •Values (@RootId, @RootId, 0);
- •Instead of delete
- •3. Два важных частных случая
- •3.1. Случай ограниченного количества уровней иерархии
- •3.2. Случай ограниченного числа потомков
- •Заключение
- •Библиографический список
- •Ермаков Дмитрий Германович
- •620002, Екатеринбург, ул. Мира, 19
Insert into @tree (Name, Level) values (@NodeName, @Level);
-- Пока не доберёмся до корневого элемента иерархии...
WHILE (@ID <> @Parent)
BEGIN
SELECT @ID=ID, @Parent=Parent, @NodeName=Data
FROM T
WHERE ID=@Parent;
-- Наращиваем расстояние до предка
SET @Level=@Level+1;
-- Добавляем запись в возвращаемую таблицу
Insert into @tree (Name, Level) values
(@NodeName, @Level);
END
RETURN
END
При помощи этой функции получим всех предков, например, узла O:
select * from GetParents('O') ORDER BY Level DESC;
Результат выполнения этого запроса представлен на рис. 22.
Рис. 22. Использование функции нахождения всех предков некоторого узла для узла O
Теперь при помощи функции GetParents можно решить задачу о нахождении ближайшего общего предка для двух узлов. Пусть заданы узлы I и K. Их общий ближайший предок – узел B (см. рис. 8).
С помощью запросов
select [name] from GetParents('I');
и
select [name] from GetParents('K');
получим списки всех предков этих узлов (рис. 23).
Рис. 23 Все предки узлов I и K
Запрос
select * from GetParents('I') where
([name] in (select [name] from GetParents('K')));
даст список всех общих предков для узлов I и K (рис. 24).
Рис. 24. Список всех общих предков для узлов I и K
Из этого списка надо выбрать элемент с минимальным значением поля Level (рис. 25).
select MIN([level]) from GetParents('I') where
[name] in (select [name] from GetParents('K'));
Рис. 25. Получаем элемент с минимальным значением в поле Level
Окончательно получаем ближайшего общего предка для узлов I и K при помощи следующего предложения SQL (рис. 26):
select [name] from GetParents('I') where
([name] in (select [name] from GetParents('K'))
And ([level]=((
select MIN([level]) from GetParents('I') where
[name] in (select [name] from GetParents('K'))))));
Рис. 26. Получаем ближайшего общего предка для узлов I и K
Задача выбора всех потомков (или поддерева) для некоторого, наперёд заданного узла более сложная, так как, в отличие от предков, которые для каждого узла единственные на каждом уровне, у одного предка может быть несколько различных непосредственных потомков.
Для решения этой задачи можно использовать средства некоторого внешнего объемлющего языка уровня приложения или хранимые процедуры СУБД. Здесь может использоваться рекурсивный вызов, однако следует учесть, что существует ограничение на вложенность рекурсивных вызовов (например, не более 100 для MS SQL Server 2005 Express Edition), а дерево может быть больше, чем разрешённая глубина вложенности рекурсивных вызовов. Приведём пример рекурсивной функции, использующей курсор:
CREATE FUNCTION MyGetTree(@root varchar(1),
@order varchar(4096),
@level int)
RETURNS @tree TABLE
(
[name] varchar,
id int,
parent int,
[level] int,
[order] varchar(4096)
)
AS
Begin
-- ВНИМАНИЕ! В реальной функции необходимо
-- проверить законность входных параметров.
-- После каждой операции необходима проверка
-- наличия ошибок, отсутствующая в данном примере!
DECLARE @id int;
DECLARE @parent int;
DECLARE @data varchar(1);
IF @level=0
BEGIN
-- Если это корневой элемент
-- записываем в таблицу информацию о
-- заданном узле выбираемого поддерева.