Oracle数据库之PLSQL触发器

--=======触发器============
--是一段命名的PL/SQL代码块,只不过该代码块在特定的条件下被触发并且执行。
--对于这样的代码我们称之为触发器

--======触发器的分类=============
--通常根据触发条件以及触发级别的不同分为DML触发器,INSTEAD OF 触发器,系统事件触发器。
---DML触发器: ORACLE 对DML语句进行触发,
		--可以在DML操作前或操作后进行触发,并且可以对每个行或语句操作上进行触发。
		
---INSTEAD OF 触发器 :在ORACLE里,对于简单视图,可以直接使用DML进行操作,
		--而复杂视图则不能直接使用DML,因此INSTEAD OF 触发器应运而生。
		--INSTEAD OF 触发器主要是为解决复杂视图不能执行DML而创建。
		
---系统事件触发器  
		--在 ORACLE 数据库系统的事件中进行触发,如ORACLE系统的启动与关闭等.
		--使用系统触发器,便于系统跟踪,监测数据库变化情况等。

--============触发器的用途=========
		--控制DDL语句的行为,如通过更改、创建或重命名对象 
		--控制DML语句的行为,如插入、更新和删除 
		--实施参照完整性、复杂业务规则和安全性策略 
		--在修改视图中的数据时控制和重定向DML语句 
		--通过创建透明日志来审核系统访问和行为的信息
		
--=======DML语句触发器==================
--组成部分		描述				可能值
--触发时间		触发事件的时间顺序		before,after
--触发事件		DML语句是触发事件		insert,update,delete
--触发器类型		触发器被执行的次数		statement,row
--触发器体		该触发器将要执行的动作	        完整的PLSQL块

--======DML触发器的类型===========
--语句级触发器
--行级触发器 (for each row) 
--区别:触发的次数不同,如果DML语句影响1行,那么两种效果一样
--		如果影响多行,行级触发次数比语句级触发次数多.

--=========DML触发器的触发顺序===============

--在单行数据上的触发顺序(触发代码仅被执行一次)
---BEFORE 语句级触发器
------BEFORE 行级触发器
------AFTER 行级触发器
-- AFTER 语句级触发器

--.在多行数据上的触发顺序(语句级触发器仅被执行一次,行级触发器在每个作业行上被执行一次)
--BEFORE 语句级触发器
------BEFORE 行级触发器
------AFTER 行级触发器
----------BEFORE 行级触发器
----------AFTER 行级触发器
--AFTER 语句级触发器

--==创建触发器的语法

        CREATE [OR REPLACE] TRIGGER trigger_name
        {BEFORE | AFTER | INSTEAD OF}     
--定义触发类型,即那一种或多种DML以及特定的列
        {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] --满足条件才会触发

        BEGIN

            trigger_body;

        END;
	
--=====在行级触发器中使用被插入、更新或删除的记录中的列值,(只能用在行级触发)
---可以使用NEW和OLD限定符来表示
--- :old 修饰符访问操作完成前列的值
--- :new 修饰符访问操作完成后列的值
---============================================
--触发事件	 :old.id						:new.id
--insert 		:old.id结果 为null			数据库会把  的值的值插入id列 
--update		在update之前的值				update之后的新值
--delete		delete之前的原始值			字段null

--需求:完成sequence的调用( 自动生成主键)
--准备表:
create table t1 (id number(4) ,c1 number(4));
create sequence s;--创建系列s
create or replace trigger  get_pk
--在insert , t1表之前触发
	before insert  on t1 	for each row  --每一行都被触发
declare
begin
-- :new是个记录类型的变量,结构类似于表结构,每条新插入的记录存储在其中。
--定义行级的before insert触发器,在插入记录之前,改变:new里的值,从而实现自动产生主键值。
	select s.nextval into :new.id from dual;
	dbms_output.put_line(':new.id'|| :new.id);-- 1,2,3,4,
	dbms_output.put_line(' :old.id'|| :old.id); -- 没有
end;

--执行 会触发 get_pk触发器.
insert into t1 values (100,100);
insert into t1 values (100,200);
insert into t1 values (100,300);

