原文链接:http://book.51cto.com/art/201007/212376.htm
使用INSTEAD OF 触发器
如果创建一个对象视图,则可以使用INSTEAD OF 触发器来告诉Oracle 如何更新作为视图一部分的基表。可以在对象视图或标准关系视图中使用INSTEAD OF 触发器。
例如,如果一个视图涉及两个表的连接,那么用户在视图中更新记录的能力有限。但是,如果使用INSTEAD OF 触发器,那么当用户试图通过该视图更改值时,可以告诉Oracle 如何在表中更新、删除或插入记录。INSTEAD OF 触发器中的程序代码代替了输入的update、delete 或insert 命令。
例如,有一个连接BOODSHELF 表与BOOKSHELF_AUTHOR 表的视图:
在下面的程序清单中,创建了AUTHOR_PUBLISHER 视图的一个INSTEAD OF 触发器:
create trigger AUTHOR_PUBLISHER_UPDATE instead of UPDATE on AUTHOR_PUBLISHER for each row 该触发器的下一部分告诉Oracle 如何处理update 操作。首先要检查的是触发器体内部的Publisher 值。如果旧的Publisher 值等于新的Publisher 值,则不做任何修改。如果两个值不相同,则BOOKSHELF 表被更新为新的Publisher 值:
现在可以直接更新AUTHOR_PUBLISHER 视图并使触发器恰当地更新基表。例如,以下命令将更新BOOKSHELF 表:
可以通过查询BOOKSHELF 表,来验证update 操作:
INSTEAD OF 触发器的功能十分强大。如本示例所示,使用PL/SQL 内可用的流控制逻辑,可以使用该触发器在不同的数据库表上进行操作。在处理对象视图时,可以使用INSTEADOF 触发器将对象视图的DML 重定位到这些视图的基表上。
使用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 where AuthorName = 'W. P. KINSELLA';
AUTHORNAME PUBLISHER
--------------------------------------------- ----------
W. P. KINSELLA MARINER
W. P. KINSELLA
BALLANTINE 如果试图更新Publisher 的值,则更新会失败:
update AUTHOR_PUBLISHER set Publisher = 'MARINER' where AuthorName = 'W. P. KINSELLA'; set Publisher = '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 set Publisher = :new.Publisher where Title = :old.Title; end if; if :old.AuthorName <> :new.AuthorName then update BOOKSHELF_AUTHOR set AuthorName = :new.AuthorName where Title = :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 set Publisher = :new.Publisher where Title = :old.Title; end if;
触发器的下一部分判断AuthorName 的值是否有变化。如果AuthorName 的值被修改,则更新BOOKSHELF 表,以反映新的AuthorName 值:
if :old.AuthorName <> :new.AuthorName then update BOOKSHELF_AUTHOR set AuthorName = :new.AuthorName where Title = :old.Title; end if;
因此,该视图依赖两个表—— BOOKSHELF 和BOOKSHELF_AUTHOR—— 并且该视图的update 操作可以更新一个表也可以同时更新两个表。为了支持对象视图而引入的INSTEADOF 触发器是应用程序开发的有力工具。
现在可以直接更新AUTHOR_PUBLISHER 视图并使触发器恰当地更新基表。例如,以下命令将更新BOOKSHELF 表:
update AUTHOR_PUBLISHER set Publisher = 'MARINER' where AuthorName = 'W. P. KINSELLA'; 2 rows updated.
可以通过查询BOOKSHELF 表,来验证update 操作:
select Publisher from BOOKSHELF where Title in (select Title from BOOKSHELF_AUTHOR where AuthorName = 'W. P. KINSELLA');
PUBLISHER
--------------------
MARINER
MARINER
INSTEAD OF 触发器的功能十分强大。如本示例所示,使用PL/SQL 内可用的流控制逻辑,可以使用该触发器在不同的数据库表上进行操作。在处理对象视图时,可以使用INSTEADOF 触发器将对象视图的DML 重定位到这些视图的基表上。