Oracle PL/SQL進階編程(第十二彈:替代觸發器)

DML觸發器只能應用在表上。而替代觸發器只能定義在視圖上。當腰對一個不能進行修改的視圖進行數據的修改時,或者要修改視圖中的某個嵌套表時,可以使用替代觸發器。

替代觸發器的作用

提到觸發器,又稱爲INSTEAD OF觸發器,它會替代原來的數據操作語句的執行,更改爲使用在觸發器中定義的語句來執行數據操作。

一些簡單的單表視圖,可以直接INSERT、UPDATE,但如果要對複雜的視圖進行INSERT、UPDATE,可以通過替代觸發器,將這些DML語句對視圖的更改替換爲對基表的 DML操作。
要注意:
- 替代觸發器只能用於視圖
- 當建立替代觸發器時,不能指定BEFORE和AFTER選項。
- 當建立替代觸發器時,視圖沒有指定WITH CHECK OPTION選項。
- 當建立替代觸發器時,必須指定FOR EACH ROW方法。

定義替代觸發器

替代觸發器的定義語法和DML觸發器相似,不同之處在於DML觸發器中用BEFORE和AFTER指定觸發時機的地方改爲了INSTEAD OF,語法如下:

CREATE [OR REPLACE] TRIGGER [schema.]trigger
INSTEAD OF verb_list ON [schema.]view_name
[REFERENCING {OLD AS old} | {NEW AS new} | {PARENT AS parent}]
FOR EACH ROW
[WHEN (condition)]
plsql_block | call_procedure_statement

下面的代碼創建了一個視圖和一個替代觸發器:

--創建視圖emp_dept視圖
CREATE OR REPLACE VIEW scott.emp_dept (empno,
                                       ename,
                                       job,
                                       mgr,
                                       hiredate,
                                       sal,
                                       comm,
                                       deptno,
                                       dname,
                                       loc
                                      )
AS
   SELECT emp.empno, emp.ename, emp.job, emp.mgr, emp.hiredate, emp.sal,
          emp.comm, emp.deptno, dept.dname, dept.loc
     FROM dept, emp
    WHERE ((dept.deptno = emp.deptno));

CREATE OR REPLACE TRIGGER t_emp_dept
   INSTEAD OF UPDATE OR INSERT OR DELETE ON emp_dept   
   REFERENCING NEW AS n OLD AS o      --指定謂詞別名
   FOR EACH ROW                       --行級觸發器
DECLARE
   v_counter   INT;                   --計數器統計變量
BEGIN
   SELECT COUNT (*)
     INTO v_counter
     FROM dept
    WHERE deptno = :o.deptno;           --判斷在dept表中是否存在相應的記錄   
   IF v_counter >0                      --如果存在,則更新dept表
   THEN
      CASE 
      WHEN UPDATING THEN
         UPDATE dept SET dname=:n.dname,loc=:n.loc WHERE deptno=:o.deptno;
      WHEN INSERTING THEN
         INSERT INTO dept VALUES (:n.deptno, :n.dname, :n.loc); 
      WHEN DELETING THEN
         DELETE FROM dept WHERE deptno=:o.deptno;     --刪除dept表      
      END CASE;
   END IF;
   SELECT COUNT (*)                    --判斷emp表中是否存在員工記錄
     INTO v_counter
     FROM emp
    WHERE empno = :n.empno;
   IF v_counter > 0                    --如果存在,則更新emp表
   THEN
      CASE 
      WHEN UPDATING THEN
         UPDATE emp SET ename=:n.ename,job=:n.job,mgr=:n.mgr, hiredate=:n.hiredate,sal=:n.sal,
                   comm=:n.comm, deptno=:n.deptno WHERE empno=:o.empno;    
      WHEN INSERTING THEN
         INSERT INTO emp
                  (empno, ename, job, mgr, hiredate, sal,
                   comm, deptno
                  )
           VALUES (:n.empno, :n.ename, :n.job, :n.mgr, :n.hiredate, :n.sal,
                   :n.comm, :n.deptno
                  );
      WHEN DELETING THEN
         DELETE FROM emp WHERE empno=:o.empno;   
      END CASE;       
   END IF;
END; 

嵌套表替代觸發器

下面的代碼創建了一個具有嵌套表數據的視圖:

--創建用於嵌套表的對象類型
CREATE OR REPLACE TYPE emp_obj AS OBJECT(
   empno NUMBER(4),
   ename VARCHAR2(10),
   job VARCHAR2(10),
   mgr NUMBER(4),
   hiredate DATE,
   sal NUMBER(7,2),
   comm NUMBER(7,2),
   deptno NUMBER(2)
);
--創建嵌套表類型
CREATE OR REPLACE TYPE emp_tab_type AS TABLE OF emp_obj;
--創建嵌套表視圖,MULTISET必須與CAST一起使用
CREATE OR REPLACE VIEW dept_emp_view AS
   SELECT deptno,dname,loc,
   CAST(MULTISET(SELECT * FROM emp WHERE deptno=dept.deptno) AS emp_tab_type) emplst
   FROM dept;

可以看到,代碼中使用CAST AS語句和MULTISET將對emp表特定員工編號的查詢轉換成了emp_tab_typ類型 的嵌套表,現在視圖dept_emp_view具有了一個嵌套表列。
爲了在嵌套表視圖中執行DML操作,我們來創建一個嵌套表替代觸發器:

CREATE OR REPLACE TRIGGER dept_emp_innerview
   INSTEAD OF INSERT
   ON NESTED TABLE emplst OF dept_emp_view                       --創建嵌套表替代觸發器
BEGIN
   INSERT INTO emp                                             --插入子表記錄
               (deptno, empno, ename, job, mgr,
                hiredate, sal, comm
               )
        VALUES (:PARENT.deptno, :NEW.empno, :NEW.ename, :NEW.job, :NEW.mgr,
                :NEW.hiredate, :NEW.sal, :NEW.comm
               );
END;

這樣,我們就可以用以下DML向dept_emp_view視圖的嵌套表插入一行記錄:

INSERT INTO TABLE (SELECT emplst
                     FROM dept_emp_view
                    WHERE deptno = 10)
     VALUES (8003, '四爺', '皇上', NULL, SYSDATE, 5000, 500, 10);

嵌套表替代觸發器與普通的 替代觸發器的創建方式基本相同,但是有如下兩個基本的區別:
- 嵌套表使用ON NESTED TABLE 嵌套表列 OF 嵌套表視圖這種定義方式
- PARENT謂詞在嵌套表替代觸發器中具有值,指向包含嵌套表的視圖的父項記錄。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章