對于復雜的視圖,無法直接對視圖進行修改。或者在某些情況下,需要將對視圖的修改轉化為另外一種操作,這種情況下可以使用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表中還存在基于字段更新的觸發器的話,就不能使用這種辦法了。