Можно ли динамически перебирать столбцы таблицы? - PullRequest
5 голосов
/ 21 июня 2010

У меня есть функция триггера для проверки таблицы со следующим фрагментом кода:

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

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

Как это можно сделать?

Ответы [ 5 ]

8 голосов
/ 21 июня 2010

Из документации 9.0 beta2 о предложении WHEN в триггерах, которое можно использовать в более ранних версиях в теле триггера:

OLD.* IS DISTINCT FROM NEW.*

или, возможно, ( из 8.2 заметок о выпуске )

IF row(new.*) IS DISTINCT FROM row(old.*)

7 голосов
/ 21 июня 2010

Посмотрите на information_schema, там есть вид "столбцы". Выполните запрос, чтобы получить все текущие имена столбцов из таблицы, из которой сработал триггер:

SELECT 
    column_name 
FROM 
    information_schema.columns 
WHERE 
    table_schema = TG_TABLE_SCHEMA 
AND 
    table_name = TG_TABLE_NAME;

Просмотрите результат, и все!

Более подробную информацию можно найти в подробном руководстве .

2 голосов
/ 02 марта 2012
1 голос
/ 22 июня 2010

Используйте pl / perl или pl / python. Они гораздо лучше подходят для таких задач. намного лучше.

Вы также можете установить hstore-new и использовать его семантику row-> hstore, но это определенно не очень хорошая идея при использовании обычных типов данных.

0 голосов
/ 10 апреля 2018

В 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.

Или переместите это условие также в предложение WHEN:

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, видимая условием, является текущим значением, которое, возможно, было изменено более ранними триггерами.Кроме того, условие WHEN триггера BEFORE не позволяет просматривать системные столбцы строки NEW (например, oid), поскольку они еще не были установлены.

InДля триггера AFTER условие WHEN оценивается сразу после обновления строки и определяет, стоит ли событие в очереди для запуска триггера в конце оператора.Таким образом, когда условие AFTER триггера *1054* не возвращает true, нет необходимости ставить в очередь событие или повторно извлекать строку в конце оператора.Это может привести к значительному ускорению операторов, которые изменяют много строк, если триггер нужно запускать только для нескольких строк.

Related:

Также для обращения к заголовку вопроса

Можно ли динамически циклически проходить по столбцам таблицы?

Да.Примеры:

...