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

Oracle 觸發器進階:REFERENCING、WHEN、觸發器謂詞與 FOLLOWS 控制

     編輯:Oracle 教學

Oracle 觸發器進階:REFERENCING、WHEN、觸發器謂詞與 FOLLOWS 控制

掌握觸發器進階特性,能編寫更清晰、可控、高性能的觸發邏輯。本文深入講解 REFERENCING 別名機制、WHEN 條件過濾、三大觸發器謂詞(INSERTING/UPDATING/DELETING)及 FOLLOWS 執行順序控制。

一、REFERENCING 子句:為 :OLD/:NEW 起別名

當觸發器邏輯複雜,直接使用 :OLD.col、:NEW.col 可讀性差時,可定義別名:

CREATE OR REPLACE TRIGGER myempaddsal_trigger
BEFORE UPDATE ON myemp
REFERENCING OLD AS myemp_old NEW AS myemp_new
FOR EACH ROW
DECLARE
BEGIN
  IF ABS((:myemp_new.sal - :myemp_old.sal) / :myemp_old.sal) > 0.1 THEN
    RAISE_APPLICATION_ERROR(-20005, '工資最大漲幅不能超過 10%');
  END IF;
END;

此處 :myemp_new.sal 等價於 :NEW.sal,語義更清晰。

二、WHEN 子句:行級觸發器的前置過濾器

WHEN 子句在觸發器體執行前評估,條件為 FALSE 則跳過觸發器體,減少開銷。注意:WHEN 中引用 :OLD/:NEW 時可省略冒號。

示例 1:禁止工資為 0 的新員工入職

CREATE OR REPLACE TRIGGER myemptestadd1
BEFORE INSERT ON myemp
FOR EACH ROW
WHEN (NEW.sal = 0)
DECLARE
BEGIN
  RAISE_APPLICATION_ERROR(-20003, :NEW.empno || ' 的工資為 0,不合規定!');
END;

示例 2:工資只能漲不能降

CREATE OR REPLACE TRIGGER myemptestadd1
BEFORE UPDATE ON myemp
FOR EACH ROW
WHEN (NEW.sal < OLD.sal)
DECLARE
BEGIN
  RAISE_APPLICATION_ERROR(-20003, :OLD.empno || ' 的工資只能漲不能降!');
END;

三、觸發器謂詞:單一觸發器識別多種 DML 事件

在 FOR EACH ROW 觸發器中,三個布爾謂詞僅有一個為 TRUE:

謂詞觸發事件為返回
INSERTINGINSERTTRUE
UPDATINGUPDATETRUE
DELETINGDELETETRUE

示例:統一日志觸發器記錄 dept 表操作

-- 日志表
CREATE TABLE deptlog (
  logid NUMBER PRIMARY KEY,
  type  VARCHAR2(20) NOT NULL,
  deptno NUMBER(2),
  logdate DATE,
  dname VARCHAR2(14),
  loc   VARCHAR2(13)
);
CREATE SEQUENCE deptlog_seq;

-- 觸發器
CREATE OR REPLACE TRIGGER dept_trigger
BEFORE INSERT OR UPDATE OR DELETE ON dept
FOR EACH ROW
BEGIN
  IF INSERTING THEN
    INSERT INTO deptlog VALUES (deptlog_seq.NEXTVAL, 'INSERT', :NEW.deptno, SYSDATE, :NEW.dname, :NEW.loc);
  ELSIF UPDATING THEN
    INSERT INTO deptlog VALUES (deptlog_seq.NEXTVAL, 'UPDATE', :NEW.deptno, SYSDATE, :NEW.dname, :NEW.loc);
  ELSIF DELETING THEN
    INSERT INTO deptlog VALUES (deptlog_seq.NEXTVAL, 'DELETE', :OLD.deptno, SYSDATE, :OLD.dname, :OLD.loc);
  END IF;
END;

四、FOLLOWS 子句:指定同類觸發器執行順序(11g+)

同一表、同一時機、同一粒度的多個觸發器,默認執行順序不確定。使用 FOLLOWS 顯式聲明順序:

-- 觸發器 1
CREATE OR REPLACE TRIGGER dept1
BEFORE INSERT OR UPDATE OR DELETE ON dept
FOR EACH ROW
BEGIN
  DBMS_OUTPUT.PUT_LINE('執行第 1 個觸發器 dept1');
END;

-- 觸發器 2:跟隨 dept1
CREATE OR REPLACE TRIGGER dept2
BEFORE INSERT OR UPDATE OR DELETE ON dept
FOR EACH ROW FOLLOWS dept1
BEGIN
  DBMS_OUTPUT.PUT_LINE('執行第 2 個觸發器 dept2');
END;

-- 觸發器 3:跟隨 dept2
CREATE OR REPLACE TRIGGER dept3
BEFORE INSERT OR UPDATE OR DELETE ON dept
FOR EACH ROW FOLLOWS dept2
BEGIN
  DBMS_OUTPUT.PUT_LINE('執行第 3 個觸發器 dept3');
END;

測試結果: 任意 DML 操作均按 1→2→3 順序輸出。

最佳實踐總結

  1. 複雜觸發器使用 REFERENCING 提升可維護性。
  2. 行級觸發器盡量用 WHEN 過濾無效觸發,降低開銷。
  3. 合併同類日志觸發器,用 INSERTING/UPDATING/DELETING 分支處理。
  4. 多觸發器協作時,必須用 FOLLOWS 固化順序,避免升級/遷移後順序變更導致邏輯錯誤。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved