Хотя ответ Джереми хороший, все еще есть возможности для улучшения.
Проблемы
Вы должны быть очень точными в определениицели.Ваше заявление:
Мне нужно удалить строку вместо обновления в случае, если значение целевой ячейки равно нулю.
... не означает, что столбец был изменен наNULL
в UPDATE
под рукой.Может быть, NULL
до того, как вы реализовали триггер.Так что не:
<strike>BEFORE UPDATE OF def_id ON public.definition_products</strike>
, а просто:
BEFORE UPDATE ON public.definition_products
Конечно, если столбец определен NOT NULL
(как это, вероятно, и должно быть), эффективной разницы нет - кромедля шума и дополнительной точки отказа. Руководство:
Будет сработать специфичный для столбца триггер (один из которых определен с использованием UPDATE OF
column_name
)когда любой из его столбцов указан как цель в списке UPDATE
команды *1036*.Возможно изменение значения столбца, даже если триггер не запущен, поскольку изменения, внесенные в содержимое строки с помощью триггеров BEFORE UPDATE
, не учитываются.
Кроме того, ничто в вашем вопросе не указывает на необходимость динамического SQL.(Это будет в том случае, если вы хотите повторно использовать одну и ту же функцию триггера для нескольких триггеров в разных таблицах. И даже тогда часто лучше просто создать несколько отдельных функций триггера по нескольким причинам: проще, быстрее, меньшеподверженный ошибкам, легче читаемый и поддерживаемый, ...)
Что касается "подверженного ошибкам": ваш исходный динамический оператор был просто недействителен:
<strike>EXECUTE 'DELETE FROM ' || TG_TABLE_NAME || ' WHERE $1 = ''$2'''
USING refColumnName, OLD.id;</strike>
- Can 'Передать имя столбца как значение (
refColumnName
). - Невозможно поместить одинарные кавычки вокруг
$2
, который передается как значение и, следовательно, не нуждается в кавычках. - Неквалифицированный, без кавычек
TG_TABLE_NAME
может пойти ужаснонеправильный, что особенно важно для функции с большим весом, которая удаляет строки.
Версия Джереми исправляет большинство, но все еще содержит неквалифицированную TG_TABLE_NAME
.
Это было бы хорошо:
EXECUTE format('DELETE FROM %s WHERE %I = $1', TG_RELID::regclass, refColumnName) -- refColumnName still unquoted
USING OLD.id;
Или:
EXECUTE format('DELETE FROM %I.%I WHERE %I = $1', TG_TABLE_SCHEMA, TG_TABLE_NAME, refColumnName)
USING OLD.id;
Связанный:
Решение
Упрощенная функция триггера:
CREATE OR REPLACE FUNCTION delete_on_update_related_table()
RETURNS trigger AS
$func$
BEGIN
DELETE FROM public.definition_products WHERE id = OLD.id; -- def_id?
RETURN NULL;
END
$func$ LANGUAGE plpgsql;
Более простой триггер:
CREATE TRIGGER proper_delete
BEFORE UPDATE ON public.definition_products
FOR EACH ROW
WHEN (NEW.def_id IS NULL) -- that's the defining condition!
EXECUTE PROCEDURE delete_on_update_related_table(); -- no parameter
Вы, вероятно, хотите использовать OLD.id
, а не OLD.def_id
.(Строка для удаления лучше всего определяется по PK, а не по столбцу, измененному на NULL
.) Но это не совсем понятно.