38.2.2 使用INSTEAD OF 触发器
如果创建一个对象视图,则可以使用INSTEAD OF 触发器来告诉Oracle 如何更新作为视图一部分的基表。可以在对象视图或标准关系视图中使用INSTEAD OF 触发器。
例如,如果一个视图涉及两个表的连接,那么用户在视图中更新记录的能力有限。但是,如果使用INSTEAD OF 触发器,那么当用户试图通过该视图更改值时,可以告诉Oracle 如何在表中更新、删除或插入记录。INSTEAD OF 触发器中的程序代码代替了输入的update、delete 或insert 命令。
例如,有一个连接BOODSHELF 表与BOOKSHELF_AUTHOR 表的视图:create or replace view AUTHOR_PUBLISHER as
select BA.AuthorName, Title, B.Publisher
from BOOKSHELF_AUTHOR BA inner join BOOKSHELF B
using (Title);
可以从该视图中选择相应的值—— 而且如果使用INSTEAD OF 触发器,就可以通过该视图执行数据操作。考虑以下记录:select AuthorName, Publisher from AUTHOR_PUBLISHER
whereAuthorName='W. P. KINSELLA';
AUTHORNAME PUBLISHER
--------------------------------------------- ----------
W. P. KINSELLA MARINER
W. P. KINSELLA BALLANTINE
如果试图更新Publisher 的值,则更新会失败:update AUTHOR_PUBLISHER
setPublisher='MARINER'
whereAuthorName='W. P. KINSELLA';
setPublisher='MARINER'
*
ERROR at line 2:
ORA-01779: cannot modify a column which maps to a
non key-preserved table
问题是Oracle 不能确定BOOKSHELF 表中哪些记录中的哪些出版商要更新。为了通过该视图执行更新,需要使用INSTEAD OF 触发器。
在下面的程序清单中,创建了AUTHOR_PUBLISHER 视图的一个INSTEAD OF 触发器:create or replace trigger AUTHOR_PUBLISHER_UPDATE
instead of UPDATE on AUTHOR_PUBLISHER
for each row
begin
if :old.Publisher<>:new.Publisher
then
update BOOKSHELF
setPublisher= :new.Publisher
whereTitle= :old.Title;
end if;
if :old.AuthorName<>:new.AuthorName
then
update BOOKSHELF_AUTHOR
setAuthorName= :new.AuthorName
whereTitle= :old.Title;
end if;
end;
/
该触发器的***部分命名触发器,并通过instead of 子句描述其用途。顾名思义该触发器的功能很明显:用于支持对AUTHOR_PUBLISHER 视图执行的update 命令。它是一个行级触发器;可以处理每个变化的行,如下所示:create trigger AUTHOR_PUBLISHER_UPDATE
instead of UPDATE on AUTHOR_PUBLISHER
for each row
该触发器的下一部分告诉Oracle 如何处理update 操作。首先要检查的是触发器体内部的Publisher 值。如果旧的Publisher 值等于新的Publisher 值,则不做任何修改。如果两个值不相同,则BOOKSHELF 表被更新为新的Publisher 值:begin
if :old.Publisher<>:new.Publisher
then
update BOOKSHELF
setPublisher= :new.Publisher
whereTitle= :old.Title;
end if;
触发器的下一部分判断AuthorName 的值是否有变化。如果AuthorName 的值被修改,则更新BOOKSHELF 表,以反映新的AuthorName 值:if :old.AuthorName<>:new.AuthorName
then
update BOOKSHELF_AUTHOR
setAuthorName= :new.AuthorName
whereTitle= :old.Title;
end if;
因此,该视图依赖两个表—— BOOKSHELF 和BOOKSHELF_AUTHOR—— 并且该视图的update 操作可以更新一个表也可以同时更新两个表。为了支持对象视图而引入的INSTEADOF 触发器是应用程序开发的有力工具。
现在可以直接更新AUTHOR_PUBLISHER 视图并使触发器恰当地更新基表。例如,以下命令将更新BOOKSHELF 表:update AUTHOR_PUBLISHER
setPublisher='MARINER'
whereAuthorName='W. P. KINSELLA';
2 rows updated.
可以通过查询BOOKSHELF 表,来验证update 操作:select Publisher from BOOKSHELF
where Title in
(select Title from BOOKSHELF_AUTHOR
whereAuthorName='W. P. KINSELLA');
PUBLISHER
--------------------
MARINER
MARINER
INSTEAD OF 触发器的功能十分强大。如本示例所示,使用PL/SQL 内可用的流控制逻辑,可以使用该触发器在不同的数据库表上进行操作。在处理对象视图时,可以使用INSTEADOF 触发器将对象视图的DML 重定位到这些视图的基表上。
【责任编辑:云霞 TEL:(010)68476606】
点赞 0