Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2003.04.17;
Скачать: CL | DM;

Вниз

Копирование иерархий(поддеревьев в дереве)   Найти похожие ветки 

 
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;
Скачать: CL | DM;

Наверх




Память: 0.52 MB
Время: 0.012 c
3-54506
Гость
2003-03-30 23:18
2003.04.17
QReport - кто хорошо разбирается?


1-54601
diww
2003-04-07 17:00
2003.04.17
как узнать тип ошибки?


3-54494
Palladin
2003-03-31 10:37
2003.04.17
MSSQL Export/Import Wizard


7-54913
AlekseyK
2003-02-26 12:00
2003.04.17
Закрытие другой прграммы


14-54880
Карелин Артем
2003-04-02 09:01
2003.04.17
Что за инфа в отклике сервера?