欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

oracle创建和使用触发器

程序员文章站 2024-01-23 09:30:46
触发器:类似于AOP(面向切面编程)中的拦截器;不能传递参数,输出参数,也不能显示调用,只有满足触发器条件时会由Oracle自动调用。 触发器分类: 语句级触发器;DML操作...
触发器:类似于AOP(面向切面编程)中的拦截器;不能传递参数,输出参数,也不能显示调用,只有满足触发器条件时会由Oracle自动调用。
触发器分类:
语句级触发器;DML操作 insert delete update select
行级触发器;
系统事件触发器;数据库的关闭 启动

用户事件触发器;DDL操作 drop alter create

 

--创建员工表t_employee
create table t_employee(
       employee_id number not null primary key,
       employee_name varchar2(20),
       work_year number,
       status varchar2(10)
);

select * from t_employee;
--t_employee插入多条记录
insert all
  into t_employee(employee_id,employee_name,work_year,status) values(1,'金瑞',5,'ACT')
  into t_employee(employee_id,employee_name,work_year,status) values(2,'钟君',5,'ACT')
  into t_employee(employee_id,employee_name,work_year,status) values(3,'王山',5,'ACT')
  into t_employee(employee_id,employee_name,work_year,status) values(4,'刘迪',4,'ACT')
  into t_employee(employee_id,employee_name,work_year,status) values(5,'钟会',3,'ACT')
  into t_employee(employee_id,employee_name,work_year,status) values(6,'张玉',3,'ACT')
  into t_employee(employee_id,employee_name,work_year,status) values(7,'柳青',3,'ACT')
  into t_employee(employee_id,employee_name,work_year,status) values(8,'胡东',3,'ACT')
  into t_employee(employee_id,employee_name,work_year,status) values(9,'商乾',3,'ACT')
  into t_employee(employee_id,employee_name,work_year,status) values(10,'王蒙',1,'ACT')
select * from dual;
--创建工资表t_salary
create table t_salary(
       salary_id number not null primary key,
       employee_id number,
       month varchar2(10),
       salary number
);
select * from t_salary;

--t_salary插入多条记录
insert all
  into t_salary(salary_id,employee_id,month,salary) values(1,1,'1月',8000)
  into t_salary(salary_id,employee_id,month,salary) values(2,2,'1月',7000)
  into t_salary(salary_id,employee_id,month,salary) values(3,3,'1月',7000)
  into t_salary(salary_id,employee_id,month,salary) values(4,4,'1月',7000)
  into t_salary(salary_id,employee_id,month,salary) values(5,5,'1月',6000)
  into t_salary(salary_id,employee_id,month,salary) values(6,6,'1月',5500)
  into t_salary(salary_id,employee_id,month,salary) values(7,7,'1月',5000)
  into t_salary(salary_id,employee_id,month,salary) values(8,8,'1月',4000)
  into t_salary(salary_id,employee_id,month,salary) values(9,9,'1月',4000)
  into t_salary(salary_id,employee_id,month,salary) values(10,10,'1月',3000)
  into t_salary(salary_id,employee_id,month,salary) values(11,1,'2月',8000)
  into t_salary(salary_id,employee_id,month,salary) values(12,2,'2月',7000)
  into t_salary(salary_id,employee_id,month,salary) values(13,3,'2月',7000)
  into t_salary(salary_id,employee_id,month,salary) values(14,4,'2月',7000)
  into t_salary(salary_id,employee_id,month,salary) values(15,5,'2月',6000)
  into t_salary(salary_id,employee_id,month,salary) values(16,6,'2月',5500)
  into t_salary(salary_id,employee_id,month,salary) values(17,7,'2月',5000)
  into t_salary(salary_id,employee_id,month,salary) values(18,8,'2月',4000)
  into t_salary(salary_id,employee_id,month,salary) values(19,9,'2月',4000)
  into t_salary(salary_id,employee_id,month,salary) values(20,10,'2月',3000)
  into t_salary(salary_id,employee_id,month,salary) values(21,1,'3月',8000)
  into t_salary(salary_id,employee_id,month,salary) values(22,2,'3月',7000)
  into t_salary(salary_id,employee_id,month,salary) values(23,3,'3月',7000)
  into t_salary(salary_id,employee_id,month,salary) values(24,4,'3月',7000)
  into t_salary(salary_id,employee_id,month,salary) values(25,5,'3月',6000)
  into t_salary(salary_id,employee_id,month,salary) values(26,6,'3月',5500)
  into t_salary(salary_id,employee_id,month,salary) values(27,7,'3月',5000)
  into t_salary(salary_id,employee_id,month,salary) values(28,8,'3月',4000)
  into t_salary(salary_id,employee_id,month,salary) values(29,9,'3月',4000)
  into t_salary(salary_id,employee_id,month,salary) values(30,10,'3月',3000)
select * from dual;

【1】为单个事件定义触发器

--创建触发器:为了防止员工表中插入新数据work_year被改动,创建触发器在插入新数据时使得work_year默认0
create or replace trigger tr_before_insert_employee
  before insert
  on t_employee
  for each row
    begin
      :new.work_year:=0;
    end;
--查看创建的触发器信息
select * from user_objects where object_type='TRIGGER' and object_name='TR_BEFORE_INSERT_EMPLOYEE';    
--测试触发器tr_before_insert_employee
insert into t_employee(employee_id,employee_name,work_year,status) values(11,'张静',5,'ACT');
--结果
SQL> insert into t_employee(employee_id,employee_name,work_year,status) values(11,'张静',5,'ACT');
1 row inserted

SQL> select * from t_employee where employee_id=11;
EMPLOYEE_ID EMPLOYEE_NAME    WORK_YEAR STATUS
----------- --------------- ---------- ----------
         11 张静                  0      ACT
--演示:new只能用于行级触发器
create or replace trigger tr_before_insert_employee
  before insert
  on t_employee
  --for each row
    begin
      :new.work_year:=0;
    end;    
--报错信息
ORA-04082: NEW 或 OLD 引用不允许在表级触发器中
--演示利用表级触发器限制用户操作
create or replace trigger tr_before_insert_employee
  before insert
  on t_employee
    begin
      if user!='ADMIN' then
            raise_application_error('-20001','权限不足','不能向表中插入数据');
      end if;
    end;  
drop trigger tr_before_insert_employee;
--测试限制触发器,以下DML操作会报错
insert into t_employee(employee_id,employee_name,work_year,status) values(11,'张静',5,'ACT');

【2】为多个事件定义触发器

--演示为多个事件创建触发器:将insert or update的status字段改为大写形式
create or replace trigger tr_insert_update_employee
  before insert or update
  on t_employee
  for each row
    begin
      :new.status:=upper(:new.status);
    end;
    
--测试上述触发器
insert into t_employee(employee_id,employee_name,work_year,status) values(11,'张静',5,'act');
--结果
EMPLOYEE_ID EMPLOYEE_NAME         WORK_YEAR STATUS
----------- -------------------- ---------- ----------
         11 张静                          0 ACT
update t_employee set status='act' where employee_id=11;
--结果
EMPLOYEE_ID EMPLOYEE_NAME         WORK_YEAR STATUS
----------- -------------------- ---------- ----------
         11 张静                          0 XXX

【3】为单个事件多个触发器

按照触发器的创建时间,同一事件按序触发不同的触发器

前边创建的触发器:
tr_before_insert_employee限制工龄为0
tr_insert_update_employee限制status的字母为大写

--测试多个触发器 如果触发器触发成功会将下面的work_year改为0,status改为大写ACT
insert into t_employee(employee_id,employee_name,work_year,status) values(12,'王静',5,'act');
--结果:符合预期值
EMPLOYEE_ID EMPLOYEE_NAME         WORK_YEAR STATUS
----------- -------------------- ---------- ----------
         12 王静                          0 ACT
         
【4】创建触发器通过条件进行触发

--先删除之前的触发器
select * from user_objects where object_type='TRIGGER';
drop trigger TR_INSERT_UPDATE_EMPLOYEE;
drop trigger TR_BEFORE_INSERT_EMPLOYEE;
--创建触发器,注意:old和new在触发器的描述语句中使用,:old和:new在触发器的操作语句中使用
--如果work_year大于0,则把status的值改为ACT
create or replace trigger tr_update_employee
  before update
  on t_employee
  for each row
    when (old.status='CXF' and old.work_year>0)
    begin
      :new.status:='ACF';
    end;
--测试触发器
update t_employee set employee_id=employee_id;--不会更改表内容,但会触发触发器
--结果
EMPLOYEE_ID EMPLOYEE_NAME         WORK_YEAR STATUS
----------- -------------------- ---------- ----------
          1 金瑞                          5 ACT
          2 钟君                          5 ACT
          3 王山                          5 ACT
          4 刘迪                          4 ACT
          5 钟会                          3 ACF
          6 张玉                          3 ACF
          7 柳青                          3 ACF
          8 胡东                          3 ACF
          9 商乾                          3 ACT
         10 王蒙                          1 ACT
         12 王静                          0 ACT