oracle触发器学习

触发器

什么是触发器

1.  触发器是在事件发生时隐式地自动运行的PL/SQL程序块,不能接收参数,不能被调用。

2.   触发器必须由事件才能触发。触发器的触发事件分可为3类,分别是DML事件、DDL事件和数据库事件。


触发器的分类


DML触发器

DML触发器是定义在表上的触发器,由DML事件引发。

编写DML触发器的要素是:

l   确定触发的表,即在其上定义触发器的表。

l   确定触发的事件,DML触发器的触发事件有INSERT、UPDATE和DELETE三种。

l   确定触发时间。触发的时间有BEFORE和AFTER两种,分别表示触发动作发生在DML语句执行之前和语句执行之后。

l   确定触发级别,有语句级触发器和行级触发器两种。语句级触发器表示SQL语句只触发一次触发器,行级触发器表示SQL语句影响的每一行都要触发一次。

 

DML触发器的执行顺序:

由于在同一个表上可以定义多个DML触发器,因此触发器本身和引发触发器的SQL语句在执行的顺序上有先后的关系。它们的顺序是:

* 如果存在语句级BEFORE触发器,则先执行一次语句级BEFORE触发器。

* 在SQL语句的执行过程中,如果存在行级BEFORE触发器,则SQL语句在对每一行操作之前,都要先执行一次行级BEFORE触发器,然后才对行进行操作。如果存在行级AFTER触发器,则SQL语句在对每一行操作之后,都要再执行一次行级AFTER触发器。

* 如果存在语句级AFTER触发器,则在SQL语句执行完毕后,要最后执行一次语句级AFTER触发器。

 

DML触发器还有一些具体的问题,说明如下:

* 如果有多个触发器被定义成为相同时间、相同事件触发,且最后定义的触发器是有效的,则最后定义的触发器被触发,其他触发器不执行。

* 一个触发器可由多个不同的DML操作触发。在触发器中,可用INSERTING、DELETING、UPDATING谓词来区别不同的DML操作。这些谓词可以在IF分支条件语句中作为判断条件来使用。

* 在行级触发器中,用:new 和:old(称为伪记录)来访问数据变更前后的值。但要注意,INSERT语句插入一条新记录,所以没有:old记录,而DELETE语句删除掉一条已经存在的记录,所以没有:new记录。UPDATE语句既有:old记录,也有:new记录,分别代表修改前后的记录。引用具体的某一列的值的方法是: :old.字段名或:new.字段名

* 触发器体内禁止使用COMMIT、ROLLBACK、SAVEPOINT语句,也禁止直接或间接地调用含有上述语句的存储过程。


创建DML触发器

语法

CREATE [OR REPLACE] TRIGGER trigger_name
{BEFORE | AFTER | INSTEAD OF }
{INSERT | DELETE | UPDATE [OF column [, column …]]}
[OR {INSERT | DELETE | UPDATE [OF column [, column …]]}...]
ON [schema.]table_name | [schema.]view_name 
[REFERENCING {OLD [AS] old | NEW [AS] new| PARENT as parent}]
[FOR EACH ROW ]
[WHEN condition]
PL/SQL_BLOCK | CALL procedure_name;

l   BEFORE 和AFTER指出触发器的触发时序分别为前触发和后触发方式,前触发是在执行触发事件之前触发当前所创建的触发器,后触发是在执行触发事件之后触发当前所创建的触发器。

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

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

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

l   当一个基表被修改( INSERT, UPDATE, DELETE)时要执行的存储过程,执行时根据其所依附的基表改动而自动触发,因此与应用程序无关,用数据库触发器可以保证数据的一致性和完整性。


练习一、利用触发器,记录所有对Grade表进行的添加,修改,删除历史。

建立历史表,用于记录历史

create table grade_his

(gradeid_before number(6), gradename_beforevarchar2(20),

gradeid_after number(6), gradename_aftervarchar2(20),

operated_type varchar2(20),operated_byvarchar2(20), operated_datedate

)

;

建立触发器,用于记录插入历史

create orreplace trigger trg_insert_grade

after inserton grade

for eachrow

declare

begin

  insert into grade_his(gradeid_after, gradename_after, operated_type,operated_by, operated_date)

  values

  (:new.gradeid,:new.gradename,'插入',sys_context('userenv','SESSION_USER'),sysdate);

End;


建立触发器,用来记录修改历史

create orreplace trigger trg_update_grade

before updateon grade

for eachrow

declare

begin

  insert into grade_his(gradeid_before, gradename_before, gradeid_after, gradename_after, operated_type,operated_by, operated_date)

  values

  (:old.gradeid,:old.gradename,:new.gradeid,:new.gradename,'更新',sys_context('userenv','SESSION_USER'),sysdate);

end;


建立触发器,用来记录删除历史

create orreplace trigger trg_delete_grade

before deleteon grade

for eachrow

declare

begin

  insert into grade_his(gradeid_before, gradename_before,  operated_type,operated_by, operated_date)

  values

  (:old.gradeid,:old.gradename,'删除',sys_context('userenv','SESSION_USER'),sysdate);

end;


一个例子:

要求周六周日不能删除数据

begin
  
if to_char(sysdate,'d')in(6,7) then
  raise_application_error(-20001,'不能删除');--第一次吧application忘了
end if;
end;

测试:

delete from dept where dno = 1001;


另一个自己的例子:

   create or replace trigger trig_trage after insert on tradeinfo
     for each row
     begin
     if :new.transtype='存入' then
      update cardinfo set balance= :new.transmoney+balance where cardid= :new.cardid;--注意表
     else
      update cardinfo set balance = balance-:new.transmoney where cardid = :new.cardid;
     end if;
     end;



     测试:
     insert into tradeinfo values(to_date('2016-02-03','YYYY-MM-DD HH24:mi:ss'),'1001200130014001','支取',100);

触发器多用于关联表的更新,记录等方面。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值