firebird - после вставки или триггера обновления - PullRequest
3 голосов
/ 15 февраля 2012

У меня есть расчет в моей БД, необходимо обновить «field1» для «table1» после триггера обновления.

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

, пожалуйста, посоветуйте, как обновить «field1» после того, как триггер «После обновления» был выполнен и без повторного запуска триггера «after update».

Я знаючто я не могу использовать NEW с триггером After.

Спасибо

Ответы [ 4 ]

6 голосов
/ 15 февраля 2012

Можно использовать пользовательский механизм блокировки, основанный на переменных контекста, которые предотвращают повторный вызов триггера AFTER UPDATE.

CREATE TRIGGER au FOR table
  AFTER UPDATE
  POSITION 0
AS
BEGIN
  IF RDB$GET_CONTEXT('USER_TRANSACTION', 'MY_LOCK') IS NULL THEN
  BEGIN
    RDB$SET_CONTEXT('USER_TRANSACTION', 'MY_LOCK', 1);

    ...
    Do your update operations here
    ...

    RDB$SET_CONTEXT('USER_TRANSACTION', 'MY_LOCK', NULL);
  END

  WHEN ANY DO
  BEGIN
    RDB$SET_CONTEXT('USER_TRANSACTION', 'MY_LOCK', NULL);
    EXCEPTION;
  END
END
0 голосов
/ 29 февраля 2012

простое решение ...

запустить обновление только , если значение NEW.FIELD1 действительно новое , например:

CREATE TRIGGER au FOR table1
  AFTER UPDATE
  POSITION 0
AS
DECLARE VARIABLE TMP AS NUMBER(15,5); -- SAME DATATYPE OF FIELD1
BEGIN
  -- MAKE YOUR CALCULATION
  TMP=CALCULATEDVALUE;
  -- UPDATE THE ROW ONLY IF THE VALUES IS CHANGED
  IF (TMP<>NEW.FIELD1) UPDATE TABLE1 SET FIELD1=:TMP WHERE KEY=NEW.KEY; -- PAY ATTENTION IF TMP OR NEW.FIELD1 CAN BE NULL. IN THIS CASE USE COALESCE OR A DIFFERENCE COMPARISON
END
0 голосов
/ 15 февраля 2012

Очевидный ответ - переключиться на триггер BEFORE UPDATE, как указал Дж. Купер ... однако, если есть какая-то причина, по которой вы обязательно должны использовать AFTER UPDATE, тогда вы должны установить флаг, который говорит что поле нужно пересчитать и проверить его в своем триггере. Одним из способов сделать это было бы установить поле на NULL в BEFORE триггере и затем проверить NULL в AFTER триггере, то есть

CREATE TRIGGER bu_trigger BEFORE UPDATE
BEGIN
  -- mark field for recalculation if needed
  IF(update invalidates the field1 value)THEN
     NEW.field1 = NULL;
END

CREATE TRIGGER au_trigger AFTER UPDATE
BEGIN
  -- only update if the field is NULL
  IF(NEW.field1 IS NULL)THEN
     UPDATE table1 SET field1 = ...;
END

Но, используя эту технику, вам, вероятно, придется использовать множество IF(OLD.field IS DISTINCT FROM NEW.field)THEN проверок в триггерах, чтобы избежать ненужных обновлений в ваших триггерах.

0 голосов
/ 15 февраля 2012

Решение: используйте BEFORE UPDATE TRIGGER вместо AFTER UPDATE TRIGGER

CREATE TRIGGER some_trigger BEFORE UPDATE ... etc
...