设计和使用触发机制 触发机制从本质上来说是一种特殊类型的存贮过程它可以在下列的三种情况之一发生时 自动运行 l 更新 l 插入 l 删除 Transcat-SQL 创建触发机制的语法格式如下 SYNTAX create trigger trigger_name on table_name for {insert, update, delete} as SQL_Statements ORACLE 7 SQL 则使用下边的语法来创建触发机制 SYNTAX CREATE [OR REPLACE] TRIGGER [schema.]trigger_name {BEFORE | AFTER} {DELETE | INSERT | UPDATE [OF column[, column]...]} [OR {DELETE | INSERT | UPDATE [OF column [, column] ...]}]... ON [schema.]table [[REFERENCING { OLD [AS] old [NEW [AS] new] | NEW [AS] new [OLD [AS] old]}] FOR EACH ROW [WHEN (condition)] ] pl/sql statements... 触发机制对于强制执行引用完整性非常有用我们在第9 天创建和维护表中学习 如何创建表时曾经提到过强制执行引用完整性可以保证在多表交叉访问时数据的有效性 如果用户输入了下边的命令 INPUT 1> insert RECORDINGS values (12, "The Cross of Changes", 3, 1994) SQL 21 日自学通(V1.0) 翻译人笨猪 275 2> go 分析 这是一个有效的在表RECORDINGS 表中插入新记录的命令可是对ARTISTS 表进 行一下快速的检查后你会发现并没有ARTIST_ID=12 的记录用户所拥有的在 RECORDINGS 表中插入记录的权利可以彻底地破坏你的数据引用完整性 注尽管有许多数据库系统都可以通过在创建表的时候设置约束来强制执行数据的引 用完整性但是触发机制却提供了更为灵活的解决方法约束将会把系统的错误信息返回 给用户并且你现在可能已经知道了这些错误信息有时对你没有多大的帮助而作为 另外一种方法触发机制可以打印出错误信息调用其它的存贮过程如果有必要它还 可以修正错误信息 触发机制与事务处理 触发机制所进行的活动是被默认为事务处理的一部分进行的主要的事件次序如下 1 默认地自动运行BEGIN TRANSACTION 语句对于表和触发机制而言 2 当插入更新删除操作发生时 3 触发机制被调用其中的语句被自动执行 4 由触发机制自动的完成事务处理的取消或确认操作 例13.9 本例解决了早些时候更新RECORDINGS 表时所带来的问题 INPUT 1> create trigger check_artists 2> on RECORDINGS 3> for insert, update as 4> if not exists (select * from ARTISTS, RECORDINGS 5> where ARTISTS.artist_id = RECORDINGS.artist_id) 6> begin 7> print "Illegal Artist_ID!" 8> rollback transaction 9> end SQL 21 日自学通(V1.0) 翻译人笨猪 276 10> go 分析 类似的问题也可能在删除RECORDINGS 表中的记录时出现如果你只是将 RECORDINGS 表中将某个艺术家删除了你可能也想同时删除ARTIST 表中的艺术家记 录如果在触发机制激活之前记录已经被删除了那么你如何才能知道哪一个ARTIST_ID 记录才是需要删除的记录呢对于这个问题有两种解决的办法 l 将ARTIST 表中的所有不在RECORDINGS 表中存在记录的艺术家删除见例 13.10a l 检查被删除过的逻辑表Transcat-SQL 可以维护两个表DELETED 和 INSERTED 这两个表中保存着对真实表的最近所做的改动它与触发机制所创 建的表有着相同的结构因此你可以从DELETE 表中获得ARTIST_ID 的内容 并将它从ARTIST 中删除见例13.10b 例13.10a INPUT 1> create trigger delete_artists 2> on RECORDINGS 3> for delete as 4> begin 5> delete from ARTISTS where artist_id not in 6> (select artist_id from RECORDINGS) 7> end 8> go 例13.10b 1> create trigger delete_artists 2> on RECORDINGS 3> for delete as 4> begin 5> delete ARTISTS from ARTISTS, deleted 6> where ARTIST.artist_id = deleted.artist_id 7> end SQL 21 日自学通(V1.0) 翻译人笨猪 277 8> go 使用触发机制时的限制 l 当你在使用触发机制时你必须要知道它有如下的使用限制 l 不能在临时表中创建触发机制 l 触发机制必须在当前的表所在的数据库中创建 l 不能在视图中创建触发机制 l 当表被删除以后所有与之相关的触发机制会被自动地删除 触发机制的嵌套 触发机制也可以被嵌套比如说你可以创建一个触发机制来执行删除动作例如如 果触发机制自己删除了一个记录数据库服务器可以据此激活另一个触发机制结果将会 不停地循环直到表中的所有记录都被删除掉或一些其他的触发条件被激活嵌套机制 不是默认的可是环境中必须提供这个功能对于这个主题你可以参考你的数据库文档 来得到更多的内容
看看这个例子!很简单的! CREATE OR REPLACE TRIGGER trigger_card_payment_seq after delete on card_payment_seq for each row declarebegin insert into retract_card_payment_seq(PAYMENT_CHANNEL_ID,SEQ_ID,MONTH_NUMBER, ACCTBK_PAYMENT_ID,AREA_CODE,ID_TYPE, PAYMENT_ID,PAYMENT_DATE,COMMAND_CODE, HRN,CARD_ID,CARD_VALUE,STATUS,retract_date) values(:old.PAYMENT_CHANNEL_ID,:old.SEQ_ID,:old.MONTH_NUMBER, :old.ACCTBK_PAYMENT_ID,:old.AREA_CODE,:old.ID_TYPE, :old.PAYMENT_ID,:old.PAYMENT_DATE,:old.COMMAND_CODE, :old.HRN,:old.CARD_ID,:old.CARD_VALUE,:old.STATUS,sysdate); end;
触发机制从本质上来说是一种特殊类型的存贮过程它可以在下列的三种情况之一发生时
自动运行
l 更新
l 插入
l 删除
Transcat-SQL 创建触发机制的语法格式如下
SYNTAX
create trigger trigger_name
on table_name
for {insert, update, delete}
as SQL_Statements
ORACLE 7 SQL 则使用下边的语法来创建触发机制
SYNTAX
CREATE [OR REPLACE] TRIGGER [schema.]trigger_name
{BEFORE | AFTER}
{DELETE | INSERT | UPDATE [OF column[, column]...]}
[OR {DELETE | INSERT | UPDATE [OF column [, column] ...]}]...
ON [schema.]table
[[REFERENCING { OLD [AS] old [NEW [AS] new]
| NEW [AS] new [OLD [AS] old]}]
FOR EACH ROW
[WHEN (condition)] ]
pl/sql statements...
触发机制对于强制执行引用完整性非常有用我们在第9 天创建和维护表中学习
如何创建表时曾经提到过强制执行引用完整性可以保证在多表交叉访问时数据的有效性
如果用户输入了下边的命令
INPUT
1> insert RECORDINGS values (12, "The Cross of Changes", 3, 1994)
SQL 21 日自学通(V1.0) 翻译人笨猪
275
2> go
分析
这是一个有效的在表RECORDINGS 表中插入新记录的命令可是对ARTISTS 表进
行一下快速的检查后你会发现并没有ARTIST_ID=12 的记录用户所拥有的在
RECORDINGS 表中插入记录的权利可以彻底地破坏你的数据引用完整性
注尽管有许多数据库系统都可以通过在创建表的时候设置约束来强制执行数据的引
用完整性但是触发机制却提供了更为灵活的解决方法约束将会把系统的错误信息返回
给用户并且你现在可能已经知道了这些错误信息有时对你没有多大的帮助而作为
另外一种方法触发机制可以打印出错误信息调用其它的存贮过程如果有必要它还
可以修正错误信息
触发机制与事务处理
触发机制所进行的活动是被默认为事务处理的一部分进行的主要的事件次序如下
1 默认地自动运行BEGIN TRANSACTION 语句对于表和触发机制而言
2 当插入更新删除操作发生时
3 触发机制被调用其中的语句被自动执行
4 由触发机制自动的完成事务处理的取消或确认操作
例13.9
本例解决了早些时候更新RECORDINGS 表时所带来的问题
INPUT
1> create trigger check_artists
2> on RECORDINGS
3> for insert, update as
4> if not exists (select * from ARTISTS, RECORDINGS
5> where ARTISTS.artist_id = RECORDINGS.artist_id)
6> begin
7> print "Illegal Artist_ID!"
8> rollback transaction
9> end
SQL 21 日自学通(V1.0) 翻译人笨猪
276
10> go
分析
类似的问题也可能在删除RECORDINGS 表中的记录时出现如果你只是将
RECORDINGS 表中将某个艺术家删除了你可能也想同时删除ARTIST 表中的艺术家记
录如果在触发机制激活之前记录已经被删除了那么你如何才能知道哪一个ARTIST_ID
记录才是需要删除的记录呢对于这个问题有两种解决的办法
l 将ARTIST 表中的所有不在RECORDINGS 表中存在记录的艺术家删除见例
13.10a
l 检查被删除过的逻辑表Transcat-SQL 可以维护两个表DELETED 和
INSERTED 这两个表中保存着对真实表的最近所做的改动它与触发机制所创
建的表有着相同的结构因此你可以从DELETE 表中获得ARTIST_ID 的内容
并将它从ARTIST 中删除见例13.10b
例13.10a
INPUT
1> create trigger delete_artists
2> on RECORDINGS
3> for delete as
4> begin
5> delete from ARTISTS where artist_id not in
6> (select artist_id from RECORDINGS)
7> end
8> go
例13.10b
1> create trigger delete_artists
2> on RECORDINGS
3> for delete as
4> begin
5> delete ARTISTS from ARTISTS, deleted
6> where ARTIST.artist_id = deleted.artist_id
7> end
SQL 21 日自学通(V1.0) 翻译人笨猪
277
8> go
使用触发机制时的限制
l 当你在使用触发机制时你必须要知道它有如下的使用限制
l 不能在临时表中创建触发机制
l 触发机制必须在当前的表所在的数据库中创建
l 不能在视图中创建触发机制
l 当表被删除以后所有与之相关的触发机制会被自动地删除
触发机制的嵌套
触发机制也可以被嵌套比如说你可以创建一个触发机制来执行删除动作例如如
果触发机制自己删除了一个记录数据库服务器可以据此激活另一个触发机制结果将会
不停地循环直到表中的所有记录都被删除掉或一些其他的触发条件被激活嵌套机制
不是默认的可是环境中必须提供这个功能对于这个主题你可以参考你的数据库文档
来得到更多的内容
看看这个例子!很简单的!
CREATE OR REPLACE TRIGGER trigger_card_payment_seq after
delete on card_payment_seq for each row
declarebegin insert into retract_card_payment_seq(PAYMENT_CHANNEL_ID,SEQ_ID,MONTH_NUMBER,
ACCTBK_PAYMENT_ID,AREA_CODE,ID_TYPE,
PAYMENT_ID,PAYMENT_DATE,COMMAND_CODE,
HRN,CARD_ID,CARD_VALUE,STATUS,retract_date)
values(:old.PAYMENT_CHANNEL_ID,:old.SEQ_ID,:old.MONTH_NUMBER,
:old.ACCTBK_PAYMENT_ID,:old.AREA_CODE,:old.ID_TYPE,
:old.PAYMENT_ID,:old.PAYMENT_DATE,:old.COMMAND_CODE,
:old.HRN,:old.CARD_ID,:old.CARD_VALUE,:old.STATUS,sysdate);
end;