Страница 1 из 1
ХП & Дерево
Добавлено: 02 июн 2006, 12:28
santilaas
Всем привет!
Помогите, кому не трудно!
Скажем, у меня в БД имеется таблица типа дерева (Id_Good, Id_Parent, Good_Name, FullPath).
Мне нужно, чтобы при вставке - изменении данных в этой таблице автоматически формировалось поле FullPath, которое есть объединение всех полей Name вплоть до редактируемого элемента.
(т.е полный путь к редактируемогу элементу)
В книге "Мир Interbase 3" на стр. 71-74 есть очень хороший пример рекурсивной процедуры, в которой входным параметром является
идентификатор категории, начиная с которой и формируется полный путь. Эту процедуру я взял себе.
Но у меня проблема:
Как все-таки из триггера обратиться к этой процедуре и взять из неё путь только к данному-текущему редактируемому элементу?
Делаю так, но что-то не то:
Код: Выделить всё
CREATE TRIGGER STRUCT_EL_BI_BU_TRIG FOR STRUCT_EL
ACTIVE BEFORE INSERT OR UPDATE POSITION 1 //для этой таблицы
//имеется также триггер BeforeInsert, формирующий new.id_good
as
declare variable full_goods_name varchar(251);
begin
select g.full_goods_name from Getfullname(1) g
where g.Id_child_Good = NEW.Id_good
into :full_goods_name;
new.FullPath = :full_goods_name;
end
- ничего не заносится.
Только, пожалуйста, не отправляйте читать доку - и так над книжкой провел много времени. Хотя, не знаю - может фигу увидел?!
Заранее благодарен
Добавлено: 02 июн 2006, 13:13
Dimitry Sibiryakov
А зачем тебе каждый раз проходить весь путь? Взял FullPath парента и добавил к нему свое. Все.
SELECT FullPath||:new.Name from struct_el where Id_good=:new.Parent_Id into New.FullPath;
Добавлено: 02 июн 2006, 15:27
Zhur
Dimitry Sibiryakov писал(а):А зачем тебе каждый раз проходить весь путь? Взял FullPath парента и добавил к нему свое. Все.
SELECT FullPath||:new.Name from struct_el where Id_good=:new.Parent_Id into New.FullPath;
А если у парента парент изменится??? Тогда придется наоборот, всех чайлдов искать и изменять у них...тут даже посложнее будет
Добавлено: 02 июн 2006, 15:37
santilaas
Я вот тоже думал-думал. Скорее всего так и надо, как в книге. Вот только как из процедуры получить нужное значение?
Добавлено: 02 июн 2006, 15:51
Zhur
santilaas писал(а):Я вот тоже думал-думал. Скорее всего так и надо, как в книге. Вот только как из процедуры получить нужное значение?
А как в книге? Поподробнее.. а то я эту гнигу не видал. Я только по статьям тренируюсь
Добавлено: 02 июн 2006, 20:28
santilaas
Код: Выделить всё
CREATE PROCEDURE GETFULLNAME (ID_GOOD2SHOW INTEGER)
RETURNS (FULL_GOODS_NAME VARCHAR(250), ID_CHILD_GOOD INTEGER)
AS
DECLARE VARIABLE CURR_CHILD_NAME VARCHAR(35);
begin
/*организуем внешний цикл For Select по непосредственным потомкам товара с ID_GOOD = ID_GOOD2SHOW*/
for select gt.id_good, gt.good_name
from GoodsTree gt
where gt.id_parent=:Id_Good2Show
into :ID_CHILD_GOOD, :full_goods_name
do
begin
/*если у найденного узла с ID_PARENT_GOOD = ID_CHILD_GOOD нет потомков, то он является "листом" дерева
и попадает в результаты*/
if (not exists (select * from GoodsTree
where GoodsTree.Id_parent_good=:id_child_good))
then
begin
/* Передаём лист дерева в результаты */
suspend;
end
else
begin
/* сохраняем имя узла-родителя во временной переменной */
curr_child_name = full_goods_name;
/* рекурсивно запускаем эту процедуру */
for
select ID_CHILD_GOOD, full_goods_name
from GETFULLNAME (:ID_CHILD_GOOD)
into :ID_CHILD_GOOD, :full_goods_name
do
begin
/*добавляем имя узла-родителя к найденному имени потомка*/
full_goods_name = curr_child_name||'/'||full_goods_name;
suspend; /* возвращаем полное имя товара*/
end
end
end
end
- да и ещё разовью мысль -
1) во-первых,получается, если добавляем запись в мою таблицу, то ей должно автоматом в поле Fullpath
записаться полное название вплоть до текущего элемента (опять же - как вышеописанную процедуру вызвать, что получить
значение для path и собственно записать его?????)
(т.е. используем триггер Before insert)
2) Во-вторых, если изменяем элемент, а у него есть потомки, то и у них также должно обновиться значение поля FullPath
(т.е. используем триггер Before Update) - вопрос тот же: какой вызов процедуры?
Добавлено: 02 июн 2006, 21:22
kdv
то ей должно автоматом в поле Fullpath
записаться полное название вплоть до текущего элемента (опять же - как вышеописанную процедуру вызвать, что получить
значение для path и собственно записать его?????)
(т.е. используем триггер Before insert)
где логика? я уже на sql.ru ответил. Все это напоминает здесь вопрос mila про "обработку вставленных записей в udf, которая вызывается из триггера на after insert".
Во-вторых, если изменяем элемент, а у него есть потомки, то и у них также должно обновиться значение поля FullPath
ну и накой тогда такая геморройная реализация? неужто тебе в статьях про "деревья"
www.ibase.ru/develop.htm ничего не понравилось?
например, стандартное "дерево", описанное в моей статье, не требует никаких таких жутких телодвижений. Например, при переносе ветки дерева у переносимого элемента меняется parent_id и всё!
Добавлено: 03 июн 2006, 09:03
santilaas
Дело в том, что я и сам не любитель хранить полный путь (посоветовали мне).
И в принципе оно скорее всего и не нужно.
На самом деле ситуация такая:
в БД есть таблица№1 и таблица№2(дерево), в таблице№1 есть внешний ключ на таблицу№2. В приложении есть соответствующие этим таблицам формы. Из формы№1 я открываю форму№2, дважды кликаю на определённой записи таблицы-дерева и полный путь (т.е. Lookup-поле на ключ таблицы№2) должен отобразиться (в поле Edit или DbGrid-e) на форме№1.
Ну и соответственно если, просто открываем форму№1 - это lookup-поле уже должно отображать полный путь.
Добавлено: 03 июн 2006, 12:05
Zhur
Да и мне прищлось хранить полный путь... только не текстовые выражения типа 'NAME1\NAME2\NAME3', а их идентификаторы '1~1253~123'... короче как в той статье про деревья.
Связано это с тем, что у меня будут выборки чайлдрв, НЕ принадлежащих узлу. Без хранения поля FULLPATH такие запросы у меня долго работали (я использовал NOT IN ХП).
Кстати, про это даже недавно мой топик был.
Добавлено: 03 июн 2006, 20:01
santilaas
Спасибо всем, кто откликнулся.
В общем я послушав и подумав, решил путь в таблице оставить,
и для моей реальной таблицы (Kod, Kod_parent, Name, Path, Type, Power) получил три триггера:
Код: Выделить всё
----------------------------------------------
CREATE TRIGGER STRUCT_EL_BI_TRIG FOR STRUCT_EL
ACTIVE BEFORE INSERT POSITION 1
as
declare variable new_path varchar(251);
begin
/* если элемент находится в самой верхушке дерева,
тогда путь будет равен названию этого элемента*/
if (new.kod_parent = 0) then
new.path = new.name;
/* иначе новый путь будет складываться из пути родителя
+ '\' + название нового элемента*/
else
begin
select path
from struct_el
where kod = new.kod_parent
into :new_path;
new.path = :new_path||'\'||new.name;
end
end
-----------------------------------------------
CREATE TRIGGER STRUCT_EL_BU_TRIG FOR STRUCT_EL
ACTIVE BEFORE UPDATE POSITION 0
as
declare variable new_path varchar(251);
begin
/* если у данного элемента сменился родитель или название, тогда ...*/
if ((new.kod_parent <> old.kod_parent) or
(new.name <> old.name)) then
if (new.kod_parent = 0) then
new.path = new.name;
else
begin
select path
from struct_el
where kod = new.kod_parent
into :new_path;
new.path = :new_path||'\'||new.name;
end
end
-----------------------------------------------
CREATE TRIGGER STRUCT_EL_AU_TRIG FOR STRUCT_EL
ACTIVE AFTER UPDATE POSITION 0
as
begin
if (new.path <> old.path) then
update struct_el
set path = new.path||'\'||name
where kod_parent = new.kod;
end
------------------------------------------------
- вроде все работает, на быстродействие не проверял, но думаю для ограниченного в 7 уровней дерева - попрет.