对于复杂的视图,无法直接对视图进行修改。或者在某些情况下,需要将对视图的修改转化为另外一种操作,这种情况下可以使用INSTEAD OF TRIGGER

看一个简单的例子,下面建立一个UNION ALL视图,其中T1表是不能修改的,对视图T所有的修改都重定位到T2上。

SQL> CREATE TABLE T1 (ID NUMBER PRIMARY KEY, NAME VARCHAR2(30), OTHERS VARCHAR2(30));

表已创建。

SQL> CREATE TABLE T2 (ID NUMBER PRIMARY KEY, NAME VARCHAR2(30), OTHERS VARCHAR2(30));

表已创建。

SQL> CREATE VIEW T AS SELECT * FROM T1 UNION ALL SELECT * FROM T2;

视图已创建。

SQL> INSERT INTO T1 VALUES (1, 'T1', 'TEST');

已创建 1 行。

SQL> INSERT INTO T2 VALUES (2, 'T2', 'TEST T2');

已创建 1 行。

SQL> COMMIT;

提交完成。

SQL> SELECT * FROM T;

ID NAME OTHERS
---------- ------------------------------ ------------------------------
1 T1 TEST
2 T2 TEST T2

SQL> INSERT INTO T VALUES (3, 'T', 'TEST AGAIN');
INSERT INTO T VALUES (3, 'T', 'TEST AGAIN')
*
1 行出现错误:
ORA-01732:
此视图的数据操纵操作非法


SQL> DELETE T;
DELETE T
*
1 行出现错误:
ORA-01732:
此视图的数据操纵操作非法


SQL> UPDATE T SET OTHERS = 'UPDATED' WHERE ID = 2;
UPDATE T SET OTHERS = 'UPDATED' WHERE ID = 2
*
1 行出现错误:
ORA-01732:
此视图的数据操纵操作非法

下面建立INSTEAD OF触发器:

SQL> CREATE OR REPLACE TRIGGER INSTEADOF_T
2 INSTEAD OF INSERT OR UPDATE OR DELETE ON T
3 REFERENCES OLD AS OLD NEW AS NEW
4 FOR EACH ROW
5 BEGIN
6 IF INSERTING THEN
7 INSERT INTO T2 VALUES (:NEW.ID, :NEW.NAME, :NEW.OTHERS);
8 ELSIF UPDATING THEN
9 UPDATE T2 SET ID = :NEW.ID, NAME = :NEW.NAME, OTHERS = :NEW.OTHERS
10 WHERE ID = :OLD.ID;
11 ELSIF DELETING THEN
12 DELETE T2 WHERE ID = :OLD.ID;
13 END IF;
14 END;
15 /

 

触发器已创建

SQL> INSERT INTO T VALUES (3, 'T', 'TEST AGAIN');

已创建 1 行。

SQL> SELECT * FROM T;

ID NAME OTHERS
---------- ------------------------------ ------------------------------
1 T1 TEST
2 T2 TEST T2
3 T TEST AGAIN

SQL> SELECT * FROM T1;

ID NAME OTHERS
---------- ------------------------------ ------------------------------
1 T1 TEST

SQL> SELECT * FROM T2;

ID NAME OTHERS
---------- ------------------------------ ------------------------------
2 T2 TEST T2
3 T TEST AGAIN

SQL> UPDATE T SET OTHERS = 'UPDATED';

已更新3行。

SQL> SELECT * FROM T;

ID NAME OTHERS
---------- ------------------------------ ------------------------------
1 T1 TEST
2 T2 UPDATED
3 T UPDATED

SQL> DELETE T;

已删除3行。

SQL> SELECT * FROM T;

ID NAME OTHERS

---------- ------------------------------ ------------------------------
1 T1 TEST

 

SQL> SELECT * FROM T2;

未选定行

INSTEAD OF触发器已经发挥了作用,将所有对视图T的修改都重定向到T2上,不过UPDATE的修改采用了偷懒的写法,这里并没有对修改的列进行检测,而是采用了全部更新的方法。这样可以减少代码量,但是会对一些没有发生修改的字段进行更新,导致REDOUNDO的增加。如果T2表中还存在基于字段更新的触发器的话,就不能使用这种办法了。