程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 數據庫知識 >> Oracle數據庫 >> Oracle教程 >> PL/SQL編程_觸發器,plsql編程觸發器

PL/SQL編程_觸發器,plsql編程觸發器

編輯:Oracle教程

PL/SQL編程_觸發器,plsql編程觸發器


觸發器是一種特殊的存儲過程,它在創建後就存儲在數據庫中。
觸發器的特殊性在於它是建立在某個具體的表之上的,而且是自動激發執行的,如果用戶在這個表上執行了某個DML操作( UPDATE 、INSERT 、DELETE ),觸發器就被激發執行。
觸發器常用於自動完成一些數據庫的維護工作。
例如,觸發器可以具有以下功能:
·可以對表自動進行復雜的安全性、完整性檢查。
·可以在對表進行DML操作之前或之後進行其他處理。
·進行審計,可以對表上的操作進行跟蹤。
·實現不同節點間數據庫的同步更新。

觸發器的使用
觸發器是依附於某個具體的表的特殊存儲過程,它在某個DML操作的激發下自動執行。
在創建觸發器時應該仔細考慮如它的相關信息。
具體地說,應該考慮以下幾個方面的問題:
1 )觸發器應該建立在哪個表之上。
2 )觸發器應該對什麼樣的DML操作進行相應。
3 )觸發器在指定的DML操作之前激發還是在之後撤發。
4 )對每次DML相應一次,還是對受DML操作影響的每一行數據都響應一次。
在確定了觸發器的實現細節後,現在,就可以創建觸發器了。
創建觸發器的語法格式為:
CREATE [OR REPLACE] TRIGGER 觸發器名
BEFORE | AFTER | INSTEAD OF
DELETE | INSERT | UPDATE [OF 列名]
ON 表名
[FOR EACH ROW [WHEN 條件]]
BEGIN
PL/SQL語句;
END;
在創建觸發器的語法結構中,用方括號限定的部分是可選的,可以根據需要選用。
創建觸發器的命令是CREATE TRIGGER ,根據指定的名字創建一個觸發器。
OR REPLACE子句的作用是如果已經存在同名的觸發器,則刪除它,並重新創建。
觸發器可以是前激發的( BEFORE ),也可以是後激發的( AFTER )。
如果是前激發的,則觸發器在DML語句執行之前激發。
如果是後激發的,則觸發器在DML語句執行之後激發。
用BEFORE關鍵字創建的觸發器是前激發的,用AFTER關鍵字創建的觸發器是後激發的,這兩個關鍵字只能使用其一。
INSTEAD OF子句僅用於視圖上的觸發器。
觸發器可以被任何DML命令激發,包括INSERT 、DELETE和UPDATE 。
如果希望其中的一種、兩種或三種命令能夠激發該觸發器,則可以指定它們之間的任意組合,兩種不同命令之間用OR分開。
如果指定了UPDATE命令,還可以進一步指定當表中的哪個列受到UPDATE命令的影響時激發該觸發器。
當在指定的表上執行指定的DML命令時,將會激發觸發器,觸發器將對這樣的操作進行必要的響應。
觸發器可能對每次單獨的DML操作響應一次,也可能對每次DML操作所影響的每一行數據響應一次。
如果對每次單獨的DML操作響應一次,觸發器執行的次數與受影晌的行數無關,這樣的觸發器叫做語句級觸發器
如果對受影響的每一行數據都響應一次,那麼觸發器執行的次數等於受影響的行數,這樣的觸發器叫做行觸發器
FOR EACH ROW子句的作用是指定創建的觸發器為行觸發器。
如果沒有這樣的子句,則創建的觸發器為語句級觸發器。

由關鍵字BEGIN和END限定的部分是觸發器的代碼,也就是觸發器被激發時所執行的代碼。
代碼的編寫方法與普通PL/SQL塊的編寫方法相同。

在觸發器中可以定義變量,也可以進行異常處理,如果發生異常,就執行相應的異常處理程序。

例如,下面創建的觸發器是為了監視用戶對表EMP中的數據所進行的刪除操作。

如果有這樣的訪問,則打印相應的信息。

CREATE OR REPLACE TRIGGER tri_emp
AFTER DELETE
ON emp
BEGIN
DBMS_OUTPUT.PUT_LINE('正在對表emp進行刪除操作');
END;

從觸發器的執行情況可以看出,無論用戶通過DELETE命令刪除0行、1行或者多行數據,這個觸發器只對每次DELETE操作激發一次,所以這是一個典型的語句級觸發器。
如果一個觸發器不再使用,那麼可以刪除它。

刪除觸發器的語法為:

