|
|
su.dbms.sql- SU.DBMS.SQL ------------------------------------------------------------------ From : …ўЈҐЁ© ’ а«®ўбЄЁ© 2:5020/400 12 Feb 2001 20:50:44 To : All Subject : Re: ?Деревья - хочу мыслей --------------------------------------------------------------------------------
Извините за длиннющее письмо, но идей много.Приходится часто работать с
деревьями, и есть чем поделиться.
Мысли такие.
Для получения таблицы, по которой можно по дереву (представленному в виде
дерева) ползать, можно использовать пример из Books Online от MSSQL. Hа
вкладке "Индекс" набрать hierarchical information
Hа всякий случай привожу этот пример, тем более он построен без применения
рекурсии в явном виде - вызовов самой себя в этой хранимке нет, используется
временная таблица-стек.
Databases often store hierarchical information. For example, the following
data is a hierarchical representation of regions of the world. This
representation does not clearly show the structure implied by the data.
Parent Child
---------------------------------- ----------------------------------
World Europe
World North America
Europe France
France Paris
North America United States
North America Canada
United States New York
United States Washington
New York New York City
Washington Redmond
This example is easier to interpret:
World
North America
Canada
United States
Washington
Redmond
New York
New York City
Europe
France
Paris
The following Transact-SQL procedure expands an encoded hierarchy to any
arbitrary depth. Although Transact-SQL supports recursion, it is more
efficient to use a temporary table as a stack to keep track of all of the
items for which processing has begun but is not complete. When processing is
complete for a particular item, it is removed from the stack. New items are
added to the stack as they are identified.
CREATE PROCEDURE expand (@current char(20)) as
SET NOCOUNT ON
DECLARE @level int, @line char(20)
CREATE TABLE #stack (item char(20), level int)
INSERT INTO #stack VALUES (@current, 1)
SELECT @level = 1
WHILE @level > 0
BEGIN
IF EXISTS (SELECT * FROM #stack WHERE level = @level)
BEGIN
SELECT @current = item
FROM #stack
WHERE level = @level
SELECT @line = space(@level - 1) + @current
PRINT @line
DELETE FROM #stack
WHERE level = @level
AND item = @current
INSERT #stack
SELECT child, @level + 1
FROM hierarchy
WHERE parent = @current
IF @@ROWCOUNT > 0
SELECT @level = @level + 1
END
ELSE
SELECT @level = @level - 1
END -- WHILE
Для получения простого списка всех потомков определенного можно использовать
SP. У меня это сделано примерно так (в SP)
DECLARE clvl int
CREATE TABLE #ttx (id int, clevel int)
CREATE INDEX tidx ON #ttx (clevel)
INSERT #ttx VALUES (@treeTop,0)
SET clvl=-1
WHILE @@rowcount<>0
BEGIN
SET clvl=clvl+1
INSERT #ttx
SELECT id,clvl+1 FROM permanentTree WHERE parentId IN (SELECT id FROM #ttx
WHERE clevel=clvl)
END
--Вот и все. Теперь в #ttx просто список.
Есть у меня еще одна интересная функция для разнесения дерева по большим
группам. В таблице largeGroups находится список идентификаторов больших
групп. Функция возвращает таблицу из двух столбцов: первый ID элемента, а
второй- ID ближайшей группы, в которую он входит (группы могут располагаться
в любых местах дерева).
CREATE FUNCTION GetSelfGroups
RETURNS @grps TABLE (id nchar(11) NOT NULL,[group] nchar(11) NULL, clvl int)
AS--Разбивает дерево дерево на большие группы
BEGIN
DECLARE @clvl int,@flag bit
SET @clvl=0
insert @grps values('',NULL,0)
SET @flag=1
WHILE @flag=1
BEGIN
--Шаг первый. Возьмем всех прямых потомков
INSERT @grps
SELECT permanentTree.id,grps.[group],@clvl+1
FROM compress INNER JOIN @grps grps
ON permanentTree.parentId=grps.id WHERE grps.clvl=@clvl
--Закончим свистопляску когда нечего станет выбирать
IF @@ROWCOUNT=0 SET @flag=0
--Пропишем у элементов группы.
UPDATE @grps
SET [group]=largeGroups.[id]
FROM @grps grps INNER JOIN largeGroups ON grps.id=largeGroups.[id]
SET @clvl=@clvl+1
END
DELETE @grps WHERE clvl=0 --Выбросим пустой нулевой элемент
RETURN
END
И еще метод, который я встретил в одной проге.
В таблице с деревом было создано длинное текстовое поле. В это текстовое
поле записывались коды всех его предков, начиная с корня плюс еще и номер
самого элемента. Hапример, так:
ID parent SortField
--------------------------
1 NULL 000001
2 1 000001000002
3 2 000001000002000003
Убого, конечно, но жить можно. Если отсортировать по этому полю, то
получается как раз дерево.
Если сделать запрос, к примеру, SELECT * FROM thisTable WHERE SortField LIKE
'000001%', то можно получить ВСЕХ потомков элемента 1.
> Хочется: получить список всех потомков, список предков, определение
> принадлежности к потомкам и т.п.
> Поделитель прз. идеями. а еще лучше ссылками/названиями токовых
_учебников_
> PS Если вышеперечисленное делать на SP, то как выглядит ее болванка? - это
> вроде должна быть с одной стороны рекурсия, с другой select?
> PPS Если это не совсем chainik, то плз. в эху
>
--- ifmail v.2.15dev5
* Origin: Demos online service (2:5020/400)
Вернуться к списку тем, сортированных по: возрастание даты уменьшение даты тема автор
Архивное /su.dbms.sql/6577d34bbb7f.html, оценка из 5, голосов 10
|