物化视图的刷新其实和普通的SQL执行没有什么本质的区别,因此也可以通过在物化视图上创建触发器的方式,对刷新操作进行定制。



正好前两天有人在BLOG上问我,如果在物化视图添加一个时间戳列,并在物化视图更新的时候,自动维护这个列。其实很简单,通过触发器就可以达到这个目的:

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


表已创建。


SQL> INSERT INTO T SELECT ROWNUM, TNAME FROM TAB;


已创建25行。


SQL> COMMIT;


提交完成。


SQL> CREATE MATERIALIZED VIEW LOG ON T;


实体化视图日志已创建。


SQL> CREATE TABLE MV_T (ID NUMBER, NAME VARCHAR2(30), TIME DATE DEFAULT SYSDATE);


表已创建。


SQL> CREATE MATERIALIZED VIEW MV_T ON PREBUILT TABLE REFRESH FAST


 2  AS SELECT * FROM T;


实体化视图已创建。


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


在这个例子中建立一个ON PREBUILT TABLE类型的物化视图,其中物化视图的基表比主表要多了一个字段,并为这个字段设置了默认值。

物化视图在完全刷新的时候会自动在这个字段中写入默认值,但是如果基表进行了更新操作,则物化视图中新增的时间戳字段并不会在刷新的时候自动更新。

其实解决这个问题的方法很简单,一个UPDATE触发器就可以了:

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  /


触发器已创建


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操作就可以了,因为DELETE不涉及到这个问题,而INSERT操作由于表的时间戳字段设置了默认值,因此不需要触发器进行额外的设置:

SQL> INSERT INTO T VALUES (26, 'C');


已创建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



oracle视频教程请关注:http://u.youku.com/user_video/id_UMzAzMjkxMjE2.html