![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Копирование иерархий(поддеревьев в дереве)
AlexandrN © (2003-03-26 09:16:00)Привет всем...
Короче...
Есть иерархическая структура представленная как PARENT - CHILD, в таблице вида:
ID | Parent_ID | Level | Other
, где ID - идентификатор объекта;
Parent_ID - ссылка на ID;
Level - уровень в дереве;
Если кто знает или подозревает,
Как можно скопировать часть поддерева и вставить его в новое место, причём именно копирование(как в проводнике с папками), то немогли бы вы поделиться как всётаки это делается, хотелось бы всётаки увидеть как это делаетсь на практике, а не в теории.
Sergey13 (2003-03-27 10:11:00) [1]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 того места куда вставляешь ветку), остальные поля старые
Примерно так. С конкретной реализацией - сам.
AlexandrN (2003-03-26 13:11:00) [2]Походу дела нет...
kaif (2003-03-26 12:27:00) [3]Самое главное это может ли Sybase, как это делает IB, с выходным набором, возвращаемым процедурой обращаться как с простой таблицей?
То есть можно ли в Sybase написать
SELECT * FROM MYPROCEDURE ?
AlexandrN (2003-03-26 12:13:00) [4]2Sergey13:
Дерево для копирования получаю просто за один запрос, за счёт хранения иерархий элементов дерева в виде:
.ROOT_ID.ID.ID.ID. ....
, где ROOT_ID - корень всего дерева(АЛЯ диски в проводнике);
ID - дочерние элементы;
Также стоит тригер на добавление новых элементов, который автоматически расчитывает уровень нового элемента в дереве, и строит иерархию для этого элемента.
На счёт готовой процедуры.......!
Сам я неселён в написании этих самых ханимых процедур и функции(ПЛОХОВАТО - САМ ПОНИМАЮ) поэтому и обратился к обществу с таким вопросом, в надежде, что ктото делал уже подобное и ему несоставит большого труда поделиться реализацией.
P.S.
Спасибо всем ктоб что либо предлагает...
Sergey13 (2003-03-26 11:54:00) [5]2AlexandrN (26.03.03 09:16)
А какая разница SUSPEND... не SUSPEND...
Смысл то одинаковый. Выташить искомое дерево, переназначить ID и вставить назад. Или тебе готовую процедуру хочется? Сейчас то ты с деревом как работаешь? Или не работаешь вообще?
AlexandrN (2003-03-26 11:40:00) [6]Да Sybase не знает про SUSPEND...
kaif (2003-03-26 11:34:00) [7]Если в Sybase нет аналога команде SUSPEND InterBase-а, то мой метод не будет работать и придется писать обход дерева в лоб в каком-нибудь курсоре.
AlexandrN (2003-03-26 11:26:00) [8]Ответ на вопрос про СУБД: Sybase SQL Anywhere 7.
Соловьев (2003-03-26 10:54:00) [9]2 kaif ©
я же и написал, что надо будет переделать чутка...
kaif (2003-03-26 10:52:00) [10]2 Соловьев © (26.03.03 10:38)
Да, Вы правы. Именно так можно построить первую процедуру. Только возвращать надо не текст пути, а просто PARENT_ID и ID всех обойденных пунктов.
Затем объединив в запросе такой набор по PARENT_ID с исходной таблицей получаем все пары старший-любой младший. А затем любая, самая невероятная задача работы с деревом решается как правило одним простым селектом.
Соловьев (2003-03-26 10:42:00) [11]Забыл написать, что это для IB и FB
kaif (2003-03-26 10:39:00) [12]Точнее
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:38:00) [13]Я вот писал процедуру для поиска пути от родителя до корня.
думаю переделать ее под твою задачу не займет много времени:
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:33:00) [14]Для работы с деревьями в 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;
Надеюсь, объяснил понятно.
zacho (2003-03-26 10:31:00) [15]
> AlexandrN (26.03.03 10:12)
Какая СУБД ?
AlexandrN (2003-03-26 10:12:00) [16]Да подкинул ч не лёгкую задачку....??????
Но всё же где - же вы умельцы, которые моглибы поделиться, хотябы самой тупой реализацией (SP or Func)!?
Соловьев (2003-03-26 09:45:00) [17]сорри не догнал сначала.
Polevi (2003-03-26 09:35:00) [18]2Соловьев © (26.03.03 09:31)
это будет не копирование а перемещение
Sergey13 (2003-03-26 09:34:00) [19]2AlexandrN (26.03.03 09:16)
Это вопрос не простой даже для Оракула(где есть "деревянные" запросы). Основная сложность состоит в том, что надо по ходу дела менять ID & Parent_ID на новые, но сохранять при этом связи. Я делал это примерно так (на Оракле). Вытаскивал в память все узлы и сразу(в запросе) генерил им новые Id-шники. Потом бегал по этому "массиву" циклами и заменял старые значения ID & Parent_ID на новые. Потом уже писал в таблицу.
Соловьев (2003-03-26 09:31:00) [20]а можно взять и присвоить друго просто родителя, вот и все.