1. 程式人生 > >oracle 觸發器的種類和觸發事件,DML觸發器,DDL事件觸發器,替代觸發器,檢視觸發器,...

oracle 觸發器的種類和觸發事件,DML觸發器,DDL事件觸發器,替代觸發器,檢視觸發器,...

轉載:http://heisetoufa.iteye.com/blog/367314

觸發器的種類和觸發事件
觸發器必須由事件才能觸發。觸發器的觸發事件分可為3類,分別是DML事件、DDL事件和資料庫事件。
每類事件包含若干個事件,如下所示。資料庫的事件是具體的,在建立觸發器時要指明觸發的事件。
種  類 關 鍵 字 含    義

Sql程式碼  收藏程式碼
  1. DML事件(3種)   INSERT  在表或檢視中插入資料時觸發  
  2.     UPDATE  修改表或檢視中的資料時觸發  
  3.     DELETE  在刪除表或檢視中的資料時觸發  
  4. DDL事件(3種)   CREATE  在建立新物件時觸發  
  5.     ALTER   修改資料庫或資料庫物件時觸發  
  6.     DROP    刪除物件時觸發  
  7. 資料庫事件(5種)   STARTUP 資料開啟時觸發  
  8.     SHUTDOWN    在使用NORMAL或IMMEDIATE選項關閉資料庫時觸發  
  9.     LOGON   當用戶連線到資料庫並建立會話時觸發  
  10.     LOGOFF  當一個會話從資料庫中斷開時觸發  
  11.     SERVERERROR 發生伺服器錯誤時觸發  


觸發器的型別可劃分為4種:資料操縱語言(DML)觸發器、替代(INSTEAD OF)觸發器、資料定義語言(DDL)觸發器和資料庫事件觸發器。
各類觸發器的作用如下所示。

Sql程式碼  收藏程式碼
  1. 種  類    簡  稱    作    用  
  2. 資料操縱語言觸發器   DML觸發器  建立在表上,由DML事件引發的觸發器  
  3. 替代觸發器   INSTEADOF觸發器   建立在檢視上,用來替換對檢視進行的插入、刪除和修改操作  
  4. 資料定義語言觸發器   DDL觸發器  定義在模式上,觸發事件是資料庫物件的建立和修改  
  5. 資料庫事件觸發器    —   定義在整個資料庫或模式上,觸發事件是資料庫事件  


DML觸發器的要點
DML觸發器是定義在表上的觸發器,由DML事件引發。編寫DML觸發器的要素是:
* 確定觸發的表,即在其上定義觸發器的表。
* 確定觸發的事件,DML觸發器的觸發事件有INSERT、UPDATE和DELETE三種,說明見下。
* 確定觸發時間。觸發的時間有BEFORE和AFTER兩種,分別表示觸發動作發生在DML語句執行之前和語句執行之後。
* 確定觸發級別,有語句級觸發器和行級觸發器兩種。語句級觸發器表示SQL語句只觸發一次觸發器,行級觸發器表示SQL語句影響的每一行都要觸發一次。
由於在同一個表上可以定義多個DML觸發器,因此觸發器本身和引發觸發器的SQL語句在執行的順序上有先後的關係。它們的順序是:
* 如果存在語句級BEFORE觸發器,則先執行一次語句級BEFORE觸發器。
* 在SQL語句的執行過程中,如果存在行級BEFORE觸發器,則SQL語句在對每一行操作之前,都要先執行一次行級BEFORE觸發器,然後才對行進行操作。如果存在行級AFTER觸發器,則SQL語句在對每一行操作之後,都要再執行一次行級AFTER觸發器。
* 如果存在語句級AFTER觸發器,則在SQL語句執行完畢後,要最後執行一次語句級AFTER觸發器。
DML觸發器還有一些具體的問題,說明如下:
* 如果有多個觸發器被定義成為相同時間、相同事件觸發,且最後定義的觸發器是有效的,則最後定義的觸發器被觸發,其他觸發器不執行。
* 一個觸發器可由多個不同的DML操作觸發。在觸發器中,可用INSERTING、DELETING、UPDATING謂詞來區別不同的DML操作。這些謂詞可以在IF分支條件語句中作為判斷條件來使用。
* 在行級觸發器中,用:new 和:old(稱為偽記錄)來訪問資料變更前後的值。但要注意,INSERT語句插入一條新記錄,所以沒有:old記錄,而DELETE語句刪除掉一條已經 存在的記錄,所以沒有:new記錄。UPDATE語句既有:old記錄,也有:new記錄,分別代表修改前後的記錄。引用具體的某一列的值的方法是:
       

