11.2.5 复合类型触发器
复合类型的触发器是Oracle 11g的新特性,属于触发器的增强部分。复合类型的触发器相当于在一个触发器中包含了4种不同类型的触发器,分别是语句之前(before statement)、行之前(before row)、行之后(after row)、语句之后(after statement)。这么做可以很轻松地把变量在各状态之间传递,而在该类型触发器出现之前,变量在触发器之间的传递比较麻烦。
利用该类型的触发器还可以方便地解决ORA-04091错误,这里涉及一个变异表的概念,读者可以理解变异表是正在被DML操作修改的表,也是触发器的作用表。而触发器通常不能对变异表进行操作,下面一个示例将利用复合类型的触发器,解决ORA-04091错误。
【示例10】复合型触发器
该触发器试图实现功能:当为PRODUCTINFO表中的数据提高价格时,触发器判断新旧价格差是否高于价格在2000以下的所有产品价格的平均值的20%,如果高于此值,则提示数据有问题。相关步骤如下:
1)创建普通类型的触发器,并激发,查看是否存在ORA-04091错误。具体脚本如下:
01 CREATE TRIGGER PRIC_TGR
02 AFTER UPDATE ON PRODUCTINFO
03 FOR EACH ROW
04 DECLARE
05 V_PRO_AVG NUMBER(10,2):=0.0;
06 BEGIN
07 SELECT AVG(PRODUCTPRICE)
08 INTO V_PRO_AVG
09 FROM PRODUCTINFO
10 WHERE PRODUCTINFO.PRODUCTPRICE<2000;
11
12 IF:NEW.PRODUCTPRICE-:OLD.PRODUCTPRICE>V_PRO_AVG*0.20 THEN
13 RAISE_APPLICATION_ERROR(-20001,'数据修改错误!');
14 END IF;
15 END;
【代码解析】
❑第1~3行表示创建作用于表PRODUCT INFO上的修改后的行级触发器,名为PRIC_TGR。
❑第7~10行表示求取价格在2000以下的产品的平均价格,并存入变量V_PRO_AVG中,这种SELECT INTO形式的语句会把触发表作为变异表。
❑第12~14行判断新增价格如果高于平均价格的20%,则提示出错。
【验证触发器】
该触发器创建完成后,执行如下语句:
UPDATE PRODUCTINFO
SET PRODUCTPRICE=PRODUCTPRICE+300
WHERE PRODUCTPRICE>2000;
执行效果见图11.12。
图 11.12 修改表出现ORA-04091错误
2)创建复合类型的触发器,解决上一步出现的错误。具体脚本如下:
01 CREATE OR REPLACE TRIGGER COMPOUND_TGR
02 FOR UPDATE ON PRODUCTINFO COMPOUND TRIGGER
03
04 V_PRO_AVG NUMBER(10,2):=0.0;
05
06 BEFORE STATEMENT IS
07 BEGIN
08 SELECT AVG(PRODUCTPRICE)
09 INTO V_PRO_AVG
10 FROM PRODUCTINFO
11 WHERE PRODUCTINFO.PRODUCTPRICE<2000;
12 END BEFORE STATEMENT;
13
14 AFTER EACH ROW IS
15 BEGIN
16 IF:NEW.PRODUCTPRICE-:OLD.PRODUCTPRICE>V_PRO_AVG*0.20 THEN
17 RAISE_APPLICATION_ERROR(-20011,'数据修改错误!');
18 END IF;
19 END AFTER EACH ROW;
20 END;
21 /
【代码解析】
❑第1~2行表示创建复合类型的触发器,触发事件为UPDATE操作。
❑第4行表示声明变量,存放平均价格。
❑第6~12行表示前语句触发的脚本。此时的操作相当于前语句触发器的操作。
❑第14~19行表示后行级的触发。也就是说,它的执行次数和修改的记录数一致。
【验证触发器】
该触发器创建完成后,执行如下语句:
UPDATE PRODUCTINFO
SET PRODUCTPRICE=PRODUCTPRICE+300
WHERE PRODUCTPRICE>2000;
执行效果见图11.13。
图 11.13 复合触发器验证结果
从图11.13中可以看出该触发器已经正常激发,避免了普通触发器出现的ORA-04091错误。以后读者就可以不用费神地解决此类错误了。