限定值与非限定值的比较
下面的表总结了在发生不同触发器事件后用 old 或 new 相关名限定 column 名称时,检索的值。
触发事件 | old.column | new.column |
INSERT | 无值(错误) | 插入的值 |
UPDATE (column updated) | 初始值 | 当前值(U) |
UPDATE (column not updated) | 初始值 | 当前值(N) |
DELETE | 初始值 | 无值(错误) |
SELECT | 初始值 | 无值(错误) |
当相关性名称没有值是,只要 SQL 或 SPL 语句引用未定义的相关名称执行时而不是在声明相关性名称时,会发出错误,当您读取上一个表时引用以下键。
术语 含义
初始值 触发事件前的值
当前值 触发事件后的值
(N) 不能被触发操作更改
(U) 可以被触发语句更新;更新的值可能因为前面的触发操作而与初始值不同。
在 FOR EACH ROW 触发操作列表外,您不能使用旧的或新的相关名限定来自触发表的列;它总是引用数据库中的当前值。
创建触发器时,触发操作列表中的语句使用任何有效的排列顺序,即使执行触发器操作时有效的排列不同。请参阅 SET COLLATION 语句 以获取关于如何指定与 DB_LOCALE 所指定的不同的排列顺序。
触发器的再进入
在某些情况下触发器可以是再进入的。在这些情况中,触发操作可以引用触发表。换句话说,触发事件和触发操作都在同一个表上操作。下表总结了触发器可以是再进入的情况和触发器不能是再进入的情况:
- Update 触发器的触发操作不能是触发事件更新的表的 INSERT 或 DELETE 。
- 同样,Update 触发器的触发器操作不能是对触发器事件更新的列的 UPDATE 。(但是 Update 触发器的触发器操作可以更新未由触发器事件更新的列。)
例如,假设以下 UPDATE 语句,更新 tab1 的列 a 和 b ,是触发语句:
UPDATE tab1 SET (a, b) = (a + 1, b + 1);
现在考虑以下示例中的触发操作。第一个 UPDATE 语句可以是有效的触发操作,但是第二个不是,因为它再次更新 b 列。
UPDATE tab1 SET c = c + 1; -- OK
UPDATE tab1 SET b = b + 1; -- INVALID
- 如果触发器具有 UPDATE 事件,则触发操作可以是带有 INTO 语句(引用触发事件更新的列或触发表中的任何其它列)的 EXECUTE PROCEDURE 或 EXECUTE FUNCTION 语句。
当 EXECUTE PROCEDURE 或 EXECUTE FUNCTION 语句是触发操作时 UPDATE 触发器的 INTO 子句仅在 FOR EACH ROW 触发操作中有效,并且出现在 INTO 子句中的列名必须来自触发表。
以下语句说明了 INTO 子句的正确用法:
CREATE TRIGGER upd_totpr UPDATE OF quantity ON items
REFERENCING OLD AS pre_upd NEW AS post_upd
FOR EACH ROW(EXECUTE PROCEDURE
calc_totpr(pre_upd.quantity,post_upd.quantity,
pre_upd.total_price) INTO total_price);
INTO 关键字之后的列必须在触发列表中,但是不需要被触发事件更新。
当 INTO 子句出现在 EXECUTE PROCEDURE 或 EXECUTE FUNCTION 语句中时,当从 UDR 返回值时,数据库服务器立即用该值更新指定的列。
- 如果触发器具有 INSERT 事件,则触发操作不能是引用触发表中的列的 INSERT 或 DELETE 语句。
- 如果触发器具有 INSERT 事件,则触发操作可以是引用触发表中的列的 UPDATE 语句,但是该列不能是触发器事件向其提供值的列。
如果触发器具有 INSERT 事件,并且触发器操作更新触发表,则两个语句中的列必须互斥。例如,假设触发语句为表 tab1 的列 cola 和 colb 插入值:
INSERT INTO tab1 (cola, colb) VALUES (1,10);
现在考虑以下触发操作。第一个 UPDATE 是有效的,但是第二个无效。因为即使触发事件已经为列 colb 提供了值,它仍然更新列 colb :
UPDATE tab1 SET colc=100; --OK
UPDATE tab1 SET colb=100; --INVALID
- 如果触发器具有 INSERT 事件,则触发操作可以是带有 INTO 子句(引用触发事件提供的列或触发事件未提供的列)的 EXECUTE PROCEDURE 或 EXECUTE FUNCTION 语句。
当 EXECUTE PROCEDURE 或 EXECUTE FUNCTION 语句是触发操作时,仅当触发操作出现在 FOR EACH ROW 列表中时,您可以为 INSERT 触发器指定 INTO 子句。在此情况中,INTO 子句只能包含来自触发表的列名称。
以下语句说明了 INTO 子句的有效用法:
CREATE TRIGGER ins_totpr INSERT ON items
REFERENCING NEW AS new_ins
FOR EACH ROW (EXECUTE PROCEDURE calc_totpr
(0, new_ins.quantity, 0) INTO total_price);
INTO 关键字之后的列可以是触发事件提供的触发列表中的列,或是触发事件未提供的触发表中的事件。
当 INTO 子句出现在 EXECUTE PROCEDURE 或 EXECUTE FUNCTION 语句中时,数据库夫服务器立即用从 UDR 返回的值更新指定的列。
- 如果触发操作是 SELECT 语句,则 SELECT 语句可以引用触发表。SELECT 语句可以是以下实例中的触发操作:
- SELECT 语句出现在 WHERE 子句的子查询中或出现在触发操作语句中。
- 触发操作是 UDR ,且 SELECT 语句出现在 UDR 中。
再进入和级联触发器
触发器不能再进入的情况中递归应用于所有的级联触发器。它被认为是初始触发器的一部分。特别地,该规则表示级联触发器不能更新原始触发语句更新的触发表中的任何列,包括该语句影响的任何非触发列。例如,假设此 UPDATE 语句是触发语句:
UPDATE tab1 SET (a, b) = (a + 1, b + 1);
在下一个示例的级联触发器中,trig2 在运行时失败,因为它引用触发 UPDATE 语句更新的列 b :
CREATE TRIGGER trig1 UPDATE OF a ON tab1-- Valid
AFTER (UPDATE tab2 SET e = e + 1);
CREATE TRIGGER trig2 UPDATE OF e ON tab2-- Invalid
AFTER (UPDATE tab1 SET b = b + 1);
现在考虑以下 SQL 语句,当执行最终的 UPDATE 语句时,列 a 被更新且触发器 trig1 被激活。
触发操作再次用 EXECUTE PROCEDURE INTO 语句更新列 a 。
CREATE TABLE temp1 (a INT, b INT, e INT);
INSERT INTO temp1 VALUES (10, 20, 30);
CREATE PROCEDURE proc(val iINT) RETURNING INT,INT;
RETURN val+10, val+20;
END PROCEDURE;
CREATE TRIGGER trig1 UPDATE OF a ON temp1
FOR EACH ROW (EXECUTE PROCEDURE proc(50) INTO a, e);
CREATE TRIGGER trig2 UPDATE OF e ON temp1
FOR EACH ROW (EXECUTE PROCEDURE proc(100) INTO a, e);
UPDATE temp1 SET (a,b) = (40,50);
该级联触发器示例有几个问题。首先,更新列 a 是否会再次激活触发器 trig1 ?答案是否定的。因为触发器已被激活,它没有被再次激活。如果触发操作是 EXECUTE PROCEDURE INTO 或 EXECUTE FUNCTION INTO 语句,只有那些从更新的列到之后(在触发器级联中)在该表中互斥的列上定义的触发器才被激活。其它触发器被忽略。