ld.欄位名或:new.欄位名
* 觸發器體內禁止使用COMMIT、ROLLBACK、SAVEPOINT語句,也禁止直接或間接地呼叫含有上述語句的儲存過程。
定義一個觸發器時要考慮上述多種情況,並根據具體的需要來決定觸發器的種類。
DML觸發器的建立
建立DML觸發器需要CREATE TRIGGER系統許可權。建立DML觸發器的語法如下:
CREATE [OR REPLACE] TRIGGER 觸發器名
{BEFORE|AFTER|INSTEAD OF} 觸發事件1 [OR 觸發事件2...]
ON 表名
WHEN 觸發條件
[FOR EACH ROW]
DECLARE
宣告部分
BEGIN
主體部分
END;
其中:
OR REPLACE:表示如果存在同名觸發器,則覆蓋原有同名觸發器。
BEFORE、AFTER和INSTEAD OF:說明觸發器的型別。
WHEN 觸發條件:表示當該條件滿足時,觸發器才能執行。
觸發事件:指INSERT、DELETE或UPDATE事件,事件可以並行出現,中間用OR連線。
對於UPDATE事件,還可以用以下形式表示對某些列的修改會引起觸發器的動作:
UPDATE OF 列名1,列名2...
ON 表名:表示為哪一個表建立觸發器。
FOR EACH ROW:表示觸發器為行級觸發器,省略則為語句級觸發器。
觸發器的建立者或具有DROP ANY TIRGGER系統許可權的人才能刪除觸發器。刪除觸發器的語法如下:
DROP TIRGGER 觸發器名
可以通過命令設定觸發器的可用狀態,使其暫時關閉或重新開啟,即當觸發器暫時不用時,可以將其置成無效狀態,在使用時重新開啟。該命令語法如下:
ALTER TRIGGER 觸發器名 {DISABLE|ENABLE}
其中,DISABLE表示使觸發器失效,ENABLE表示使觸發器生效。
同儲存過程類似,觸發器可以用SHOW ERRORS 檢查編譯錯誤。
行級觸發器的應用
在行級觸發器中,SQL語句影響的每一行都會觸發一次觸發器,所以行級觸發器往往用在對錶的每一行的操作進行控制的場合。若在觸發器定義中出現FOR EACH ROW子句,則為語句級觸發器。
【訓練1】  建立包含插入、刪除、修改多種觸發事件的觸發器DML_LOG,對EMP表的操作進行記錄。用INSERTING、DELETING、UPDATING謂詞來區別不同的DML操作。
在建立觸發器之前,需要先建立事件記錄表LOGS,該表用來對操作進行記錄。該表的欄位含義解釋如下:
LOG_ID:操作記錄的編號,數值型,它是該表的主鍵,由序列自動生成。
LOG_TABLE:進行操作的表名,字元型,非空,該表設計成可以由多個觸發器共享使用。比如我們可以為dept表建立類似的觸發器,同樣將操作記錄到該表。
LOG_DML:操作的動作,即INSERT、DELETE或UPDATE三種之一。
LOG_KEY_ID:操作時表的主鍵值,數值型。之所以記錄表的主鍵,是因為主鍵是表的記錄的惟一標識,可以識別是對哪一條記錄進行了操作。對於emp表,主鍵是empno。
LOG_DATE:操作的日期,日期型,取當前的系統時間。
LOG_USER:操作者,字元型,取當時的操作者賬戶名。比如登入SCOTT賬戶進行操作,在該欄位中,記錄賬戶名為SCOTT。
步驟1:在SQL*Plus中登入STUDENT賬戶,建立如下的記錄表LOGS:

Sql程式碼  收藏程式碼
  1. CREATETABLE logs(  
  2.         LOG_ID NUMBER(10) PRIMARYKEY,  
  3.         LOG_TABLE VARCHAR2(10) NOTNULL,  
  4.         LOG_DML VARCHAR2(10),  
  5.         LOG_KEY_ID NUMBER(10),  
  6.         LOG_DATE DATE,  
  7.         LOG_USER VARCHAR2(15)  
  8.         );  


