首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> Oracle 資料庫 >> Oracle 資料庫基礎

Oracle 觸發器完整指南:分類、編寫、:NEW/:OLD、複合觸發器與管理實務

     編輯:Oracle 資料庫基礎

觸發器核心概念

儲存於資料庫的 PL/SQL 區塊,**由事件自動觸發執行**,使用者無法直接 CALL。適用於:稽核日誌、衍生欄位維護、跨表同步、安全防護、資料完整性補強。

觸發事件類型

類別事件
DMLINSERT、UPDATE、DELETE
DDLCREATE、ALTER、DROP
資料庫系統STARTUP、SHUTDOWN、SERVERERROR
使用者LOGON、LOGOFF、DDL/DML 執行

觸發器三要素

  1. 觸發事件/語句:上表任一事件。
  2. 觸發限制:WHEN (condition) 布林運算式,FALSE/NULL 時跳過執行。
  3. 觸發動作:PL/SQL 區塊或 CALL procedure。

六大分類與適用場景

分類觸發時機執行次數典型用途
列級 BEFORE每列變更前N 列 = N 次驗證/修正新值、自動填充衍生欄位、防刪保護
列級 AFTER每列變更後N 列 = N 次稽核日誌、跨表同步、發送通知
語句級 BEFORE整句執行前1 次/句全域暫存表初始化、權限檢查
語句級 AFTER整句執行後1 次/句統計更新、批次日誌彙總
複合觸發器4 時間點合一視邏輯需同時存取 BEFORE/AFTER 狀態、避免 mutating table 錯誤
INSTEAD OF取代 DMLN 列 = N 次不可更新視圖的寫入轉導基礎表

編寫關鍵::NEW / :OLD 伪記錄

操作:OLD:NEW
INSERT無 (NULL)新值
UPDATE舊值新值
DELETE舊值無 (NULL)

**僅列級觸發器可用**。語句級觸發器無 :NEW/:OLD。

判斷觸發 DML 類型

IF INSERTING THEN ... ELSIF UPDATING THEN ... ELSIF DELETING THEN ... END IF;

實戰範例

列級 BEFORE:自動維護修改時間

CREATE OR REPLACE TRIGGER trg_emp_biu
BEFORE INSERT OR UPDATE ON emp
FOR EACH ROW
BEGIN
  :NEW.modified_dt := SYSDATE;
  :NEW.modified_by := USER;
END;

列級 AFTER:稽核日誌

CREATE OR REPLACE TRIGGER trg_emp_audit
AFTER INSERT OR UPDATE OR DELETE ON emp
FOR EACH ROW
DECLARE
  v_action VARCHAR2(10);
BEGIN
  IF INSERTING THEN v_action := 'INS';
  ELSIF UPDATING THEN v_action := 'UPD';
  ELSE v_action := 'DEL';
  END IF;
  INSERT INTO emp_audit (emp_id, action, old_name, new_name, action_dt, action_by)
  VALUES (NVL(:NEW.emp_id, :OLD.emp_id), v_action, :OLD.ename, :NEW.ename, SYSDATE, USER);
END;

複合觸發器:解決 Mutating Table (ORA-04091)

CREATE OR REPLACE TRIGGER trg_compound
FOR UPDATE OF salary ON emp
COMPOUND TRIGGER
  -- 1. 語句前
  BEFORE STATEMENT IS BEGIN NULL; END BEFORE STATEMENT;
  -- 2. 每列前
  BEFORE EACH ROW IS BEGIN NULL; END BEFORE EACH ROW;
  -- 3. 每列後(可安全查詢同表)
  AFTER EACH ROW IS
  BEGIN
    -- 此處可 SELECT emp 而不報 ORA-04091
    NULL;
  END AFTER EACH ROW;
  -- 4. 語句後
  AFTER STATEMENT IS BEGIN NULL; END AFTER STATEMENT;
END;

INSTEAD OF:視圖寫入轉導

CREATE VIEW v_emp_dept AS
SELECT e.emp_id, e.ename, d.dname FROM emp e JOIN dept d ON e.deptno = d.deptno;

CREATE OR REPLACE TRIGGER trg_v_emp_dept_iof
INSTEAD OF INSERT OR UPDATE ON v_emp_dept
FOR EACH ROW
BEGIN
  IF INSERTING THEN
    INSERT INTO emp (emp_id, ename, deptno) VALUES (:NEW.emp_id, :NEW.ename, :NEW.deptno);
  ELSE
    UPDATE emp SET ename = :NEW.ename, deptno = :NEW.deptno WHERE emp_id = :OLD.emp_id;
  END IF;
END;

觸發器管理

操作SQL
停用ALTER TRIGGER trg_name DISABLE;
啟用ALTER TRIGGER trg_name ENABLE;
刪除DROP TRIGGER trg_name;
查看狀態SELECT trigger_name, status FROM user_triggers;

避坑指南

  1. Mutating Table (ORA-04091): 列級觸發器中查詢/修改同一觸發表 → 改用複合觸發器 AFTER EACH ROW 或語句級觸發器。
  2. 遞迴觸發: 觸發器動作再次觸發同觸發器 → 使用包變數標記 pkg.flag 防重入。
  3. 效能: 大批次 DML 觸發列級觸發器極慢 → 改語句級、或暫停觸發器 ALTER TRIGGER ... DISABLE 批次跑完再啟用。
  4. 隱蔽邏輯: 觸發器在背景執行,除錯困難 → 關鍵邏輯改用存儲過程顯式呼叫,觸發器僅做薄封裝。

總結

觸發器 = 事件驅動的自動化 PL/SQL。掌握 **列級 vs 語句級、BEFORE vs AFTER、:NEW/:OLD、複合觸發器解決 Mutating、INSTEAD OF 處理視圖寫入** 六大核心,並嚴守「慎用、可追蹤、可停用」三原則,讓觸發器成為資料完整性守門員而非維護噩夢。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved