Oracle--触发器

触发器

    特殊的存储过程, 不需要我们手动调用, 当用户触发某一个行为, Oracle自动执行相对于的触发器

触发器的语法: trigger

CREATE [OR REPLACE] TRIGGER 触发器名 触发时间 触发事件
[ON表名/视图名]
[FOR EACH ROW] [when 条件] //加上FOR EACH ROW 即为行级触发器,不加时为语句级触发器
DECLARE
  声明部分
BEGIN
  pl/sql语句
END;

注意:

--  1)  触发时间:即该触发器是在触发事件发生之前(BEFORE)还是之后(AFTER)触发, instead of替换,只用于视图 ,用的很少.
--  2) 触发事件: 某个动作:   可以写多个
--      DML触发: insert, update,delete     ***
--      DDL触发: cretae  alter   drop      ***
--      系统事件: oracle服务系统的启动, 关闭,异常
--      用户事件: 登录, 退出

--  3)触发条件:由WHEN子句指定一个逻辑表达式。只有当该表达式的值为TRUE时,遇到触发事件才会自动执行触发操作。

--  4) 触发频率: FOR EACH ROW: 行级触发, 操作每一行,都触发,  没有加: 语义级触发, 只触发一次

注意: 在oracle规定: 在触发器中不能提交(commit)/回滚(rollback)事务
  原因:oracle把触发器当成后台监控,而我们的commit/rollback是前台监控
  所以你不能用后台来操控前台的操作.

语义级触发器:例:

-- 编写一个针对于emp_back3 进行删除操作的触发器
create  or replace  trigger  trig_deleteEmp after  delete
on emp_back3
declare
begin
   dbms_output.put_line('删除了数据');
end;
  --执行
  --删除
  delete emp_back3 where deptno = 20;

行级触发器:例:

--行级触发器  for each row
create  or replace  trigger  trig_deleteEmp after  delete
on emp_back3
for each row 
declare
begin
   dbms_output.put_line('删除了数据');
end;
drop  trigger trig_deleteEmp;
   --执行
  --删除
  delete emp_back3 where deptno = 20;

触发器的一些操作

  --查看当前用户创建哪些触发器
  select * from user_triggers;
  
  --查看某个触发器的源代码
  select * from user_source where name ='TRIG_EMP2_UPDATE';
  
  --禁用触发器 alter trigger 触发器名 disable
  alter trigger TRIG_EMP2_UPDATE disable;
  
  --启动触发器 alter trigger 触发器名 enable
  alter trigger TRIG_EMP2_UPDATE enable;
  
  --启动某张表中定义所有的触发器
  alter table emp2 enable all triggers;
  --禁用某张表中定义的所有触发器
  alter table emp2 disable all triggers;
  
  --删除触发器
  drop trigger TRIG_EMP2_UPDATE;

触发器的谓词

inserting, deleting, updating
--如果一个触发绑定多个事件,    想知道 触发这个触发器由哪个事件触发
--通过谓词来判断,  
--如果是insert事件触发, inserting谓词的值为true
--如果是delete事件触发, deleting谓词的值为true --如果是update事件触发, updating谓词的值为true

例:

create or replace  trigger  trig1 after insert or delete or update
on emp_back3
declare
begin
  if  inserting  then
  --如果是插入, 打印  insert table
   dbms_output.put_line(' insert table');   -- 调用dbms_output包下的put_line() 存储过程
  elsif deleting then 
  --如果是删除, 打印  delete table
  dbms_output.put_line(' delete table');
  elsif updating then
  --如果是修改, 打印  update table
   dbms_output.put_line(' update table');
  end if;
end;

insert into emp_back3  values(1010,'JIM','ANALYST',7566,sysdate,4500,null,20);

delete from emp_back3 where  empno = 1010;

update emp_back3 set sal = sal + 2;

伪记录

 :new  新的记录,     :old 旧的记录   ***伪记录 只能在行级触发器有效