執行結果:

Sql程式碼  收藏程式碼
  1. 表已建立。  


步驟2:建立一個LOGS表的主鍵序列LOGS_ID_SEQ:

Sql程式碼  收藏程式碼
  1. CREATESEQUENCE logs_id_squ INCREMENT BY 1   
  2.         START WITH 1 MAXVALUE 9999999 NOCYCLE NOCACHE;  


執行結果:

Sql程式碼  收藏程式碼
  1. 序列已建立。  


步驟3:建立和編譯以下觸發器:

Sql程式碼  收藏程式碼
  1. CREATEORREPLACETRIGGER DML_LOG  
  2.         BEFORE --觸發時間為操作前
  3.         DELETEORINSERTORUPDATE-- 由三種事件觸發
  4.         ON emp  
  5.         FOR EACH ROW -- 行級觸發器
  6.         BEGIN
  7. IF INSERTING THEN
  8.         INSERTINTO logs        VALUES(logs_id_squ.NEXTVAL,'EMP','INSERT',:new.empno,SYSDATE,USER);  
  9.          ELSIF DELETING THEN
  10.          INSERTINTO logs       VALUES(logs_id_squ.NEXTVAL,'EMP','DELETE',:old.empno,SYSDATE,USER);  
  11.          ELSE
  12.              INSERTINTO logs       VALUES(logs_id_squ.NEXTVAL,'EMP','UPDATE',:new.empno,SYSDATE,USER);  
  13.         END IF;  
  14.         END;  


執行結果:
觸發器已建立
步驟4:在EMP表中插入記錄:

Sql程式碼  收藏程式碼
  1. INSERTINTO emp(empno,ename,job,sal) VALUES(8001,'MARY','CLERK',1000);  
  2.         COMMIT;  


執行結果:

Sql程式碼  收藏程式碼
  1. 已建立1行。  
  2.         提交完成。  


步驟5:檢查LOGS表中記錄的資訊:

Sql程式碼  收藏程式碼
  1. SELECT * FROM LOGS;  


執行結果為:
   

Sql程式碼  收藏程式碼
  1. LOG_ID LOG_TABLE  LOG_DML    LOG_KEY_ID LOG_DATE   LOG_USER  
  2.         ----------------- ----------------- ------------------ ----------------------- ---------------- -------------------
  3.           1 EMP         INSERT            8001    29-3月 -04     STUDENT  
  4.         已選擇 1 行。  


說明:本例中在emp表上建立了一個由INSERT或DELETE或UPDATE事件觸發的行級觸發器,觸發器的名稱是LOG_EMP。對於不同 的操作,記錄的內容不同。本例中只插入了一條記錄,如果用一條不帶WHERE條件的UPDATE語句來修改所有僱員的工資,則將逐行觸發觸發器。
INSERT、DELETE和UPDATE都能引發觸發器動作,在分支語句中使用INSERTING、DELETING和UPDATING來區別是由哪種操作引發的觸發器動作。
在本例的插入動作中,LOG_ID欄位由序列LOG_ID_SQU自動填充為1;LOGS表LOG_KEY_ID欄位記錄的是新插入記錄的主鍵 8001;LOD_DML欄位記錄的是插入動作INSERT;LOG_TABLE欄位記錄當前表名EMP;LOG_DATE欄位記錄插入的時間04年3月 1日;LOG_USER欄位記錄插入者STUDENT。
【練習1】修改、刪除剛剛插入的僱員記錄,提交後檢查LOGS表的結果。
【練習2】為DEPT表建立同樣的觸發器,使用LOGS表進行記錄,並檢驗結果。
【訓練2】  建立一個行級觸發器LOG_SAL,記錄對職務為CLERK的僱員工資的修改,且當修改幅度超過200時才進行記錄。用WHEN條件限定觸發器。
在建立觸發器之前,需要先建立事件記錄表LOGERR,該表用來對操作進行記錄。該表的欄位含義解釋如下:
NUM:數值型,用於記錄序號。
MESSAGE:字元型,用於記錄錯誤資訊。
步驟1:在SQL*Plus中登入STUDENT賬戶,建立如下的記錄表LOGERR:

