Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Копирование иерархий(поддеревьев в дереве)


Страницы:   1 2

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]

а можно взять и присвоить друго просто родителя, вот и все.


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо