firebird - 插入或更新触发器后

时间:2012-02-15 02:32:26

标签: sql stored-procedures triggers firebird

我的数据库计算需要在更新触发器后更新“table1”的“field1”。

更新该字段会导致更新后触发器触发并执行冗长的过程并显示错误。

请告知如何在执行“更新后”触发器后更新“field1”,而不再使“更新后”触发器再次执行。

我知道我不能在After触发器上使用NEW。

由于

4 个答案:

答案 0 :(得分:6)

可以使用基于上下文变量的自定义锁定机制,防止重复调用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

答案 1 :(得分:0)

显而易见的答案是切换到BEFORE UPDATE触发器,如J Cooper所指出的......但是,如果有某种原因你必须使用AFTER UPDATE那么你必须设置一个标志,告诉该字段需要重新计算并在触发器中检查它。一种方法是在NULL触发器中将字段设置为BEFORE,然后在AFTER触发器中检查NULL,即

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检查来避免触发器中的无效更新。

答案 2 :(得分:0)

简单的解决方案......

如果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

答案 3 :(得分:-1)

解决方案:使用BEFORE UPDATE TRIGGER代替AFTER UPDATE TRIGGER

CREATE TRIGGER some_trigger BEFORE UPDATE ... etc