技术开发 频道

ORACLE PL/SQL编程之八:把触发器说透

  8.2.3 创建替代(INSTEAD OF)触发器

  创建触发器的一般语法是:

CREATE [OR REPLACE] TRIGGER trigger_name

  INSTEAD OF

  {INSERT | DELETE | UPDATE [OF column [, column …]]}

  [
OR {INSERT | DELETE | UPDATE [OF column [, column …]]}...]

  
ON [schema.] view_name --只能定义在视图上

  [REFERENCING {OLD [
AS] old | NEW [AS] new| PARENT as parent}]

  [
FOR EACH ROW ] --因为INSTEAD OF触发器只能在行级上触发,所以没有必要指定

  [WHEN condition]

  PL
/SQL_block | CALL procedure_name;


  其中:

  INSTEAD OF 选项使ORACLE激活触发器,而不执行触发事件。只能对视图和对象视图建立INSTEAD OF触发器,而不能对表、模式和数据库建立INSTEAD OF 触发器。

  FOR EACH ROW选项说明触发器为行触发器。行触发器和语句触发器的区别表现在:行触发器要求当一个DML语句操走影响数据库中的多行数据时,对于其中的每个数据行,只要它们符合触发约束条件,均激活一次触发器;而语句触发器将整个语句操作作为触发事件,当它符合约束条件时,激活一次触发器。当省略FOR EACH ROW 选项时,BEFORE 和AFTER 触发器为语句触发器,而INSTEAD OF 触发器则为行触发器。

  REFERENCING 子句说明相关名称,在行触发器的PL/SQL块和WHEN 子句中可以使用相关名称参照当前的新、旧列值,默认的相关名称分别为OLD和NEW。触发器的PL/SQL块中应用相关名称时,必须在它们之前加冒号(:),但在WHEN子句中则不能加冒号。

  WHEN 子句说明触发约束条件。Condition 为一个逻辑表达时,其中必须包含相关名称,而不能包含查询语句,也不能调用PL/SQL 函数。WHEN 子句指定的触发约束条件只能用在BEFORE 和AFTER 行触发器中,不能用在INSTEAD OF 行触发器和其它类型的触发器中。

  INSTEAD_OF 用于对视图的DML触发,由于视图有可能是由多个表进行联结(join)而成,因而并非是所有的联结都是可更新的。但可以按照所需的方式执行更新,例如下面情况:

  例1:

CREATE OR REPLACE VIEW emp_view AS

  
SELECT deptno, count(*) total_employeer, sum(sal) total_salary

  FROM emp GROUP BY deptno;

  在此视图中直接删除是非法:

SQL>DELETE FROM emp_view WHERE deptno=10;

  DELETE FROM emp_view WHERE deptno
=10

  ERROR 位于第 1 行:

  ORA-01732: 此视图的数据操纵操作非法

  但是我们可以创建INSTEAD_OF触发器来为 DELETE 操作执行所需的处理,即删除EMP表中所有基准行:

CREATE OR REPLACE TRIGGER emp_view_delete

  INSTEAD OF DELETE
ON emp_view FOR EACH ROW

  BEGIN

  DELETE FROM emp WHERE deptno
= :old.deptno;

  
END emp_view_delete;

  DELETE FROM emp_view WHERE deptno
=10;

  DROP TRIGGER emp_view_delete;

  DROP VIEW emp_view;

  例2:创建复杂视图,针对INSERT操作创建INSTEAD OF触发器,向复杂视图插入数据。

   创建视图:

CREATE OR REPLACE FORCE VIEW "HR"."V_REG_COU" ("R_ID", "R_NAME", "C_ID", "C_NAME")
AS
SELECT r.region_id,
r.region_name,
c.country_id,
c.country_name
FROM regions r,
countries c
WHERE r.region_id
= c.region_id;

    创建触发器:

CREATE OR REPLACE TRIGGER "HR"."TR_I_O_REG_COU" INSTEAD OF

  INSERT
ON v_reg_cou FOR EACH ROW DECLARE v_count NUMBER;

  BEGIN

  
SELECT COUNT(*) INTO v_count FROM regions WHERE region_id = :new.r_id;

  
IF v_count = 0 THEN

  INSERT INTO regions

  (region_id, region_name

  ) VALUES

  (:
new.r_id, :new.r_name

  );

  
END IF;

  
SELECT COUNT(*) INTO v_count FROM countries WHERE country_id = :new.c_id;

  
IF v_count = 0 THEN

  INSERT

  INTO countries

  (

  country_id,

  country_name,

  region_id

  )

  VALUES

  (

  :
new.c_id,

  :
new.c_name,

  :
new.r_id

  );

  
END IF;

  
END;


  创建INSTEAD OF触发器需要注意以下几点:

  只能被创建在视图上,并且该视图没有指定WITH CHECK OPTION选项。

  不能指定BEFORE 或 AFTER选项。

  FOR EACH ROW子可是可选的,即INSTEAD OF触发器只能在行级上触发、或只能是行级触发器,没有必要指定。

  没有必要在针对一个表的视图上创建INSTEAD OF触发器,只要创建DML触发器就可以了。

0
相关文章