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謂詞在嵌套表替代觸發器中具有值,指向包含嵌套表的視圖的父項記錄。