星辰日月00

欲多则心散,心散则志衰,志衰则思不达也!

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

 触发器是存放在数据库中的一种特殊类型的子程序。它不能被用户程序直接调用,
而是当特定事件或操作发生时由系统自动调用执行。触发器主要用于对数据库特定
操作、特定事件的监控和响应。这些特定的事件或操作包括启动数据库、登录数据库、
关闭数据库等系统事件、执行DML和DDL等操作。
一、概念
1.触发器的分类
(1)DML触发器,依据于基本表或简单视图建立的触发器;
(2)instead of触发器,依据于复杂视图建立的触发器;
(3)系统事件触发器,依据系统事件或DDL操作建立的触发器。
2.触发器的简介
 触发器是存放在数据库中的一种特殊类型的子程序。有PL/SQL块构成的触发器,只能包含
select、insert、update和delete等dml语句,不能包含create、alter和drop等DDL语句,以及
commit、rollback和savepoint等事务控制语句。
触发器的组成:
(1)触发事件:引起触发器代码执行的事件。这些事件包括启动和关闭全程、用户登录和断开会话、
oracle错误消息、特定表或视图的dml操作、数据库方案的ddl语句等。可以将上述多个事件用关系运算符or组合。
(2)触发条件:由when子句指定的逻辑表达式。when子句为可选项,若指定when子句,当触发事件发生时,
when条件还必须为true时,触发器代码才能执行。
(3)触发时刻:用于指定触发器代码在触发事件完成之前还是完成之后执行。如果指定为after关键字,
表示触发代码在触发事件完成之前还是完成之后执行。如果指定为before关键字,表示触发事件执行前
执行触发器代码,然后再完成触发事件。
3.触发器示例

create or replace trigger change_teacher
before insert or update or delete on teachers
begin
if (to_char(sysdate, 'HH4') not between '8' and '17') or
(to_char(sysdate, 'dy', 'nls date_langudage = american') in ('sat', 'sun')) then
raise_application_error(-20000, '在非工作时间不能改变教师信息。');
end if;
end change_teacher;

4.触发器的管理
(1)查看已建立触发器的有关信息
 

select * from user_triggers
where trigger_name = 'change_teacher';


(2)查看与修改触发器中的错误

show errors;
edit; --执行edit命令后,自动打开记事本处理文件编辑状态。


(3)禁用触发器是指在触发事件发生时禁止触发器代码执行

--语法格式:
alter trigger trigger_name disable;
alter trigger change_teacher disable; --禁用:disable,启用:enable。


(4)删除触发器

--语法格式:
drop trigger trigger_name;
drop trigger change_teacher;


二、DML触发器
 DML触发器是基于表的触发器,当对某个表进行DML操作时会激活该类触发器。

--语法格式:
create [or replace] trigger trigger_name
before | after trigger_event [of column_name]
on table_name
[for each row]
[when trigger_condition]
begin
trigger_body
end [trigger_name]
--trigger_name,指定定义触发器的名字。
--or replace,在定义触发器时,会先删除同名的触发器后再创建新的触发器,若省略,则需手动删除。
--before|after,指定触发器代码是在触发事件trigger_event之前还是之后执行。
--column_name,指定表table_name中的列名。
--for each row,指定触发器为行触发器,若省略,默认为语句触发器。
--when trigger_condition,指定触发条件。
--trigger_body,是构成触发器pl/sql语句,可以包括定义部分、执行部分和异常处理部分。
--关键字end之后的可行项[trigger_name]给出触发器名字,若指定则可增加程序的可读性。
dml触发器的触发事件trigger_event可以是对表进行insert、update和delete三种操作。

(1)单一触发事件的dml触发器

--建立存放审计数据的表
create table students_grade_change(
student_id number(5),
course_id number(5),
oldScore number(4,1),
newScore number(4,1),
time_change date
)

create or replace trigger s_g_change
after update of score on students_grade
for each row
begin
insert into students_grade_change
value(:old.student_id, :old.course_id, :old.score, :new.score, sysdate);
end s_g_change;


(2)多个触发事件的dml触发器
 在三种操作(insert、updatet和delete)中,指定一种以上的操作作为触发事件,这样的dml
触发器称为多个触发事件的dml触发器。当在触发器中同时包含多种触发事件(insert、update、
和delete),并且需要根据事件的不同进行不同的操作时,则可以在触发器代码中使用3个条件
谓词加以区别。

--条件谓词inserting:当触发器为insert操作时,该条件谓词返回true,否则返回false。
--
updating和deleting的情况类似。
create or replace trigger change_teacher
before insert or update or delete on teachers
begin
if (to_char(sysdate, 'HH24') not between '8' and '17')
or (to_char(sysdate, 'dy', 'nls date_langudage = american') in ('sat', 'sun')) then
case
when inserting then
raise_application_error(
-20001, '在非工作时间不能增加教师信息。');
when updating then
raise_application_error(-20002, '在非工作时间不能修改教师信息。');
when deleting then
raise_application_error(-20003, '在非工作时间不能删除教师信息。');
end case;
end if;
end change_teacher;


三、instead of触发器
 当定义视图时,如果使用了集合操作符( union、union all、minus、intersect)、列 Aggregate 函数、
distinct、group by等子句、多个表的连接操作等,视图便不能直接执行insert、update和delete等dml操作。
instead of触发器是基于这种复杂视图的触发器,当对这种复杂视图进行dml操作时会激活该类触发器。

--语法格式:
create [or replace] trigger trigger_name
instead of trigger_event [of column_name]
on view_name
for each row
[when trigger_condition]
begin
trigger_body
end [trigger_name];
--instead of指定触发器类型。
--
创建视图
create view teachers_view2 as
select t.teacher_id, t.name, d.department_id, d.department_name
from teachers t, departments d
where t.department_id = d.department_id;
--创建instead of触发器
create or replace trigger t_d_change
instead of insert on teachers_view2
for each row
declare
v_counter int;
begin
select count(*) into v_counter from departments
where department_id = :new.department_id;
if v_counter = 0 then
insert into department(department_id, department_name)
values(:new.department_id, :new.department_name);
end if;
select count(*) into v_counter from teachers
where teacher_id = :new.teacher_id;
if v_counter = 0 then
insert into teachers(teacher_id, name, department_id)
values(:new.teacher_id, :new.name, :new.department_id);
end if;
end t_d_change;


四、系统事件触发器
 系统事件触发器基于数据库或模式schema。触发事件包括数据库事件(如startup、shutdown等)、
DDL事件(如create、alter、drop等)。

--语法格式:
create [or replace] trigger trigger_name
before | after trigger_event
on database | schema
[when trigger_condition]
begin
trigger_body
end trigger_name;
--database | schema 指定触发器是基于数据库还是基于模式。
--
建立event_drop,以便存储删除对象的有关信息
create table event_drop(
user_name varchar2(15), --操作员
object_name varchar2(15), --grades
object_type varchar2(10), --对象类型 table
object_owner varchar2(15), --对象所有者
creation_date date --触发时间
);
--建立系统事件触发器sys_event
create or replace trigger sys_event
after drop on schema
begin
insert into event_drop
values(user, ora_dict_obj_name, ora_dict_obj_type, ora_dict_obj_owner, sysdate)
end sys_event;

 

posted on 2012-04-05 13:53  星辰日月00  阅读(1021)  评论(0编辑  收藏  举报