DROP TRIGGER 觸發器名;

例如,要刪除剛才創建的觸發器tri_emp,使用的語句為:

DROP TRIGGER tri_emp;

觸發器的創建者和數據庫管理員可以使觸發器失效。

觸發器失效後將暫時不起作用,直到再次使它有效。
使觸發器失效的命令格式為:

ALTER TRIGGER 觸發器名 DISABLE;

觸發器失效後只是暫時不起作用,它仍然存在於數據庫中,使用命令可以使它再次起作用。
使觸發器再次有效的命令格式為:

ALTER TRIGGER 觸發器名ENABLE;

例如,下面的兩條命令先使觸發器tri_emp 失效,然後使其再次有效:

ALTER TRIGGER tri_emp DISABLE;

ALTER TRIGGER tri_emp ENABLE;

語句級觸發器

如果一個觸發器在用戶每次進行DML操作時被激發而且執行一次,而不管這個DML操作影響了多少行數據,這個觸發器就是語句級觸發器。
語句級觸發器有前激發和後激發兩種形式。

前激發觸發器是在DML操作執行之前被激發執行,後激發觸發器是在DML操作執行之後被激發執行。
無論是哪種形式,觸發器都將執行一次。
例如,我們創建一個前激發觸發器tri_emp,當用戶對表EMP的DEPTNO列進行UPDATE操
作時該觸發器將被激發。

創建該觸發器的語句為:

CREATE OR REPLACE TRIGGER tri_emp
BEFORE UPDATE OF deptno
ON emp
BEGIN
DBMS_OUTPUT.PUT_LINE('正在對表emp進行修改DEPTNO列操作');
END;

從UPDATE語句的執行結果可以看出,實際受影響的有6行數據,但是觸發器只執行了一次。
實際上不管這條語句影響了一行、兩行還是多行,或者沒有影響任何行,這個觸發器都將在UPDATE語句執行之前被激發執行一次。
再考慮下面的UPDATE語句,相信會對語句級觸發器的執行有更深的理解。
這次我們修改一個根本不存在的部門編號3 。

update emp set deptno=10 WHERE deptno=3;

如果更關心用戶對表所實施的訪問本身,而不是該次訪問影響的數據行數,這時可以在表上創建語句級觸發器。
在觸發器中可以使用三個條件謂詞,這三個謂詞用來判斷當前所執行的操作。

它們是:
INSERTING :如果激發觸發器的操作是INSERT ,則結果為真,否則為假
UPDATING : 如果激發觸發器的操作是UPDATE ,則結果為真,否則為假
DELETING :如果激發觸發器的操作是DELETE ,則結果為真,否則為假
這三個條件謂詞通常作為IF語句的條件,用來判斷用戶當前所進行的操作。
如果要對用戶在表emp上進行的所有DML操作進行監視,可以在這個表上創建一個觸發器,將用戶的所有DML操作作為日志記錄下來。
為此,我們先創建一個表emp_log ,它的結構及各列的意義如下所示。

列      類型     意義

oper_user  char(10)  執行DML操作的用戶

oper_type  char(10)  DML操作的類型

oper_time  char(20)  執行DML操作的時間

然後,在表emp上創建一個後激發的觸發器emp_dml_trg。

只要用戶在表上進行DML操作,這個觸發器就會將執行這個操作的用戶以及操作類型和操作時間記錄在表emp_log 中,而不管這樣的操作影響了多少行數據。

CREATE OR REPLACE TRIGGER emp_dml_trg
AFTER INSERT OR UPDATE OR DELETE
ON emp
DECLARE
dml_type char(10);
BEGIN
if INSERTING then
dml_type := 'INSERT';
elsif UPDATING then
dml_type:='UPDATE';
elsif DELETING then
dml_type:='DELETE';
END if;
INSERT INTO emp_log
VALUES(user,dml_type, to_char(sysdate , 'yyyy-mm-dd hh:mi:ss' ));
END;

如果用戶在表emp上進行了以下DML操作:

UPDATE emp set sal=sal+100;

DELETE FROM emp WHERE deptno=20;

那麼這二個操作的信息都將被記錄在表emp_log 中。

行觸發器 

如果在某個表上創建了一個觸發器,在對這個表進行DML操作時,每影響一行數據,該觸發器都將被激發執行一次,那麼這個觸發器就是行觸發器。
首先看一個非常簡單的觸發器的例子:

CREATE OR REPLACE TRIGGER tri_emp
AFTER DELETE
ON emp
FOR EACH ROW
BEGIN
DBMS_OUTPUT.PUT_LINE('一行已被刪除');
END;

這個觸發器是後觸發的。

