|
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
|