没有合适的资源?快使用搜索试试~ 我知道了~
资源推荐
资源详情
资源评论
下载
第6章 数据库触发器
命名P L / S Q L 块的第四种类型是触发器。触发器类在某些方面类似于子程序,但它们之间也
有明显地区别。我们在本章将介绍如何创建不同类型的触发器以及讨论触发器的一些应用。
6.1 触发器的类型
触发器类似于函数和过程,它们都是具有声明部分、执行部分和异常处理部分的命名
P L / S Q L块。像包一样,触发器必须在数据库中以独立对象的身份存储,并且不能与包和块具有
本地关系。我们在前两章中已经讲过,过程是显式地通过过程调用从其他块中执行的,同时,
过程调用可以传递参数。与之相反 ,触发器是在事件发生时隐式地运行的,并且触发器不能接收
参数。运行触发器的方式叫做激发( f i r i n g )触发器,触发事件可以是对数据库表的 D M L
(I N S E RT 、U P D AT E或D E L E T E )操作或某种视图的操作 ( Vi e w )。O r a c l e 8 i 把触发器功能扩展到
了可以激发系统事件,如数据库的启动和关闭,以及某种 D D L 操作。我们将在本章的后几节讨
论触发事件的详细内容。
触发器可以用于下列情况:
• 维护在表创建阶段通过声明限制无法实现的复杂完整性限制。
• 通过记录修改内容和修改者来审计表中的信息。
• 在表内容发生变更时,自动通知其他程序采取相应的处理。
• 在订阅发布环境下,发布有关各种事件的信息。
有三种主要的触发器类型: D M L 、替代触发器和系统触发器。在下面几节中,我们将逐一
介绍这些触发器类型。在本章后面“创建触发器”一节中还将详细讨论这些触发器。
注意 O r a c l e 8 i 允许使用P L / S Q L 语言或可以作为外部例程调用的其他语言来编制触发
器。有关触发器的详细介绍,请参阅 6 . 2 . 4节和第1 0章的内容。
6.1.1 DML触发器
D M L 触发器可以由D M L 语句激发,并且由该语句的类型决定 D M L触发器的类型。可以定义
D M L 触发器进行I N S E RT ,U P D AT E,D E L E T E操作。这类触发器可以在上述操作之前或之后激
发,除此之外,它们也可以在行或语句操作上激发。
作为例子,让我们假设要跟踪不同专业的统计信息,其中包括已注册学生的数量和已得到
的总分。我们要把这些结果存储在表 m a j o r _ s t a t s中:
节选自在线代码relTables.sql
CREATE TABLE major_stats (
major VARCHAR2(30),
total_credits NUMBER,
total_students NUMBER);
为了保持表m a j o r _ s t a t s 中的数据处于更新状态,我们可以创建一个每次表 s t u d e n t s被修改时
自动更新表m a j o r _ s t a t s 的触发器。下面所示的 U p d a t e M a j o r S t a t s就是实现上述功能的触发器。在
表s t u d e n t s 上进行任何D M L 操作之后,该触发器将启动运行。该触发器的代码要查询表 s t u d e n t s
并使用当前的统计信息更新表 m a j o r _ s t a t s。
节选自在线代码UpdateMajorStats.sql
CREATE OR REPLACE TRIGGER UpdateMajorStats
/* Keeps the major_stats table up-to-date with changes made
to the students table. */
AFTER INSERT OR DELETE OR UPDATE ON students
DECLARE
CURSOR c_Statistics IS
SELECT major, COUNT(*) total_students,
SUM(current_credits) total_credits
FROM students
GROUP BY major;
BEGIN
/* First delete from major_stats. This will clear the
statistics, and is necessary to account for the deletion
of all students in a given major. */
DELETE FROM major_stats;
/* Now loop through each major, and insert the appropriate row into
major_stats. */
FOR v_StatsRecord in c_Statistics LOOP
INSERT INTO major_stats (major, total_credits, total_students)
VALUES (v_StatsRecord.major, v_StatsRecord.total_credits,
v_StatsRecord.total_students);
END LOOP;
END UpdateMajorStats;
语句触发器可以激发多种类型的触发语句。例如, U p d a t e M a j o r S t a t s 可以激发 I N S E RT ,
U P D AT E,D E L E T E语句。触发事件说明了一个或多个激发触发器的 D M L 操作。
6.1.2 替代触发器
O r a c l e 8提供的这种替代触发器( Instead-of trigger)只能定义在视图上(可以是关系
或对象)。与D M L 触发器不同,D M L 触发器是在D M L 操作之外运行的,而替代触发
器则代替激发它的 D M L 语句运行。替代触发器是行一级的。例如,请看下面的视图 c l a s s e s _
r o o m s :
节选自在线代码insteadOf.sql
CREATE OR REPLACE VIEW classes_rooms AS
SELECT department, course, building, room_number
FROM rooms, classes
WHERE rooms.room_id = classes.room_id;
196计计第二部分 非对象功能
下载
如下所示,直接执行对该视图的插入操作是非法的。这是因为该视图是两个表的联合 ,而插
入操作要求对两个现行表进行修改,下面的 SQL *Plus会话显示了插入操作过程:
节选自在线代码insteadOf.sql
SQL> INSERT INTO classes_rooms (department, course, building,
room_number)
2 VALUES ('MUS', 100, 'Music Building', 200);
INSERT INTO classes_rooms (department, course, building, room_number)
*
ERROR at line 1:
ORA-01732: data manipulation operation not legal on this view
然而,我们可以创建一个替代触发器来实现正确的插入操作,也就是来更新现行表:
节选自在线代码insteadOf.sql
CREATE TRIGGER ClassesRoomsInsert
INSTEAD OF INSERT ON classes_rooms
DECLARE
v_roomID rooms.room_id%TYPE;
BEGIN
-- First determine the room ID
SELECT room_id
INTO v_roomID
FROM rooms
WHERE building = :new.building
AND room_number = :new.room_number;
-- And now update the class
UPDATE CLASSES
SET room_id = v_roomID
WHERE department = :new.department
AND course = :new.course;
END ClassesRoomsInsert;
有了触发器C l a s s e s R o o m s I n s e r t ,I N S E RT 语句就可以执行正确的更新操作。
注意 在上面的程序中,触发器 C l a s s e s R o o m s I n s e r t 没有做任何错误检查。我们将在本
章后的程序中加入错误检查和处理代码。
6.1.3 系统触发器
O r a c l e 8 i 提供了第三种触发器,这种系统触发器在发生如数据库启动或关闭等系统
事件时激发,而不是在执行 D M L 语句时激发。系统触发器也可以在 D D L操作时,如
表的创建中激发。例如,假设我们要记录对象创建的时间,我们可以通过创建下面的表来实现
上述记录功能:
节选自在线代码LogCreations.sql
CREATE TABLE ddl_creations (
user_id VARCHAR2(30),
object_type VARCHAR2(20),
第6章 数据库触发器计计197
下载
object_name VARCHAR2(30),
object_owner VARCHAR2(30),
creation_date DATE);
一旦该表可以使用,我们就可以创建一个系统触发器来记录相关信息。在每次 C R E AT E语句
对当前模式进行操作之后,触发器 L o g C r e a t i o n s就记录在d d l _ c r e a t i o n s中创建的对象的有关信息。
节选自在线代码LogCreations .sql
CREATE OR REPLACE TRIGGER LogCreations
AFTER CREATE ON SCHEMA
BEGIN
INSERT INTO ddl_creations (user_id, object_type, object_name,
object_owner, creation_date)
VALUES (USER, SYS.DICTIONARY_OBJ_TYPE, SYS.DICTIONARY_OBJ_NAME,
SYS.DICTIONARY_OBJ_OWNER, SYSDATE);
END LogCreations;
6.2 创建触发器
所有触发器,不管其类型如何,都可以使用相同的语法创建。下面是创建触发器的通用语
法:
CREATE [OR REPLACE] TRIGGER trigger_name
{BEFORE | AFTER | INSTEAD OF} triggering_event
referencing_clause
[WHEN trigger_condition]
[FOR EACH ROW]
trigger_body;
其中,t r i g g e r _ n a m e 是触发器的名称, t r i g g e r i n g _ e v e n t说明了激发触发器的事件(也可能包
括特殊的表或视图),t r i g g e r _ b o d y 是触发器的代码。r e f e r e n c i n g _ c l a u s e用来引用正在处于修改状
态下的行中的数据,如果在 W H E N子句中指定t r i g g e r _ c o n d i t i o n的话,则首先对该条件求值。触
发器主体只有在该条件为真值时才运行。我们在下面几节中将演示不同类型的触发器案例。
注意 触发器主体不能超过3 2 K。如果触发器长度超过了该限制,就要把该体内的某些
代码放到单独编译的包或存储子程序中,并从触发器主体中调用这些代码。
6.2.1 创建D M L 触发器
D M L 触发器是由对数据库表进行 I N S E RT、U P D AT E、D E L E T E操作而激发的触发器。该类
触发器可以在上述操作之前或之后激发运行,也可以按每个变更行激发一次,或每个语句激发
一次进行。这些条件的组合形成了触发器的类型。总共有 1 2 种可能的触发类型: 3种语句×2种
定时×2级。例如,下面所有的说明都是合法的 D M L触发器类型:
• 更新语句之前
• 插入行之后
• 删除行之前
198计计第二部分 非对象功能
下载
表6 - 1 总结了D M L 触发器的各种选择项。除此之外,触发器也可以由给定表中的一个以上的
D M L 语句,如I N S E RT 和U P D A E而激发。触发器中的任何代码将随触发语句一起作为同一事务
的一部分运行。
可以对一个表定义任意数量的触发器,其中可以包括一个以上的给定 D M L 类型。例如,可
以定义两个删除语句之后的触发器。所有同类型的触发器将按顺序激发。(下一节讨论触发器的
激发顺序。)
注意 在P L / S Q L 2 . 1版(O r a c l e 7 的7 . 1 版)之前的版本下,每种类型的触发器只能在表
上定义一个。也就是说,最多有 1 2 个触发器。因此,初始化参数 C O M PAT I B L E 就必须
是7 . 1 或更高以便复制一个表上的同类触发器。
D M L 触发器的触发事件说明了激发触发器的表的名称(以及列)。在O r a c l e 8 i下,触发器可
以在嵌套表的列上激发。本书的第 1 4 章提供了更多的触发器内容。
表6-1 DML触发器类型
类 别 值 说 明
语句 I N S E RT、D E L E T E 、 定义何种D M L 语句激发触发器
U P D AT E
定时 之前或之后 定义触发器是在语句运行前或运行后激发
级 行或语句 如果触发器是行级触发器,该触发器就对由触发语句变更的
每一行激发一次。如果触发器是语句级的触发器,则该触发
器就在语句之前或之后激发一次。行级触发器是按触发器定
义中的FOR EACH ROW子句表示的
1. DML触发器激发顺序
触发器是在D M L 语句运行时激发的。下面是执行 D M L 语句的算法步骤:
1) 如果有语句之前级触发器的话,先运行该触发器。
2) 对于受语句影响每一行:
a. 如果有行之前级触发器的话,运行该触发器。
b. 执行该语句本身。
c. 如果有行之后级触发器的话,运行该触发器。
3) 如果有语句之后级触发器的话,运行该触发器。
为了说明上面的算法,假设我们在表 c l a s s e s 上创建了所有四种U P D AT E 触发器,即之前,之
后,语句和行级。我们将创建三个行前触发器和两个语句后触发器,其代码如下:
节选自在线代码firingOrder .sql
CREATE SEQUENCE trig_seq
START WITH 1
INCREMENT BY 1;
CREATE OR REPLACE PACKAGE TrigPackage AS
-- Global counter for use in the triggers
v_Counter NUMBER;
END TrigPackage;
第6章 数据库触发器计计199
下载
剩余33页未读,继续阅读
资源评论
- Seavean2013-08-05相当不错,给我这个触发器新手很好的指导。
- xzy092013-03-29东西整理的挺好 很不错!
- 鬼902013-01-23教程很详细,但是我的表操作不起来,遗憾。
gelyon
- 粉丝: 301
- 资源: 6
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功