--再次查询:select * from t1 ;
-- id  c1
-- 1  100
-- 2  200
-- 3  300

--==== update :new , :old测试
create or replace trigger up_pk
	before update on t1 for each row
declare
begin
		dbms_output.put_line('update :new .c1'|| :new.c1);--400 
		dbms_output.put_line('update :old.c1'|| :old.c1); -- 300
end;
-- update:触发up_pk触发器
	update t1 set c1 = 400 where id = 3;
-- :new.c1 400 ,   :old.c1 300

--==== 测试delete
create or replace trigger de_pk
	before delete on t1 for each row
declare
begin
	dbms_output.put_line('delete :new .c1'|| :new.c1);--没有
	dbms_output.put_line('delete :old.c1'|| :old.c1);--400
end;
-- delete:触发de_pk触发器
	delete from  t1  where id = 3;
-- :new.c1 没有 ,   :old.c1 400


--=========跟记录更新t1表的时间. 
-- c2存放修改前的值, c3存储修改后的值
create table t_log (c1 varchar2(30),c2 number(4),c3 number(4) , c4 date);

--在t1表上创建触发器
-- for each row : update一行就触发1次.update 2行就触发2次
create or replace trigger update_log
	before update on t1 for each row
	-- before update on t1 这里有错, :old.c1, :new.c1不能用在表级触发器
declare
begin
	insert into t_log values (' Before update on t1 ',:old.c1, :new.c1 , sysdate);
end;


-- 测试 ,行级 ,表级触发的区别
create table t_log (c1 varchar2(30),c4 date);

--在t1表上创建触发器
-- update 1行触发1次,update 2行 也是触发1次
create or replace trigger update_log
	-- before update on t1 for each row
	before update on t1 
declare
begin
	insert into t_log values (' Before update on t1', sysdate);
end;

--== when限制条件的行级触发器
create or replace trigger update_log
	before update on t1 for each row
	when ( old.id = 1) -- 当满足这个条件的时候触发
declare
begin
	insert into t_log values (' Before update on t1', sysdate);
end;

-- == of的使用
create or replace trigger update_log
	before update on t1 of id  for each row --表示当id 被update时 才会被触发
	when ( old.id = 1) -- 当满足这个条件的时候触发
declare
begin
	insert into t_log values (' Before update on t1', sysdate);
end;


-- ==对于复杂的数据完整性,参照完整性,可以通过DML触发器来完成普通约束所不能完成的任务
-- 级联更新
CREATE OR REPLACE TRIGGER update_cascade
    AFTER DELETE OR UPDATE 
		OF deptno ON dept FOR EACH ROW
BEGIN
	-- updaing :修改了返回true ,否则 false 
	--	:old.deptno<>:new.deptno :修改前的值 不等于 修改后的值		
	IF (UPDATING AND :old.deptno<>:new.deptno) THEN
			UPDATE emp SET deptno=:new.deptno WHERE deptno=:old.deptno;

     END IF;
	
	-- deleting :删除true ,否false;
     IF DELETING THEN
        DELETE FROM emp WHERE deptno=:old.deptno;
     END IF;
END;

--查看触发器 名字,状态
select trigger_name,status from user_triggers where table_name='UPDATE_CASCADE';

--查看触发器源码
select line,text from user_source where name='TR_DEL_UPD_DEPTNO';

--禁用触发器
--当触发器被禁用后,则表上的DML操作将不会触发该触发器,
--直到该触发器被解除禁用(alter trigger trigger_name disable)
alter trigger tr_emp_sal disable;

--启用触发器
    -- 被禁用的触发器可以被解除禁用(alter trigger trigger_name enable)
 alter trigger tr_emp_sal enable;

-- 禁用、启用表上的所有触发器
 alter table emp disable all triggers;
 alter table emp enable all triggers;
 
--重新编译触发器
alter trigger tr_emp_sal compile;

-- 删除触发器
 drop trigger tr_emp_sal;

猜你喜欢

转载自whatisjavabean.iteye.com/blog/2005807