-- insert操作:  只有  :new 
-- delete操作: 只有  :old
-- update操作:  有:new   :old

例: 加薪, 不能加倒薪,   抛异常(自定义错误异常),  oracle 会捕获的 

create or replace trigger trig2  after  update
on emp_back3
for each row
--when 条件
declare
begin
   if :old.sal > :new.sal   then
      -- 学习oracle提供的一种抛异常的方式:  这个异常会被Oracle进行捕获
      -- 自定义的错误代码:  -20000~-20999
      -- raise_application_error(错误代码, 错误信息); 
      raise_application_error(-20001,'不能加倒薪');
   end if;
end;
-- 执行
begin
  update emp_back3 set sal = sal - 1 where empno = 1001;
  commit;
  exception
     when others then
      dbms_output.put_line('出错了...');
      rollback;
end;

触发器的条件when

/*
在Oracle触发器中,可以使用when关键字来指定触发器触发的条件,条件触发器不仅仅要满足触发事件,而且还有满足触发条件.
    注意:
1.when 只能在行级触发器中使用.
2.when中使用伪记录(new,old)时不需要加:
*/

例:

--只有更新后的工资大于更新前的薪水 ,则打印update add
 create or replace trigger trig_emp
  after update on emp_back3
  for each row
  --更新后的工资大于更新前的薪水,when中伪记录不需要加 :
  when (new.sal >old.sal )
  begin
      dbms_output.put_line('update ok');
  end;
--修改
  update emp_back3 set sal = sal + 1 where empno = 1001;

DDL触发器

-- 语法:
 create [or replace ] trigger 触发器名
   {before/after}
    {create/drop/alter}--触发事件可以多个
 on database --注意此时的触发不再对某张表的数据
 [when 条件]
 declare
      
 begin
              --执行语句
 end

读取DDL事件属性
    sysevent -->事件
    dictionary_obj_type :-->对象类型,如表
    dictionary_obj_name -->对象名称:如表名
    dictionary_obj_owner -->拥有者
    user --> 获取当前登录的用户名

触发器 对数据库所有的用户都有效
  是system用户创建

例:创建一个日志表

 create or replace trigger trig_logRecode after
 create or alter or drop
 on database
 declare
    --创建变量来接收
    v_action varchar2(50);
    v_type varchar2(50);
    v_name varchar2(50);
 begin
     --给变量赋值
     v_action := sysevent;
     v_type := dictionary_obj_type;
     v_name := dictionary_obj_name;
     
     --往 tb_recode 插入数据
     insert into tb_record values(seq_record_id.nextval,user,v_type,v_name ,v_action,default);
     --触发器,自动提交, 不能手动提交
    dbms_output.put_line('日志添加成功!!');
 end;
 
 -- tb_record  在system用户下
 select *  from tb_record;

用户事件:

 -- 用户登录退出日志表
create table userlog (  
             username varchar2(20),   
             logon_time date
); 

--logon登录操作
create or replace trigger database_logon   
  after logon   on database  --登录数据库后触发
  begin  
     insert into userlog    
     values(user,sysdate);   
    -- commit;
  end;  
--执行
select *  from userlog;

 例题:  禁止在非工作时间(工作时间:星期一到星期五的9:00到18:00)往emp表插入数据

create or replace trigger tirg_insertWork after insert
on empcopy
for each row
declare
  week varchar2(10);
  hours number;
begin
  select to_char(sysdate, 'day'),to_char(sysdate, 'hh24') into week,hours from dual;
   if week in('星期六','星期天') or hours not between 9 and 18   then
     raise_application_error(-20001,'禁止在非工作时间插入数据');
   else
     dbms_output.put_line('插入成功!!');
   end if;
end;
-- 执行
declare
begin
insert into empcopy values('1234','james','CLERK','7902',sysdate,'2000',null,10);
  exception
  when others then
  dbms_output.put_line('插入失败,禁止在非工作时间插入数据!!');
end;
View Code
原文地址:https://www.cnblogs.com/64Byte/p/12746358.html