Sql程式碼  收藏程式碼
  1. CREATETABLE logerr(  
  2.         NUM NUMBER(10) NOTNULL,  
  3.         MESSAGE VARCHAR2(50) NOTNULL
  4.         );  


執行結果:

Sql程式碼  收藏程式碼
  1. 表已建立。  


步驟2:建立和編譯以下觸發器:

Sql程式碼  收藏程式碼
  1. CREATEORREPLACETRIGGER log_sal  
  2.         BEFORE  
  3.         UPDATEOF sal  
  4.         ON emp  
  5.         FOR EACH ROW  
  6.         WHEN (new.job='CLERK'AND (ABS(new.sal-old.sal)>200))   
  7. DECLARE
  8.         v_no NUMBER;  
  9.         BEGIN
  10.         SELECTCOUNT(*) INTO v_no FROM logerr;   
  11.         INSERTINTO logerr VALUES(v_no+1,'僱員'||:new.ename||'的原工資:'||:old.sal||'新工資:'||:new.sal);  
  12.         END;  


執行結果:

Sql程式碼  收藏程式碼
  1. 觸發器已建立。  


步驟3:在EMP表中更新記錄:

Sql程式碼  收藏程式碼
  1. UPDATE emp SET sal=sal+550 WHERE empno=7788;  
  2.         UPDATE emp SET sal=sal+500 WHERE empno=7369;  
  3.         UPDATE emp SET sal=sal+50 WHERE empno=7876;  
  4.         COMMIT;  


執行結果:

Sql程式碼  收藏程式碼
  1. 已更新 1 行。  
  2.         已更新 1 行。  
  3.         已更新 1 行。  
  4.         提交完成。  


步驟4:檢查LOGSAL表中記錄的資訊:

Sql程式碼  收藏程式碼
  1. SELECT * FROM logerr;  


執行結果為:
      

Sql程式碼  收藏程式碼
  1. NUM MESSAGE  
  2. ------------------ --------------------------------------------------------
  3.              1 僱員SMITH的原工資:800新工資:1300  
  4.         已選擇 1 行。  


  說明:本例中,在emp表的sal列上建立了一個由UPDATE事件觸發的行級觸發器,觸發器的名稱是LOG_SAL。該觸發器由WHEN語句限定,只有當被修改工資的僱員職務為CLERK,且修改的工資超過200時才進行觸發,否則不進行觸發。
所以在驗證過程中,雖然修改了3條記錄,但通過查詢語句發現:第一條修改語句修改編號為7788的SCOTT記錄,因為SCOTT的職務是 ANALYST,不符合WHEN條件,沒有引起觸發器動作;第二條修改語句修改編號為7369的SMITH的記錄,職務為CLERK,因為增加的工資 (500)超過了200,所以引起觸發器動作,並在LOGERR表中進行了記錄;第三條修改語句修改編號為7876的僱員ADAMS的記錄,雖然 ADAMS的職務為CLERK,但修改的工資(50)沒有超過200,所以沒有引起觸發器動作。
注意:在WHEN條件中引用new和old不需要在前面加“: ”。
在以上例項中,記錄了對工資的修改超出範圍的資訊,但沒有限制對工資的修改。那麼當對僱員工資的修改幅度不滿足條件時,能否直接限制對工資的修改呢?答案是肯定的。
【訓練3】  建立觸發器CHECK_SAL,當對職務為CLERK的僱員的工資修改超出500至2000的範圍時,進行限制。
步驟1:建立和編譯以下觸發器:

Sql程式碼  收藏程式碼
  1. CREATEORREPLACETRIGGER CHECK_SAL  
  2.         BEFORE  
  3.         UPDATE
  4.         ON emp  
  5.         FOR EACH ROW  
  6.         BEGIN
  7. IF :new.job='CLERK'AND (:new.sal<500 OR :new.sal>2000) THEN
  8.          RAISE_APPLICATION_ERROR(-20001, '工資修改超出範圍,操作取消!');  
  9.         END IF;  
  10.         END;  


執行結果:

Sql程式碼  收藏程式碼
  1. 觸發器已建立。  


步驟2:在EMP表中插入記錄:

Sql程式碼  收藏程式碼
  1. UPDATE emp SET sal=800 WHERE empno=7876;  
  2.         UPDATE emp SET sal=450 WHERE empno=7876;  
  3.         COMMIT;  


執行結果:

