物化視圖的刷新其實(shí)和普通的SQL執(zhí)行沒有什么本質(zhì)的區(qū)別,因此也可以通過在物化視圖上創(chuàng)建觸發(fā)器的方式,對刷新操作進(jìn)行定制。
正好前兩天有人在BLOG上問我,如果在物化視圖添加一個(gè)時(shí)間戳列,并在物化視圖更新的時(shí)候,自動(dòng)維護(hù)這個(gè)列。其實(shí)很簡單,通過觸發(fā)器就可以達(dá)到這個(gè)目的:
SQL> CREATE TABLE T (ID NUMBER PRIMARY KEY, NAME VARCHAR2(30));
表已創(chuàng)建。
SQL> INSERT INTO T SELECT ROWNUM, TNAME FROM TAB;
已創(chuàng)建25行。
SQL> COMMIT;
提交完成。
SQL> CREATE MATERIALIZED VIEW LOG ON T;
實(shí)體化視圖日志已創(chuàng)建。
SQL> CREATE TABLE MV_T (ID NUMBER, NAME VARCHAR2(30), TIME DATE DEFAULT SYSDATE);
表已創(chuàng)建。
SQL> CREATE MATERIALIZED VIEW MV_T ON PREBUILT TABLE REFRESH FAST
2 AS SELECT * FROM T;
實(shí)體化視圖已創(chuàng)建。
SQL> ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS';
會話已更改。
SQL> SELECT * FROM T WHERE ID = 1;
ID NAME
---------- ------------------------------
1 T_AB
SQL> SELECT * FROM MV_T WHERE ID = 1;
未選定行
SQL> EXEC DBMS_MVIEW.REFRESH('MV_T', 'C')
PL/SQL 過程已成功完成。
SQL> SELECT * FROM MV_T WHERE ID = 1;
ID NAME TIME
---------- ------------------------------ -------------------
1 T_AB 2009-06-21 00:05:09
SQL> UPDATE T SET NAME = 'A' WHERE ID = 1;
已更新 1 行。
SQL> COMMIT;
提交完成。
SQL> EXEC DBMS_MVIEW.REFRESH('MV_T', 'F')
PL/SQL 過程已成功完成。
SQL> SELECT * FROM MV_T WHERE ID = 1;
ID NAME TIME
---------- ------------------------------ -------------------
1 A 2009-06-21 00:05:09
在這個(gè)例子中建立一個(gè)ON PREBUILT TABLE類型的物化視圖,其中物化視圖的基表比主表要多了一個(gè)字段,并為這個(gè)字段設(shè)置了默認(rèn)值。
物化視圖在完全刷新的時(shí)候會自動(dòng)在這個(gè)字段中寫入默認(rèn)值,但是如果基表進(jìn)行了更新操作,則物化視圖中新增的時(shí)間戳字段并不會在刷新的時(shí)候自動(dòng)更新。
其實(shí)解決這個(gè)問題的方法很簡單,一個(gè)UPDATE觸發(fā)器就可以了:
SQL> CREATE OR REPLACE TRIGGER MV_T
2 BEFORE UPDATE ON MV_T
3 FOR EACH ROW
4 BEGIN
5 :NEW.TIME := SYSDATE;
6 END;
7 /
觸發(fā)器已創(chuàng)建
SQL> UPDATE T SET NAME = 'B' WHERE ID = 1;
已更新 1 行。
SQL> COMMIT;
提交完成。
SQL> SELECT * FROM MV_T WHERE ID = 1;
ID NAME TIME
---------- ------------------------------ -------------------
1 A 2009-06-21 00:05:09
SQL> EXEC DBMS_MVIEW.REFRESH('MV_T', 'F')
PL/SQL 過程已成功完成。
SQL> SELECT * FROM MV_T WHERE ID = 1;
ID NAME TIME
---------- ------------------------------ -------------------
1 B 2009-06-21 00:14:01
只需要處理UPDATE操作就可以了,因?yàn)?span lang="EN-US">DELETE
不涉及到這個(gè)問題,而INSERT操作由于表的時(shí)間戳字段設(shè)置了默認(rèn)值,因此不需要觸發(fā)器進(jìn)行額外的設(shè)置:SQL> INSERT INTO T VALUES (26, 'C');
已創(chuàng)建 1 行。
SQL> EXEC DBMS_MVIEW.REFRESH('MV_T', 'F')
PL/SQL 過程已成功完成。
SQL> SELECT * FROM MV_T WHERE ID = 26;
ID NAME TIME
---------- ------------------------------ -------------------
26 C 2009-06-21 00:14:42