一、觸發器
觸發器是一個數據庫對象,是一個特殊的過程,當特定的時間發生時隱式地執行。比如在一個表中發生插入、更新或刪除的時間,或者 CREATE、ALTER 這樣的數據定義語句執行時,觸發器會隱式執行。當一些用戶行為或數據庫系統行為發生時(例如用戶登陸或數據庫關閉時),觸發器也會隱式執行。
觸發器組成部分:
觸發時間 觸發器體執行的時機 BEFORE、AFTER
觸發事件 那類具體的數據操縱語句 INSERT、UPDATE、DELETE、CREATE、ALTER
觸發器類型 觸發器體執行次數 Statement、Row
觸發器體 觸發器執行的具體操作 PL/SQL 塊
【注意】:
當觸發器類型為 Statement 時,稱為語句觸發器,觸發器體對於觸發事件只執行一次,及時沒有行受到影響。
當類型為 Row 時,稱為行觸發器,觸發器體對受出發時間影響的每行執行一次。
二、創建和測試語句觸發器
1.語法形式
CREATE [OR REPLACE] TRIGGER tname timing event1[OR event2 OR event3] ON table trigger_body
其中,tname 表示觸發器名字,timing 表示出發時間,event1、event2、event3 表示觸發事件,table 表示針對的表,trigger_body 表示觸發器體。
2.語句觸發器示例
例如需要創建這樣一個觸發器,只能在周一到周五的 9:00 到 18:00 才可以針對部門表 departments 進行 DML 操作。
create or replace trigger dml_depts_time before --在觸發事件發生前 insert or update or delete --觸發事件為增刪改 on departments --對表departments begin --執行觸發器體 if to_char(sysdate,'HH24:MI') not between '08:00' and '18:00' or to_char(sysdate,'DY') in ('SAT','SUN') then raise_application_error(-20205,'You may only make changes during normal office hours'); end if; end dml_depts_time
需要說明的是,上面創建觸發器的 SQL 語句中, RAISE_APPLICATION_ERROR 是一個內建過程,它返回一個錯誤給用戶,並導致 PL/SQL 塊失敗。當一個數據庫觸發器失敗時,觸發語句會自動回滾。
編譯該觸發器,通過 PL/SQL Dev 查看 Triggers 文件夾,可以看到剛編譯的 dml_depts_time 觸發器。為了驗證觸發器是否可以使用,選擇在非工作時間,執行下面的 SQL 語句更新部門表的數據。
update departments set department_name = 'IT GROUP' where department_id = 60
結果
三、創建和測試行觸發器
1.語法形式
CREATE [OR REPLACE] TRIGGER tname timing event1 [OR event2 OR event3] ON table [REFERENCING OLD AS old|NEW AS new] FOR EACH ROW [WHEN(condition)] trigger_body
2.行觸發器示例
例如需要創建一個行觸發器,當更改了雇員表中某行的職位編號字段或部門編號字段后,自動在職位變遷表 job_history 中增加一行記錄,記錄該雇員的職位(包括部門)變遷情況。創建行觸發器的 SQL 語句如下:
create or replace trigger update_job_history after -- 在觸發事件發生后 update of job_id,department_id -- 觸發事件是修改職位或部門 on employees --對表employ for each row -- 對每行 begin --執行觸發器體 insert into job_history(employee_id, start_date, end_date, job_id, department_id) values (:old.employee_id,:old.hire_date,sysdate,:old.job_id,:old.department_id); end;
編譯該觸發器。為了驗證該觸發器是否起作用,執行下面的 SQL 語句(更新兩行)並提交食物,打開職位變遷表 job_history , 自動增加了兩行記錄。
update employees set department_id = 90 where employee_id in (106,107) select * from hr.job_history
四、小題
1.不允許刪除編號為7369的員工;
create or replace trigger nodelete_emp before delete on scott.emp for each row begin if :old.empno = 7369 then -- NEW 或 OLD 引用,不允許在表級觸發器中 raise_application_error(-20006,'you can not delete the info .'); end if ; end ; delete emp where empno = 7369;
結果
2.使用觸發器實現主鍵自增長;
create sequence seq -- 創建序列 increment by 1 -- 步長為1 start with 20 -- 初始值為 20 nomaxvalue -- 無最大值 nocycle -- 不循環、 CREATE OR REPLACE TRIGGER add_auto_pk --創建自動增長 觸發器 BEFORE INSERT ON scott.emp FOR EACH ROW DECLARE v_emp_no NUMBER(4); BEGIN SELECT seq3.nextval INTO v_emp_no FROM dual; :new.empno := v_emp_no; END;