Sql程式碼  收藏程式碼
  1. UPDATE emp SET sal=450 WHERE empno=7876  
  2.                 *  
  3.         ERROR 位於第 1 行:  
  4.         ORA-20001: 工資修改超出範圍,操作取消!  
  5.         ORA-06512: 在"STUDENT.CHECK_SAL", line 3  
  6.         ORA-04088: 觸發器 'STUDENT.CHECK_SAL' 執行過程中出錯提交完成。  


步驟3:檢查工資的修改結果:

Sql程式碼  收藏程式碼
  1. SELECT empno,ename,job,sal FROM emp WHERE empno=7876;  


執行結果為:
   

Sql程式碼  收藏程式碼
  1. EMPNO ENAME      JOB              SAL  
  2. ----------------- ------------- ------------- ------------------------
  3.         7876  ADAMS      CLERK            800  


說明:在觸發器中,當IF語句的條件滿足時,即對職務為CLERK的僱員工資的修改超出指定範圍時,用 RAISE_APPLICATION_ERROR語句來定義一個臨時定義的異常,並立即引發異常。由於觸發器是BEFORE型別,因此觸發器先執行,觸發 器因異常而終止,SQL語句的執行就會取消。
通過步驟2的執行資訊可以看到,第一條語句修改編號為7876的僱員ADAMS的工資為800,成功執行。第二條語句修改僱員ADAMS的工資為450, 發生異常,執行失敗。這樣就阻止了不符合條件的工資的修改。通過步驟3的查詢可以看到,僱員ADAMS最後的工資是800,即發生異常之前的修改結果。
【練習3】限定對emp表的修改,只能修改部門10的僱員工資。
   【訓練4】  建立一個行級觸發器CASCADE_UPDATE,當修改部門編號時,EMP表的相關行的部門編號也自動修改。該觸發器稱為級聯修改觸發器。
步驟1:建立和編譯以下觸發器:

Sql程式碼  收藏程式碼
  1. CREATETRIGGER CASCADE_UPDATE  
  2. AFTER
  3. UPDATEOF deptno  
  4. ON DEPT  
  5. FOR EACH ROW  
  6. BEGIN
  7. UPDATEEMP SET EMP.DEPTNO=:NEW.DEPTNO  
  8.          WHERE EMP.DEPTNO=:OLD.DEPTNO;  
  9.         END;  


執行結果:

Sql程式碼  收藏程式碼
  1. 觸發器已建立  


步驟2:驗證觸發器:

Sql程式碼  收藏程式碼
  1. UPDATE dept SET deptno=11 WHERE deptno=10;  
  2.         COMMIT;  


執行結果:

Sql程式碼  收藏程式碼
  1. 已更新 1 行。   


執行查詢:

Sql程式碼  收藏程式碼
  1. SELECT empno,ename,deptno FROM emp;  


執行結果:
  

Sql程式碼  收藏程式碼
  1.  EMPNO ENAME          DEPTNO  
  2.     ----------------- ----------- -------------------------
  3.          7369 SMITH                 20  
  4.          7499 ALLEN                 30  
  5.         7521 WARD                   30  
  6.         7566 JONES                  20  
  7. 7654 MARTIN                 30  
  8.         7698 BLAKE                  30  
  9.          7782 CLARK                 11  
  10.          7839 KING                  11  
  11.         7844 TURNER                 30  
  12.         7876 ADAMS                  20  
  13.         7900 JAMES                  30  
  14.          7902 FORD                  20  
  15.          7934 MILLER                11  
  16.         7788 SCOTT                  20  


說明:通過檢查僱員的部門編號,發現原來編號為10的部門編號被修改為11。
本例中的UPDATE OF deptno表示只有在修改表的DEPTNO列時才引發觸發器,對其他列的修改不會引起觸發器的動作。在觸發器中,對僱員表的部門編號與修改之前的部門編 號一樣的僱員,修改其部門編號為新的部門編號。注意,在語句中同時用到了:new和:old來引用修改部門編號前後的部門編號。
【練習4】建立級聯刪除觸發器CASCADE_DELETE,當刪除部門時,級聯刪除EMP表的僱員記錄。
利用觸發器還可以修改資料。
【訓練5】  將插入的僱員的名字變成以大寫字母開頭。
步驟1:建立和編譯以下觸發器:

