我的数据库计算需要在更新触发器后更新“table1”的“field1”。
更新该字段会导致更新后触发器触发并执行冗长的过程并显示错误。
请告知如何在执行“更新后”触发器后更新“field1”,而不再使“更新后”触发器再次执行。
我知道我不能在After触发器上使用NEW。
由于
答案 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