Форум: "Базы";
Текущий архив: 2003.04.17;
Скачать: [xml.tar.bz2];
ВнизКопирование иерархий(поддеревьев в дереве) Найти похожие ветки
← →
AlexandrN (2003-03-26 09:16) [0]Привет всем...
Короче...
Есть иерархическая структура представленная как PARENT - CHILD, в таблице вида:
ID | Parent_ID | Level | Other
, где ID - идентификатор объекта;
Parent_ID - ссылка на ID;
Level - уровень в дереве;
Если кто знает или подозревает,
Как можно скопировать часть поддерева и вставить его в новое место, причём именно копирование(как в проводнике с папками), то немогли бы вы поделиться как всётаки это делается, хотелось бы всётаки увидеть как это делаетсь на практике, а не в теории.
← →
Mike_Goblin (2003-03-26 09:21) [1]На практике это делается с помощью рекурсивных вызовов процедуры копирования элемента дерева.
← →
Соловьев (2003-03-26 09:31) [2]а можно взять и присвоить друго просто родителя, вот и все.
← →
Sergey13 (2003-03-26 09:34) [3]2AlexandrN (26.03.03 09:16)
Это вопрос не простой даже для Оракула(где есть "деревянные" запросы). Основная сложность состоит в том, что надо по ходу дела менять ID & Parent_ID на новые, но сохранять при этом связи. Я делал это примерно так (на Оракле). Вытаскивал в память все узлы и сразу(в запросе) генерил им новые Id-шники. Потом бегал по этому "массиву" циклами и заменял старые значения ID & Parent_ID на новые. Потом уже писал в таблицу.
← →
Polevi (2003-03-26 09:35) [4]2Соловьев © (26.03.03 09:31)
это будет не копирование а перемещение
← →
Соловьев (2003-03-26 09:45) [5]сорри не догнал сначала.
← →
AlexandrN (2003-03-26 10:12) [6]Да подкинул ч не лёгкую задачку....??????
Но всё же где - же вы умельцы, которые моглибы поделиться, хотябы самой тупой реализацией (SP or Func)!?
← →
zacho (2003-03-26 10:31) [7]
> AlexandrN (26.03.03 10:12)
Какая СУБД ?
← →
kaif (2003-03-26 10:33) [8]Для работы с деревьями в IB я написал 2 процедуры.
1. Одна возвращает ID всех предков данного узла, включая его самого.(простой запрос предка в цикле, пока ID предка найден + SUSPEND)
2. Вторая процедура объединяет всю таблицу дерева с результатом работы первой процедуры и возвращает все пары
ID, CHILD_ID с помощью SUSPEND. В результате я получаю виртуальную таблицу, в которой каждому ID сопоставлены все потомки всех уровней для данного ID.
Все дольнейшие операции работы с деревом тогода не представляют труда. Например, чтобы выбрать всех потомков данного ID мне достаточно сделать простой SELECT из второй процедуры с условием ID = что-то.
Соответственно subj.
Я бы просто взял результат такого селекта, объединил еще раз с исходной таблицей, чтобы получить CHILD_ID, PARENT_ID, дал бы смещение, равное общему количеству COUNT(*) строк такого набора обоим полям и одной командой вставил бы в ту же таблицу.
INSERT INTO T1
SELECT P2.CHILD_ID + :offset, T1.PARENT_ID + :offset
FROM PROCEDURE2 P2, T1 WHERE P2.CHILD_ID = T1.ID;
Надеюсь, объяснил понятно.
← →
Соловьев (2003-03-26 10:38) [9]Я вот писал процедуру для поиска пути от родителя до корня.
думаю переделать ее под твою задачу не займет много времени:
CREATE PROCEDURE GETPARENTS (
ID_PROF INTEGER)
RETURNS (
NAME VARCHAR (1000))
AS
DECLARE VARIABLE PATH VARCHAR(1000);
DECLARE VARIABLE PATH_TEMP VARCHAR(1000);
DECLARE VARIABLE OID INTEGER;
DECLARE VARIABLE ID INTEGER;
BEGIN
FOR
SELECT ID_OPERATION
FROM TYPE_OPERATION
WHERE CHILD_CNT=0 AND PROFESSION_ID=:ID_PROF
INTO :ID
DO
BEGIN
PATH_TEMP = " ";
WHILE (:ID > 0) DO /* ИЩЕМ ДО КОРНЯ */
BEGIN
SELECT O.PARENT_ID, O.NAME_OPERATION
FROM TYPE_OPERATION O
WHERE O.ID_OPERATION = :ID
INTO :OID, :PATH;
ID = :OID; /* КОД РОДИТЕЛЯ ДЛЯ СЛЕДУЮЩЕЙ ВЫБОРКИ */
PATH_TEMP = :PATH||"|"||PATH_TEMP;
END
NAME = :PATH_TEMP;
SUSPEND;
END
END
← →
kaif (2003-03-26 10:39) [10]Точнее
INSERT INTO T1
SELECT P2.CHILD_ID + :offset, T1.PARENT_ID + :offset
FROM PROCEDURE2 P2, T1 WHERE P2.CHILD_ID = T1.ID AND P2.ID = :id;
где параметр :id - "копируемая" папка.
← →
Соловьев (2003-03-26 10:42) [11]Забыл написать, что это для IB и FB
← →
kaif (2003-03-26 10:52) [12]2 Соловьев © (26.03.03 10:38)
Да, Вы правы. Именно так можно построить первую процедуру. Только возвращать надо не текст пути, а просто PARENT_ID и ID всех обойденных пунктов.
Затем объединив в запросе такой набор по PARENT_ID с исходной таблицей получаем все пары старший-любой младший. А затем любая, самая невероятная задача работы с деревом решается как правило одним простым селектом.
← →
Соловьев (2003-03-26 10:54) [13]2 kaif ©
я же и написал, что надо будет переделать чутка...
← →
AlexandrN (2003-03-26 11:26) [14]Ответ на вопрос про СУБД: Sybase SQL Anywhere 7.
← →
kaif (2003-03-26 11:34) [15]Если в Sybase нет аналога команде SUSPEND InterBase-а, то мой метод не будет работать и придется писать обход дерева в лоб в каком-нибудь курсоре.
← →
AlexandrN (2003-03-26 11:40) [16]Да Sybase не знает про SUSPEND...
← →
Sergey13 (2003-03-26 11:54) [17]2AlexandrN (26.03.03 09:16)
А какая разница SUSPEND... не SUSPEND...
Смысл то одинаковый. Выташить искомое дерево, переназначить ID и вставить назад. Или тебе готовую процедуру хочется? Сейчас то ты с деревом как работаешь? Или не работаешь вообще?
← →
AlexandrN (2003-03-26 12:13) [18]2Sergey13:
Дерево для копирования получаю просто за один запрос, за счёт хранения иерархий элементов дерева в виде:
.ROOT_ID.ID.ID.ID. ....
, где ROOT_ID - корень всего дерева(АЛЯ диски в проводнике);
ID - дочерние элементы;
Также стоит тригер на добавление новых элементов, который автоматически расчитывает уровень нового элемента в дереве, и строит иерархию для этого элемента.
На счёт готовой процедуры.......!
Сам я неселён в написании этих самых ханимых процедур и функции(ПЛОХОВАТО - САМ ПОНИМАЮ) поэтому и обратился к обществу с таким вопросом, в надежде, что ктото делал уже подобное и ему несоставит большого труда поделиться реализацией.
P.S.
Спасибо всем ктоб что либо предлагает...
← →
kaif (2003-03-26 12:27) [19]Самое главное это может ли Sybase, как это делает IB, с выходным набором, возвращаемым процедурой обращаться как с простой таблицей?
То есть можно ли в Sybase написать
SELECT * FROM MYPROCEDURE ?
← →
AlexandrN (2003-03-26 13:11) [20]Походу дела нет...
← →
Sergey13 (2003-03-27 10:11) [21]2AlexandrN (26.03.03 12:13)
>Дерево для копирования получаю просто за один запрос, за счёт >хранения иерархий элементов дерева в виде:
>.ROOT_ID.ID.ID.ID. ....
>, где ROOT_ID - корень всего дерева(АЛЯ диски в проводнике);
> ID - дочерние элементы;
Т.е. одной строкой получаешь что ли? Тогда это не дерево, а список дочерних узлов или конкретная ветка дерева. Если это ветка (т.е. каждый следующий ID это потомок предыдущего и наоборот) и надо скопировать именно ее то какие затруднения у тебя это вызывает. Схема твоей процедуры примерно такая будет. С Sybase не знаком, поэтому своими словами:
получаешь свою цепочку ID, запоминаешь ее
В цикле по цепочке
1.генеришь новый ID, запоминаешь его
2.делаешь insert где ID это только что сгенеренный, Parent_id запомненый предыдущий(для первой записи NULL или Id того места куда вставляешь ветку), остальные поля старые
Примерно так. С конкретной реализацией - сам.
Страницы: 1 вся ветка
Форум: "Базы";
Текущий архив: 2003.04.17;
Скачать: [xml.tar.bz2];
Память: 0.49 MB
Время: 0.009 c