Sql程式碼  收藏程式碼
  1. CREATEORREPLACETRIGGER INITCAP  
  2. BEFORE INSERT
  3. ON EMP  
  4. FOR EACH ROW  
  5. BEGIN
  6.  :new.ename:=INITCAP(:new.ename);  
  7. END;  


執行結果:

Sql程式碼  收藏程式碼
  1. 觸發器已建立。  


步驟2:驗證執行結果:

Sql程式碼  收藏程式碼
  1. INSERTINTO emp(empno,ename,job,sal) VALUES(1000,'BILL','CLERK',1500);  


執行結果:

Sql程式碼  收藏程式碼
  1. 已建立 1 行。  


執行查詢:

Sql程式碼  收藏程式碼
  1. SELECT ename,job,sal FROM emp WHERE empno=1000;  


執行結果:

Sql程式碼  收藏程式碼
  1. ENAME      JOB              SAL  
  2.         ------------- ------------- ------------------------
  3.         Bill          CLERK           1500  


說明:在本例中,通過直接為:new.ename進行賦值,修改了插入的值,但是這種用法只能在BEFORE型觸發器中使用。驗證結果為,在插入語句中僱員名稱為大寫的BILL,查詢結果中僱員名稱已經轉換成以大寫開頭的Bill。
【練習5】限定一次對僱員的工資修改不超過原工資的10%。
語句級觸發器的應用
同行級觸發器不同,語句級觸發器的每個操作語句不管操作的行數是多少,只觸發一次觸發器,所以語句級觸發器適合於對整個表的操作許可權等進行控制。在觸發器定義中若省略FOR EACH ROW子句,則為語句級觸發器。
【訓練1】  建立一個語句級觸發器CHECK_TIME,限定對錶EMP的修改時間為週一至週五的早8點至晚5點。
步驟1:建立和編譯以下觸發器:

