Можно ли динамически петлю через столбцы таблицы?
-
28-09-2019 - |
Вопрос
У меня есть триггерная функция для теста настольный, который имеет следующий фрагмент кода:
IF TG_OP='UPDATE' THEN
IF OLD.locked > 0 AND
( OLD.org_id <> NEW.org_id OR
OLD.document_code <> NEW.document_code OR
-- other columns ...
)
THEN
RAISE EXCEPTION 'Message';
-- more code
Таким образом, я статически проверяющую все новое значение колонки со своим предыдущим значением для обеспечения целостности. Теперь каждый раз мои бизнес-логические изменения, и я должен добавить новые столбцы в эту таблицу, мне придется модифицировать этот триггер каждый раз. Я думал, что было бы лучше, если каким-то образом я смогу динамически проверять все столбцы этой таблицы, без явного набора их имени.
Как это можно сделать?
Решение
Взгляните на информацию information_schema, есть вид «столбцы». Выполните запрос, чтобы получить все текущие столбцы из таблицы, который выпустил триггер:
SELECT
column_name
FROM
information_schema.columns
WHERE
table_schema = TG_TABLE_SCHEMA
AND
table_name = TG_TABLE_NAME;
Петля через результат и там вы идете!
Больше информации можно найти в Точное руководство.
Другие советы
От 9,0 beta2 документации о WHEN
Пункт в триггерах, которые могут быть в состоянии использовать в более ранних версиях в телу триггера:
OLD.* IS DISTINCT FROM NEW.*
или, возможно, (от 8.2 заметок выпуска)
IF row(new.*) IS DISTINCT FROM row(old.*)
Используйте PL / Perl или PL / Python. Они намного лучше подходят для таких задач. много лучше.
Вы также можете установить HSTORE-NEW, И используйте его семантику Row-> HStore, но это определенно не хорошая идея при использовании нормальных данных.
В Postgres 9.0 или позже добавить WHEN
пункт к вашему определению триггера (CREATE TRIGGER
утверждение):
CREATE TRIGGER foo
BEFORE UPDATE
FOR EACH ROW
WHEN (OLD IS DISTINCT FROM NEW) -- parentheses required!
EXECUTE PROCEDURE ...;
Только возможен только для триггеров BEFORE
/ AFTER
UPDATE
, где оба OLD
и NEW
определены. Вы бы получили исключение, пытаясь использовать это WHEN
оговорка INSERT
или DELETE
триггеры.
И радикально упростить триггер функция соответственно:
...
IF OLD.locked > 0 THEN
RAISE EXCEPTION 'Message';
END IF;
...
Нет необходимости проверять IF TG_OP='UPDATE' ...
Так как этот триггер работает только для UPDATE
так или иначе.
Или переместите это состояние в пункте, когда тоже:
CREATE TRIGGER foo
BEFORE UPDATE
FOR EACH ROW
WHEN (OLD.locked > 0
AND OLD IS DISTINCT FROM NEW)
EXECUTE PROCEDURE ...;
Оставив только безусловный RAISE EXCEPTION
В вашей функции триггера, которая называется только при запуске с.
В
BEFORE
триггер, тоWHEN
условие оценивается непосредственно перед выполнением функции или будет выполнена, поэтому используяWHEN
не существенно отличается от тестирования того же состояния в начале функции триггера. Обратите внимание, чтоNEW
Строка, наблюдаемая условием, является текущее значение, возможно, модифицировано более ранние триггеры. ТакжеBEFORE
триггерWHEN
условие не разрешено изучить системные колонныNEW
строка (например, какoid
), потому что те не будут установлены.В ан
AFTER
триггер, тоWHEN
Состояние оценивается сразу после возникновения обновления строки, и он определяет, очевидно ли событие, чтобы выстрелить спусковой крючок в конце оператора. Так что когда АнAFTER
триггерWHEN
Состояние не возвращает true, нет необходимости в очереди события, ни для повторной обработки строки в конце оператора. Это может привести к значительным ускорению в заявлениях, которые изменяют много строк, если триггер требуется только для нескольких строк.
Связанный:
Также решить вопрос о вопросе
Можно ли динамически петлю через столбцы таблицы?
Да. Примеры: