powered by simpleCommunicator - 2.0.60     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Триггер, рекурсивный delete, есть грабли?
7 сообщений из 7, страница 1 из 1
Триггер, рекурсивный delete, есть грабли?
    #33906447
RomanVK
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Здравствуйте.
Первый раз работаю с триггерными функциями, почитал мануал, что-то попробовал...

есть дерево:
Код: plaintext
1.
2.
3.
4.
5.
6.
CREATE TABLE fmtest
(
  message_id int4 NOT NULL DEFAULT nextval('message_id_seq'::regclass), --id элемента
  message_pid int4 NOT NULL, -- id предка
...
)

Хочу сделать удаление всех потомков при удалении элемента


Код: plaintext
1.
2.
3.
4.
CREATE TRIGGER tg_forum_message_delete  BEFORE DELETE
  ON fmtest
  FOR EACH ROW
  EXECUTE PROCEDURE tf_forum_message_delete();

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
CREATE OR REPLACE FUNCTION tf_forum_message_delete()
  RETURNS "trigger" AS
$BODY$BEGIN

DELETE FROM fmtest WHERE message_pid=OLD.message_id;
RETURN OLD;

END$BODY$
  LANGUAGE 'plpgsql' VOLATILE;

Вопрос1... есть тут какие-нибудь грабли и не спорол ли я чушь? Вроде-бы всё работает правильно, но как-то довольно медленно(в принципе не критично но странно)... Обход дерева селектами идёт ГОРАЗДО быстрее, что мне кажется странным...

Вопрос2 - можно ли определить, первый ли это делит или нет?
на событие ПОСЛЕ удаления тоже хотелось-бы повесить тригер, чтоб он делал апдейт пары полей в этой-же таблице но только при удаление элеемента, а при рекурсивном удалении потомков не делал?..

спасибо
...
Рейтинг: 0 / 0
Триггер, рекурсивный delete, есть грабли?
    #33906580
RomanVK
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
про время выполнения вопрос снимается... делал на тестовой странице которая не была нормально проиндексирована, на боевой таблице отработало шустро :)

Остается второй вопрос... можно как-то определить, запущен ли DELETE запросом или-же он выполнен в тригерной функции... можно конечно делать апдейт после удаления каждого потомка, но это получится куча лишних апдейтов, некрасиво и дольше...

я слабо понял что значит per-statement, может как раз если сделать тип тригера per-statement, то это будет то что надо, или нет?
...
Рейтинг: 0 / 0
Триггер, рекурсивный delete, есть грабли?
    #33907271
4321
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
RomanVKпро время выполнения вопрос снимается... делал на тестовой странице которая не была нормально проиндексирована, на боевой таблице отработало шустро :)

Остается второй вопрос... можно как-то определить, запущен ли DELETE запросом или-же он выполнен в тригерной функции... можно конечно делать апдейт после удаления каждого потомка, но это получится куча лишних апдейтов, некрасиво и дольше...

я слабо понял что значит per-statement, может как раз если сделать тип тригера per-statement, то это будет то что надо, или нет?
1. мне кажется ваш велосипед будет хуже стандартного FK с условием ON DELETE CASCADE (который тоже порождает триггер , но триггер не "совсем обычный", а создаваемый модификатором CONSTRAINT
CREATE CONSTRAINT TRIGGER ....
причем триггерная ф-я будет у вас системной, написанной видимо на C и вероятно - более быстрой.

2. в стейтмент риггере вы не знаете OLD, (вернее DELETED) и поэтому вам придется делать что-то вида
2.1.
DELETE FROM fmtest
WHERE NOT EXISTS(SELECT * FROM fmtest f WHERE f.id = fmtest.pid)

(в принципе это можно было бы делать через лефт джойн, но делете в пг не поддерживает синтаксиса удаления из внешнего джойна (примерно такого):
2.2.
DELETE f.* FROM fmtest f
LEFT JOIN fmtest f1 ON f1.id = f.pid
WHERE f1.id IS NULL
(по крайней мере я не знаю, как его записать при помощи фичи USING )
и посему придется делать что-то наподобие
2.3
DELETE fmtest WHERE id IN (SELECT f.id FROM fmtest f
LEFT JOIN fmtest f1 ON f1.id = f.pid
WHERE f1.id IS NULL)
что вряд ли быстрее 2.1. (надо смотреть)
...
Рейтинг: 0 / 0
Триггер, рекурсивный delete, есть грабли?
    #33909155
RomanVK
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
А разве можно делать вторичный ключ на колонку в этой-же таблице?
Мне почему-то казалось, что нет... правда не пробовал... мне почему-то сама эта идея казалась абсурдной... :)
...
Рейтинг: 0 / 0
Триггер, рекурсивный delete, есть грабли?
    #33909361
RomanVK
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
4321 Отлично, оказывается можно, большое спасибо ... Вот ещё неизвестно сколько без этого совета жил-бы и не знал что внешним ключем колонки можно делать первичный ключ той-же таблицы.... :) Это как раз то, что доктор прописал :)

Правда всё равно остается открытым вопрос по поводу того, что тригерная функция, которая идет после удаления сообщения, вызывается и делает апдейт после удаления каждого потомка... Как сделать чтобы при обычном делите апдейт(нужно апдейтить время последнего сообщения(последнего потомка) для корневого сообщения) делался только при удалении того что указано в делите и не делался при каскадном удалении всех потомков... хотя по скорости и так вполне устраивает... но чисто эстетически не очень красиво.. ненужная избыточность... :)
...
Рейтинг: 0 / 0
Триггер, рекурсивный delete, есть грабли?
    #33909826
4321
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
RomanVKКак сделать чтобы при обычном делите апдейт(нужно апдейтить время последнего сообщения(последнего потомка) для корневого сообщения) делался только при удалении того что указано в делите и не делался при каскадном удалении всех потомков... хотя по скорости и так вполне устраивает... но чисто эстетически не очень красиво.. ненужная избыточность... :)можно сделать грубо и зримо - запретить делет из таблицы напрямую. и написать ХП для удаления, которая, кроме того, вместо триггера будет апдейтить вашу стороннюю таблицу.


можно видимо сделать через любую переменную сеанса (в частности, в plpgsql, - через создание временной таблицы или счетчика -в качестве флага "не первости отработки триггера" - с обрабоботкой исключения в триггере - если таблица/счетчик еще не созданы), например, - пользуя языки, в которых переменные сеанса создаются лехко и непринужденно.
...
Рейтинг: 0 / 0
Триггер, рекурсивный delete, есть грабли?
    #33910038
domanix
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Кстати - переменную сеанса можно сделать и в простом pgplsql и даже sql
я тут недавно для себя открыл
если в файле postgresql.conf в разделе

#---------------------------------------------------------------------------
# CUSTOMIZED OPTIONS
#---------------------------------------------------------------------------
добавить свой класс :
# list of custom variable class names
custom_variable_classes = 'session'

то после рестарта сервера можно создавать и использовать сессионные переменные. Ограничение только одно - эта переменная содержит только строки..
к примеру:
select current_setting('session.var1') -> unset
select set_config('session.var1',100,false) -> set session.var1='100'
select current_setting('session.var1') -> 100
...
Рейтинг: 0 / 0
7 сообщений из 7, страница 1 из 1
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Триггер, рекурсивный delete, есть грабли?
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]