Sql程式碼  收藏程式碼
  1. CREATEORREPLACETRIGGER CHECK_TIME  
  2. BEFORE  
  3. UPDATEORINSERTORDELETE
  4. ON EMP  
  5. BEGIN
  6.  IF (TO_CHAR(SYSDATE,'DY'IN ('SAT','SUN'))   
  7.  OR TO_CHAR(SYSDATE,'HH24')< '08'
  8.  OR TO_CHAR(SYSDATE,'HH24')>='17'THEN
  9. RAISE_APPLICATION_ERROR(-20500,'非法時間修改表錯誤!');  
  10.          END IF;   
  11.         END;  


執行結果:

Sql程式碼  收藏程式碼
  1. 觸發器已建立。  


步驟2:當前時間為18點50分,在EMP表中插入記錄:

Sql程式碼  收藏程式碼
  1. UPDATE EMP SET SAL=3000 WHERE EMPNO=7369;  


顯示結果為:

Sql程式碼  收藏程式碼
  1. UPDATE EMP SET SAL=3000 WHERE EMPNO=7369  
  2.                                        *  
  3. ERROR 位於第 1 行:  
  4.         ORA-20500: 非法時間修改表錯誤!  
  5.         ORA-06512: 在"STUDENT.CHECK_TIME", line 5  
  6.         ORA-04088: 觸發器 'STUDENT.CHECK_TIME' 執行過程中出錯  


  說明:通過引發異常限制對資料庫進行的插入、刪除和修改操作的時間。SYSDATE用來獲取系統當前時間,並按不同的格式字串進行轉換。“DY”表示獲取英文表示的星期簡寫,“HH24”表示獲取24小時制時間的小時。
當在18點50分修改表中的資料時,由於時間在8點至17點(晚5點)之外,所以產生“非法時間修改表錯誤”的使用者自定義錯誤,修改操作終止。
【練習1】設計一個語句級觸發器,限定只能對資料庫進行修改操作,不能對資料庫進行插入和刪除操作。在需要進行插入和刪除時,將觸發器設定為無效狀態,完成後重新設定為生效狀態。
資料庫事件觸發器
資料庫事件觸發器有資料庫級和模式級兩種。前者定義在整個資料庫上,觸發事件是資料庫事件,如資料庫的啟動、關閉,對資料庫的登入或退出。後者定義在模式上,觸發事件包括模式使用者的登入或退出,或對資料庫物件的建立和修改(DDL事件)。
資料庫事件觸發器的觸發事件的種類和級別如表9-3所示。

Sql程式碼  收藏程式碼
  1. 種  類    關 鍵 字   說    明  
  2. 模式級 CREATE  在建立新物件時觸發  
  3.     ALTER   修改資料庫或資料庫物件時觸發  
  4.     DROP    刪除物件時觸發  
  5. 資料庫級    STARTUP 資料庫開啟時觸發  
  6.     SHUTDOWN    在使用NORMAL或IMMEDIATE選項關閉資料庫時觸發  
  7.     SERVERERROR     發生伺服器錯誤時觸發  
  8. 資料庫級與模式級    LOGON   當用戶連線到資料庫,建立會話時觸發  
  9.     LOGOFF  當會話從資料庫中斷開時觸發  


定義資料庫事件和模式事件觸發器
建立資料庫級觸發器需要ADMINISTER DATABASE TRIGGER系統許可權,一般只有系統管理員擁有該許可權。
對於模式級觸發器,為自己的模式建立觸發器需要CREATE TRIGGER許可權,如果是為其他模式建立觸發器,需要CREATE ANY TRIGGER許可權。
資料庫事件和模式事件觸發器的建立語法與DML觸發器的建立語法類似。資料庫事件或模式事件觸發器的建立語法如下:
CREATE [OR REPLACE] TRIGGER 觸發器名
{BEFORE|AFTER }
{DDL事件1 [DDL事件2...]| 資料庫事件1 [資料庫事件2...]}
ON {DATABASE| [模式名.]SCHEMA }
[WHEN (條件)]
DECLARE
宣告部分
BEGIN
主體部分
END;
其中:DATABASE表示建立資料庫級觸發器,資料庫級要給出資料庫事件;SCHEMA表示建立模式級觸發器,模式級要給出模式事件或DDL事件。
在資料庫事件觸發器中,可以使用如表9-4所示的一些事件屬性。不同型別的觸發器可以使用的事件屬性有所不同。

Sql程式碼  收藏程式碼
  1. 屬  性    適用觸發器型別 說    明  
  2. Sys.sysevent    所有型別    返回觸發器觸發事件字串  
  3. Sys.instance_num    所有型別    返回Oracle例項號  
  4. Sys.database_name   所有型別    返回資料庫名字  
  5. Sys.server_error(stack_position)    SERVERERROR 從錯誤堆疊指定位置返回錯誤號,引數為1表示最近的錯誤  
  6. Is_servererror(error_number)    SERVERERROR 判斷堆疊中是否有引數指定的錯誤號  
  7. Sys.login_user  所有型別    返回導致觸發器觸發的使用者名稱  
  8. Sys.dictionary_obj_type CREATEALTERDROP   返回DDL觸發器觸發時涉及的物件型別  
  9. Sys. dictionary_obj_name    CREATEALTERDROP   返回DDL觸發器觸發時涉及的物件名稱  
  10. Sys.des_encrypted_password  CREATEALTERDROP   建立或修改使用者時,返回加密後的使用者密碼  


資料庫事件觸發器
下面是一個綜合的資料庫事件觸發器練習。先為STUDENT賬戶授予建立資料庫事件觸發器的許可權,ADMINISTER DATABASE TRIGGER,然後建立有關的表和觸發器,最後予以驗證。
  【訓練1】  建立觸發器,對本次資料庫啟動以來的使用者登入時間進行記錄,每次資料庫啟動後,先清空該表。
步驟1:建立登入事件記錄表:

Sql程式碼  收藏程式碼
  1. CREATETABLE userlog (  
  2. USERNAME VARCHAR2(20),  
  3. LOGON_TIME DATE);  


執行結果:

Sql程式碼  收藏程式碼
  1. 表已建立。  


步驟2:建立資料庫STARTUP事件觸發器:

Sql程式碼  收藏程式碼
  1. CREATEORREPLACETRIGGER INIT_LOGON  
  2. AFTER
  3. STARTUP   
  4. ONDATABASE
  5. BEGIN
  6.  DELETEFROM userlog;  
  7. END;  


執行結果:

Sql程式碼  收藏程式碼
  1. 觸發器已建立。  


步驟3:建立資料庫LOGON事件觸發器:

Sql程式碼  收藏程式碼
  1. CREATEORREPLACETRIGGER DATABASE_LOGON  
  2. AFTER
  3. LOGON   
  4. ONDATABASE
  5. BEGIN
  6.  INSERTINTO userlog   
  7.  VALUES(sys.login_user,sysdate);  
  8. END;  


執行結果:

Sql程式碼  收藏程式碼
  1. 觸發器已建立。  


步驟4:驗證DATABASE_LOGON觸發器:

Sql程式碼  收藏程式碼
  1. CONNECT SCOTT/[email protected];  
  2.         CONNECT STUDENT/[email protected];  


執行結果:

Sql程式碼  收藏程式碼
  1. 已連線。  
  2. 已連線。  


執行查詢:

Sql程式碼  收藏程式碼
  1. SELECT username,TO_CHAR(logon_time,'YYYY/MM/DD HH24:MI:SS'FROM userlog;  


執行結果:

Sql程式碼  收藏程式碼
  1. USERNAME             TO_CHAR(LOGON_TIME,  
  2. ----------------------------- -----------------------------------------
  3. SCOTT                   2004/03/29 22:42:20  
  4.         STUDENT                 2004/03/29 22:42:20  


步驟5:驗證INIT_LOGON觸發器。
重新啟動資料庫,登入STUDENT賬戶:

Sql程式碼  收藏程式碼
  1. SELECT username,TO_CHAR(logon_time,'YYYY/MM/DD HH24:MI:SS'FROM userlog;  


執行結果:

Sql程式碼  收藏程式碼
  1. USERNAME             TO_CHAR(LOGON_TIME,  
  2. -------------------------------- ---------------------------------------
  3.         STUDENT              2004/03/29 22:43:59  
  4.         已選擇 1 行  


說明:本例中共建立了兩個資料庫級事件觸發器。DATABASE_LOGON在使用者登入時觸發,向表userlog中增加一條記錄,記錄登入使用者 名和登入時間。INIT_LOGON在資料庫啟動時觸發,清除userlog表中記錄的資料。所以當資料庫重新啟動後,重新登入STUDENT賬戶,此時 userlog表中只有一條記錄。
【訓練2】  建立STUDENT_LOGON模式級觸發器,專門記錄STUDENT賬戶的登入時間:

Sql程式碼  收藏程式碼
  1. CREATEORREPLACETRIGGER STUDENT_LOGON   
  2. AFTER
  3. LOGON ON STUDENT.SCHEMA
  4. BEGIN
  5.  INSERTINTO userlog  
  6.  VALUES(sys.login_user,sysdate);  
  7. END;  


執行結果:

Sql程式碼  收藏程式碼
  1. 觸發器已建立。  


說明:為當前模式建立觸發器,可以省略SCHEMA前面的模式名。
【練習1】修改DATABASE_LOGON觸發器和userlog表,增加對退出時間的記錄。
DDL事件觸發器
【訓練1】  通過觸發器阻止對emp表的刪除。
步驟1:建立DDL觸發器:

Sql程式碼  收藏程式碼
  1. CREATEORREPLACETRIGGER NODROP_EMP  
  2.          BEFORE  
  3.         DROPONSCHEMA
  4.         BEGIN
  5.         IF Sys.Dictionary_obj_name='EMP'THEN
  6. RAISE_APPLICATION_ERROR(-20005,'錯誤資訊:不能刪除emp表!');  
  7.          END IF;   
  8.         END;  


執行結果:

Sql程式碼  收藏程式碼
  1. 觸發器已建立。  


步驟2:通過刪除emp表驗證觸發器:

Sql程式碼  收藏程式碼
  1. DROPTABLE emp;  


執行結果:

Sql程式碼  收藏程式碼
  1. DROPTABLE emp  
  2.         *  
  3. ERROR 位於第 1 行:  
  4.         ORA-00604: 遞迴 SQL 層 1 出現錯誤  
  5.         ORA-20005: 錯誤資訊:不能刪除emp表!  
  6.         ORA-06512: 在line 3  


     說明:該觸發器阻止在當前模式下對emp表的刪除,但不阻止刪除其他物件。Sys.Dictionary_obj_name屬性返回要刪除的物件名稱。
替代觸發器
【訓練1】  在emp表的檢視上,通過觸發器修改emp表。
步驟1:建立檢視emp_name:

Sql程式碼