Oracle 原理:DML触发器和数据库触发器

一、DML触发器

触发器的作用即当某个事件发生时会自动执行执行程序段里的内容。

触发器可以作用于表或者视图,可以指定在insert 或update 或delete  操作前、操作时、操作后 执行特定的程序段。

CREATE [OR REPLACE] TRIGGER triggername 
  BEFORE/INSTEAD OF/AFTER           ---选择事件触发(前,时,后)执行 PL/SQL代码块
  [INSERT [OR] UPDATE [OR] DELETE]  ---当执行 插入 、更新、删除前触发
  ON tblname_or_viewname            ---确认作用的表或者视图
  [Referencing {OLD [AS] old / NEW [AS] new }] 
  [FOR EACH ROW]           --指定行级触发器,不指定就是表级触发器
  [WHEN (condition)]       --当符合condition的条件满足时触发
DECLARE
  -- local variables here
BEGIN
  ;--PL/SQL block

END triggername ;

在sqlserver 中 Deleted 是一张临时表存即将被更新删除的老信息,对应Oracle 中的 :old  ,Inserted 是一张临时表用来存即将插入更新的新信息,对应Oracle 中的 :new。 :new 和:old 表示即将操作的一行数据而不是代表整个数据集,所以,在用这两个的时候通常要加上[FOR EACH ROW] 来指明行触发器。 其中 对于update的操作实际上是先把数据放入:old再删除再把新数据放入:new插入到数据库中。

由于:old是存的是老数据是即将被删除或更改的,所以更新old没意义。after 已经完成的操作后再触发,所以此时对新数据new进行操作是无意义的。当为after时,无法修改     :new的记录。

对于多表视图,是可以改变键保留表中的内容的。也可以对单表视图j进行DML操作

表级触发器在当对表或视图事件触发时,只执行1次。而行级触发器在对表或视图事件触发时,每影响1行数据就会执行1次程序块内容

在DML触发器中 不能使用rollback ,commit 还有DDL语句。

新建练习表 department_tbl:

新建如下触发器,比较效果

create view VW_department_tbl as select * from department_tbl;
--------insert视图VW_department_tbl时,给每行数据Leaders 默认值'BOSS'----
create or replace trigger departInsertDefault2
  Instead of insert   --替换原有的insert语句,且Instead Of 只能作用于视图, WHEN不能用于 INSTEAD OF
  on VW_department_tbl
  FOR EACH ROW
declare
begin
  if  :new.leaders is null then
    insert into department_tbl values(:new.department,:new.all_salary,'BOSS');
  else 
     insert into department_tbl values(:new.department,:new.all_salary,:new.leaders);
  end if;
end departInsertDefault2 ;
drop trigger departInsertDefault2;
-----------------------------------
--------insert表department_tbl时,给每行数据Leaders 默认值'BOSS'----
create or replace trigger departInsertDefault1
  before insert 
  on department_tbl 
  FOR EACH ROW
  WHEN (new.leaders is null
)declare
  
begin 
  :new.leaders :='BOSS';
end departInsertDefault1 ;
drop trigger departInsertDefault1;

对触发器2执行

对触发器1执行

新建触发器3,

create or replace procedure dep_insert(dep in department_tbl.department%type ,sal in department_tbl.all_salary%type) 
is  PRAGMA AUTONOMOUS_TRANSACTION;  --自主事物处理
begin
 insert into department_tbl values(dep,sal,'BOSS');
  --update department_tbl set leaders='BOSS' where leaders is null and department = dep;  --取不到还未提交的数据
commit;
end dep_insert;
/
create or replace trigger departInsertDefault3
  after insert        --after 无法修改基表的数据,需要自主事物处理的存储过程配合,且新数据属于未提交状态
  on department_tbl
  FOR EACH ROW
  WHEN (new.leaders is null)
  
declare
  v_data department_tbl%rowtype;
begin  
 --update department_tbl set leaders='BOSS' where leaders is null and department = :new.department;  --无法执行
  dep_insert( :new.department,:new.all_salary);
  
end departInsertDefault3 ;
drop trigger departInsertDefault3;

执行

总之,如果要修改数据建议用 before  ,after适用于数据校验,而Instead of只能作用于视图。

update 示例:

create or replace trigger departInsertDefault4
  before update        
  on department_tbl
  FOR EACH ROW
  when (old.department = new.department)
declare
begin  
    :new.all_salary := :new.all_salary+:old.all_salary;
end departInsertDefault4 ;
/
--drop trigger departInsertDefault4;

truncate table department_tbl;
insert into department_tbl(department,all_salary) values('部门1',2000);
insert into department_tbl(department,all_salary,leaders) values('部门1',2000,'BOSS');
insert into department_tbl(department,all_salary,leaders) values('部门2',3000,'雇佣者1');
update department_tbl set department = '部门999' where Leaders is not null;
update department_tbl set Leaders = 'boss' where Leaders is not null;
commit;
select * from department_tbl;

最后执行结果:

二、模式(DDL)触发器


Create table obj_tbl(
obj_name varchar2(30),
obj_type varchar2(20),
obj_date Date
)

create or replace trigger obj_trigger 
 after Create --alter drop
on SCHEMA
BEGIN
  insert into  obj_tbl values( ora_dict_obj_name,ora_dict_obj_type,SYSDATE);
END;
/

ora_client_ip_address 用于返回客户端的IP地址
ora_database_name 用于返回当前数据库名
ora_des_encrypted_password 用于返回DES加密后的用户口令
ora_dict_obj_name 用于返回DDL操作所对应的数据库对象名
ora_dict_obj_name_list(name_list_ OUT ora_name_list_t) 用于返回字事件中被修改的对象名列表
ora_dict_obj_owner 用于返回DDL操作所对应的对象的所有者名。
ora_dict_obj_ower_list(ower_list OUT ora_name_list_t) 用于返回在事件中被修改对象的所有者列表
ora_dict_obj_type 用于返回DDL操作所对应的数据库对象的类型。
ora_grantee(user_list OUT ora_name_list_t) 用于返回授权时事件授权者。
ora_instance_num 用于返回历程号。
ora_is_alter_column(column_name IN VARCHAR2) 用于检测特定列是否被修改
ora_is_creating_nested_table 用于检测是否正在建立嵌套表
ora_is_drop_column(column_name IN VARCHAR2) 用于检测特定列是否被删除
ora_is_servererror(error_number) 用于检测是否返回了特定Oracle错误。
ora_login_user 用于返回登录用户名
ora_sysevent  用于返回触发 触发器的系统时间名。

三、数据库级触发器

----数据库启动触发器-----
create or replace trigger db_trigger 
after startup on database
begin 
  insert into  obj_tbl values( ora_sysevent,null,SYSDATE);
end;
/
----数据库用户登录触发器-----
create or replace trigger user_trigger 
after logon on database
begin 
  insert into  obj_tbl values( ora_login_user,ora_client_ip_address,SYSDATE);
end;
/ 

四、对触发器的操作

alter tigger    tiggername   ENABLE/DISABLE    打开关闭触发器 

select * from dba_triggers/user_triggers   查询触发器信息

猜你喜欢

转载自blog.csdn.net/superSmart_Dong/article/details/107093957