如果對表emp進行DELETE操作,將激發這個觸發器的執行。

在創建觸發器時使用了FOR EACH ROW子句,因此這個觸發器是行觸發器,例如,如果執行了以下的DELETE語句:

DELETE FROM emp WHERE deptno=20;

執行結果中的最後一行是SQL*Plus的統計信息,表明有5行受到DELETE語句的影響。

從觸發器執行的輸出信息可以看出,觸發器確實執行了5次。
也就是說,觸發器執行的次數等於受DML操作影響的數據行數。
如果DML操作沒有影響到任何一行數據,那麼觸發器將不執行。

例如,如果要根據一個不存在的deptno列的值從emp表中刪除行:

DELETE FROM emp WHERE deptno=200;

可見,如果DML語句沒有影響到任何行,觸發器將不會執行。
如果更關心DML語句對每行數據的訪問情況,而不是DML操作本身的信息,那麼在表上創建行觸發器更合適。
在創建行觸發器時,可以指定一些條件,這樣只有當特定的數據受到DML語句影響時,觸發器才被激發執行。
創建觸發器時,可以在FOR EACH ROW子句之後使用WHEN子句指定條件。

例如,重新考慮上面的簡單的行觸發器。

如果只對部門30進行監視,只有當從表emp 中刪除deptno列值為30的行時,才激發觸發器。
這個觸發器可以這樣創建:

CREATE OR REPLACE TRIGGER tri_emp
AFTER DELETE
ON emp
FOR EACH ROW WHEN (old.deptno=30)
BEGIN
DBMS_OUTPUT.PUT_LINE('一行已被刪除');
END;

如果執行兩次DELETE操作,分別刪除deptno 為30和20的行:

DELETE FROM emp WHERE deptno=30;

DELETE FROM emp WHERE deptno=20;

可見,當從表emp 中刪除部門30的員工時,觸發器被激發,而刪除其他部門的員工時,沒有激發觸發器。
在行觸發器中,同樣可以使用條件謂詞INSERT 、UPDATING和DELETING ,以判斷當前所進行的DML操作。
行觸發器通常用於對用戶的DML操作進行合法性檢查,使得用戶修改數據的操作必須按照一定的規則進行。

為了能夠比較修改前和修改後的數據,在觸發器的可執行代碼中,可以使用兩個關聯行NEW和OLD 。
它們分別表示觸發器被激發時,當前行的原數據和新數據。
NEW表示修改後的行,通過NEW可以引用新行中的各個列的值,如NEW.ename 。

OLD表示修改前的行,通過OLD可以引用原來的各個列的值,如OLD.ename 。
對於UPDATE命令, OLD表示原來的行, NEW表示修改後的行。

對於INSERT 命令, OLD沒有意義, NEW表示新寫人的一行。
對於DELETE命令, NEW沒有意義, OLD表示被刪除的一行。
在觸發器的可執行代碼中,如果要通過OLD和NEW引用某個列的值,要在前面加上“:”在其他地方,則不用使用“:”。
現在,我們要創建一個比較復雜的觸發器,這個觸發器對表emp上的DML操作進行監視。
這個觸發器需要滿足以下要求:
1 )在DML操作執行之前進行合法性檢查。
2 )如果要從表emp 中刪除一行數據,不能刪除部門30的員工。

如果是其他部門的員工,則刪除這行數據,並把這一行數據在另一個表中進行備份。
3 )如果要寫入一行數據,要保證這個員工的工資高於1000 。
4 )如果修改表emp 的sa列 ,應保證新工資比原工資要高,並把員工的工資變化情況記錄在另一個表中。
為此,我們需創建兩個表,一個是del_action ,用來保存從表emp 中刪除的行,它的結構與表emp相同。
可以使用下面的語句創建一個空表del_action :

CREATE TABLE del_action
AS
SELECT * FROM emp
WHERE deptno=0;

第二個表是update_action ,用來記錄員工工資的變化情況。

CREATE TABLE update_action
(
empno NUMBER(4),
ename VARCHAR2(10),
old_sal NUMBER(7,2),
new_sal NUMBER(7,2),
update_time CHAR(20),
oper_user CHAR(10)
);

現在我們可以根據上面的要求創建觸發器了。

創建這個觸發器的語句為:

if DELET 工NG then
if :old.deptno=30 then
dbms_output.put line (’部門’ I I : old. deptno I I '的員工不得刪除’};
else
INSERT INTO del_action VALUES(
: old. 田npn口,: old.ename,:old.job,:old.呵r, :old.hiredate, :old.sal, :old.comm, :old.deptno);
END if;
END if;
END;



 

 

 

 

 



 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved