В функции триггера, как получить, какие поля обновляются - PullRequest
27 голосов
/ 06 января 2012

Возможно ли это? Мне интересно узнать, какие столбцы были указаны в запросе UPDATE, независимо от того, что отправляемое новое значение может быть, а может и не совпадать с тем, которое уже хранится в базе данных.

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

Ответы [ 3 ]

23 голосов
/ 06 января 2012

Если «источник» не «отправляет идентификатор», столбец не изменится.Тогда вы не сможете определить, был ли текущий UPDATE сделан тем же источником, что и последний, или источником, который вообще не изменил столбец.Другими словами: это не работает должным образом.

Если «источник» идентифицируется любой информационной функцией сеанса , вы можете работать с этим.Как:

NEW.column = session_user;

Безоговорочно для каждого обновления.

Общее решение

Я нашел способ решить исходную проблему.Для столбца будет установлено значение по умолчанию при любом обновлении , где столбец не обновляется (отсутствует в списке SET UPDATE).

Ключевым элементом является триггер для каждого столбца , представленный в PostgreSQL 9.0 - специфичный для столбца триггер с использованием предложения UPDATE OFcolumn_name.

Триггер сработает только в том случае, если хотя бы один из перечисленных столбцов упоминается как цель команды UPDATE.

Это единственный простой способ, который я нашел, чтобы отличитьстолбец был обновлен новым значением, идентичным старому, а не обновлен вообще.

Один может также анализировать текст, возвращаемый current_query().Но это кажется хитрым и ненадежным.

Функции триггеров

Я предполагаю, что столбец col определен NOT NULL.

Шаг 1: Установить *От 1053 * до NULL, если не изменилось:

CREATE OR REPLACE FUNCTION trg_tbl_upbef_step1()
  RETURNS trigger AS
$func$
BEGIN
   IF OLD.col = NEW.col THEN
      NEW.col := NULL;      -- "impossible" value
   END IF;

   RETURN NEW;
END
$func$  LANGUAGE plpgsql;

Шаг 2: Возврат к старому значению.Триггер будет срабатывать только в том случае, если значение действительно обновлено (см. Ниже):

CREATE OR REPLACE FUNCTION trg_tbl_upbef_step2()
  RETURNS trigger AS
$func$
BEGIN
   IF NEW.col IS NULL THEN
      NEW.col := OLD.col;
   END IF;

   RETURN NEW;
END
$func$  LANGUAGE plpgsql;

Шаг 3: Теперь мы можем определить недостающее обновление и установитьвместо этого используется значение по умолчанию:

CREATE OR REPLACE FUNCTION trg_tbl_upbef_step3()
  RETURNS trigger AS
$func$
BEGIN
   IF NEW.col IS NULL THEN
      NEW.col := 'default value';
   END IF;

   RETURN NEW;
END
$func$  LANGUAGE plpgsql;

Триггеры

Триггер для Шаг 2 запускается для каждого столбца!

CREATE TRIGGER upbef_step1
  BEFORE UPDATE ON tbl
  FOR EACH ROW
  EXECUTE PROCEDURE trg_tbl_upbef_step1();

CREATE TRIGGER upbef_step2
  BEFORE UPDATE <b>OF col</b> ON tbl                -- key element!
  FOR EACH ROW
  EXECUTE PROCEDURE trg_tbl_upbef_step2();

CREATE TRIGGER upbef_step3
  BEFORE UPDATE ON tbl
  FOR EACH ROW
  EXECUTE PROCEDURE trg_tbl_upbef_step3();

Триггеримена являются релевантными, потому что они запускаются в алфавитном порядке (все BEFORE UPDATE)!

Процедура может быть упрощена с помощью чего-то вроде «триггеров для каждого столбца» или любого другого способа проверкисписок целей UPDATE в триггере.Но я не вижу никакого дескриптора для этого.

Если col может быть NULL, используйте любое другое «невозможное» промежуточное значение и проверьте наличие NULL дополнительно в функции триггера 1:

IF OLD.col IS NOT DISTINCT FROM NEW.col THEN
    NEW.col := '#impossible_value#';
END IF;

Адаптируйте остальные соответственно.

2 голосов
/ 06 января 2012

В plpgsql вы можете сделать что-то подобное в своей функции триггера:

IF NEW.column IS NULL THEN
  NEW.column = 'default value';
END IF;
0 голосов
/ 02 декабря 2015

Я получил другое решение для аналогичной проблемы почти естественным образом, потому что моя таблица содержала столбец с семантикой 'отметка времени последнего обновления' (давайте назовем это UPDT).

Итак, я решил включить новые значения source и UPDT в любое обновление только за один раз (или ни одно из них). Поскольку UPDT предназначен для изменения при каждом обновлении, с такой политикой можно использовать условие new.UPDT = old.UPDT, чтобы сделать вывод, что в текущем обновлении не указан источник, и заменить источник по умолчанию.

Если в таблице уже есть столбец «время последнего обновления», это решение будет проще, чем создание трех триггеров. Не уверен, что лучше создать UPDT, когда он уже не нужен. Если обновления происходят так часто, что существует риск сходства меток времени, вместо метки времени можно использовать секвенсор.

...