oracle 觸發器的種類和觸發事件,DML觸發器,DDL事件觸發器,替代觸發器,檢視觸發器,...
轉載:http://heisetoufa.iteye.com/blog/367314
觸發器的種類和觸發事件
觸發器必須由事件才能觸發。觸發器的觸發事件分可為3類,分別是DML事件、DDL事件和資料庫事件。
每類事件包含若干個事件,如下所示。資料庫的事件是具體的,在建立觸發器時要指明觸發的事件。
種 類 關 鍵 字 含 義
- DML事件(3種) INSERT 在表或檢視中插入資料時觸發
- UPDATE 修改表或檢視中的資料時觸發
- DELETE 在刪除表或檢視中的資料時觸發
- DDL事件(3種) CREATE 在建立新物件時觸發
- ALTER 修改資料庫或資料庫物件時觸發
- DROP 刪除物件時觸發
- 資料庫事件(5種) STARTUP 資料開啟時觸發
- SHUTDOWN 在使用NORMAL或IMMEDIATE選項關閉資料庫時觸發
- LOGON 當用戶連線到資料庫並建立會話時觸發
- LOGOFF 當一個會話從資料庫中斷開時觸發
- SERVERERROR 發生伺服器錯誤時觸發
觸發器的型別可劃分為4種:資料操縱語言(DML)觸發器、替代(INSTEAD OF)觸發器、資料定義語言(DDL)觸發器和資料庫事件觸發器。
各類觸發器的作用如下所示。
- 種 類 簡 稱 作 用
- 資料操縱語言觸發器 DML觸發器 建立在表上,由DML事件引發的觸發器
- 替代觸發器 INSTEADOF觸發器 建立在檢視上,用來替換對檢視進行的插入、刪除和修改操作
- 資料定義語言觸發器 DDL觸發器 定義在模式上,觸發事件是資料庫物件的建立和修改
- 資料庫事件觸發器 — 定義在整個資料庫或模式上,觸發事件是資料庫事件
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記錄,分別代表修改前後的記錄。引用具體的某一列的值的方法是:
* 觸發器體內禁止使用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程式碼
- CREATETABLE logs(
- LOG_ID NUMBER(10) PRIMARYKEY,
- LOG_TABLE VARCHAR2(10) NOTNULL,
- LOG_DML VARCHAR2(10),
- LOG_KEY_ID NUMBER(10),
- LOG_DATE DATE,
- LOG_USER VARCHAR2(15)
- );
執行結果:
- 表已建立。
步驟2:建立一個LOGS表的主鍵序列LOGS_ID_SEQ:
- CREATESEQUENCE logs_id_squ INCREMENT BY 1
- START WITH 1 MAXVALUE 9999999 NOCYCLE NOCACHE;
執行結果:
- 序列已建立。
步驟3:建立和編譯以下觸發器:
- CREATEORREPLACETRIGGER DML_LOG
- BEFORE --觸發時間為操作前
- DELETEORINSERTORUPDATE-- 由三種事件觸發
- ON emp
- FOR EACH ROW -- 行級觸發器
- BEGIN
- IF INSERTING THEN
- INSERTINTO logs VALUES(logs_id_squ.NEXTVAL,'EMP','INSERT',:new.empno,SYSDATE,USER);
- ELSIF DELETING THEN
- INSERTINTO logs VALUES(logs_id_squ.NEXTVAL,'EMP','DELETE',:old.empno,SYSDATE,USER);
- ELSE
- INSERTINTO logs VALUES(logs_id_squ.NEXTVAL,'EMP','UPDATE',:new.empno,SYSDATE,USER);
- END IF;
- END;
執行結果:
觸發器已建立
步驟4:在EMP表中插入記錄:
- INSERTINTO emp(empno,ename,job,sal) VALUES(8001,'MARY','CLERK',1000);
- COMMIT;
執行結果:
- 已建立1行。
- 提交完成。
步驟5:檢查LOGS表中記錄的資訊:
- SELECT * FROM LOGS;
執行結果為:
- LOG_ID LOG_TABLE LOG_DML LOG_KEY_ID LOG_DATE LOG_USER
- ----------------- ----------------- ------------------ ----------------------- ---------------- -------------------
- 1 EMP INSERT 8001 29-3月 -04 STUDENT
- 已選擇 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:
- CREATETABLE logerr(
- NUM NUMBER(10) NOTNULL,
- MESSAGE VARCHAR2(50) NOTNULL
- );
執行結果:
- 表已建立。
步驟2:建立和編譯以下觸發器:
- CREATEORREPLACETRIGGER log_sal
- BEFORE
- UPDATEOF sal
- ON emp
- FOR EACH ROW
- WHEN (new.job='CLERK'AND (ABS(new.sal-old.sal)>200))
- DECLARE
- v_no NUMBER;
- BEGIN
- SELECTCOUNT(*) INTO v_no FROM logerr;
- INSERTINTO logerr VALUES(v_no+1,'僱員'||:new.ename||'的原工資:'||:old.sal||'新工資:'||:new.sal);
- END;
執行結果:
- 觸發器已建立。
步驟3:在EMP表中更新記錄:
- UPDATE emp SET sal=sal+550 WHERE empno=7788;
- UPDATE emp SET sal=sal+500 WHERE empno=7369;
- UPDATE emp SET sal=sal+50 WHERE empno=7876;
- COMMIT;
執行結果:
- 已更新 1 行。
- 已更新 1 行。
- 已更新 1 行。
- 提交完成。
步驟4:檢查LOGSAL表中記錄的資訊:
- SELECT * FROM logerr;
執行結果為:
- NUM MESSAGE
- ------------------ --------------------------------------------------------
- 1 僱員SMITH的原工資:800新工資:1300
- 已選擇 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:建立和編譯以下觸發器:
- CREATEORREPLACETRIGGER CHECK_SAL
- BEFORE
- UPDATE
- ON emp
- FOR EACH ROW
- BEGIN
- IF :new.job='CLERK'AND (:new.sal<500 OR :new.sal>2000) THEN
- RAISE_APPLICATION_ERROR(-20001, '工資修改超出範圍,操作取消!');
- END IF;
- END;
執行結果:
- 觸發器已建立。
步驟2:在EMP表中插入記錄:
- UPDATE emp SET sal=800 WHERE empno=7876;
- UPDATE emp SET sal=450 WHERE empno=7876;
- COMMIT;
執行結果:
- UPDATE emp SET sal=450 WHERE empno=7876
- *
- ERROR 位於第 1 行:
- ORA-20001: 工資修改超出範圍,操作取消!
- ORA-06512: 在"STUDENT.CHECK_SAL", line 3
- ORA-04088: 觸發器 'STUDENT.CHECK_SAL' 執行過程中出錯提交完成。
步驟3:檢查工資的修改結果:
- SELECT empno,ename,job,sal FROM emp WHERE empno=7876;
執行結果為:
- EMPNO ENAME JOB SAL
- ----------------- ------------- ------------- ------------------------
- 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:建立和編譯以下觸發器:
- CREATETRIGGER CASCADE_UPDATE
- AFTER
- UPDATEOF deptno
- ON DEPT
- FOR EACH ROW
- BEGIN
- UPDATEEMP SET EMP.DEPTNO=:NEW.DEPTNO
- WHERE EMP.DEPTNO=:OLD.DEPTNO;
- END;
執行結果:
- 觸發器已建立
步驟2:驗證觸發器:
- UPDATE dept SET deptno=11 WHERE deptno=10;
- COMMIT;
執行結果:
- 已更新 1 行。
執行查詢:
- SELECT empno,ename,deptno FROM emp;
執行結果:
- EMPNO ENAME DEPTNO
- ----------------- ----------- -------------------------
- 7369 SMITH 20
- 7499 ALLEN 30
- 7521 WARD 30
- 7566 JONES 20
- 7654 MARTIN 30
- 7698 BLAKE 30
- 7782 CLARK 11
- 7839 KING 11
- 7844 TURNER 30
- 7876 ADAMS 20
- 7900 JAMES 30
- 7902 FORD 20
- 7934 MILLER 11
- 7788 SCOTT 20
說明:通過檢查僱員的部門編號,發現原來編號為10的部門編號被修改為11。
本例中的UPDATE OF deptno表示只有在修改表的DEPTNO列時才引發觸發器,對其他列的修改不會引起觸發器的動作。在觸發器中,對僱員表的部門編號與修改之前的部門編 號一樣的僱員,修改其部門編號為新的部門編號。注意,在語句中同時用到了:new和:old來引用修改部門編號前後的部門編號。
【練習4】建立級聯刪除觸發器CASCADE_DELETE,當刪除部門時,級聯刪除EMP表的僱員記錄。
利用觸發器還可以修改資料。
【訓練5】 將插入的僱員的名字變成以大寫字母開頭。
步驟1:建立和編譯以下觸發器:
- CREATEORREPLACETRIGGER INITCAP
- BEFORE INSERT
- ON EMP
- FOR EACH ROW
- BEGIN
- :new.ename:=INITCAP(:new.ename);
- END;
執行結果:
- 觸發器已建立。
步驟2:驗證執行結果:
- INSERTINTO emp(empno,ename,job,sal) VALUES(1000,'BILL','CLERK',1500);
執行結果:
- 已建立 1 行。
執行查詢:
- SELECT ename,job,sal FROM emp WHERE empno=1000;
執行結果:
- ENAME JOB SAL
- ------------- ------------- ------------------------
- Bill CLERK 1500
說明:在本例中,通過直接為:new.ename進行賦值,修改了插入的值,但是這種用法只能在BEFORE型觸發器中使用。驗證結果為,在插入語句中僱員名稱為大寫的BILL,查詢結果中僱員名稱已經轉換成以大寫開頭的Bill。
【練習5】限定一次對僱員的工資修改不超過原工資的10%。
語句級觸發器的應用
同行級觸發器不同,語句級觸發器的每個操作語句不管操作的行數是多少,只觸發一次觸發器,所以語句級觸發器適合於對整個表的操作許可權等進行控制。在觸發器定義中若省略FOR EACH ROW子句,則為語句級觸發器。
【訓練1】 建立一個語句級觸發器CHECK_TIME,限定對錶EMP的修改時間為週一至週五的早8點至晚5點。
步驟1:建立和編譯以下觸發器:
- CREATEORREPLACETRIGGER CHECK_TIME
- BEFORE
- UPDATEORINSERTORDELETE
- ON EMP
- BEGIN
- IF (TO_CHAR(SYSDATE,'DY') IN ('SAT','SUN'))
- OR TO_CHAR(SYSDATE,'HH24')< '08'
- OR TO_CHAR(SYSDATE,'HH24')>='17'THEN
- RAISE_APPLICATION_ERROR(-20500,'非法時間修改表錯誤!');
- END IF;
- END;
執行結果:
- 觸發器已建立。
步驟2:當前時間為18點50分,在EMP表中插入記錄:
- UPDATE EMP SET SAL=3000 WHERE EMPNO=7369;
顯示結果為:
- UPDATE EMP SET SAL=3000 WHERE EMPNO=7369
- *
- ERROR 位於第 1 行:
- ORA-20500: 非法時間修改表錯誤!
- ORA-06512: 在"STUDENT.CHECK_TIME", line 5
- ORA-04088: 觸發器 'STUDENT.CHECK_TIME' 執行過程中出錯
說明:通過引發異常限制對資料庫進行的插入、刪除和修改操作的時間。SYSDATE用來獲取系統當前時間,並按不同的格式字串進行轉換。“DY”表示獲取英文表示的星期簡寫,“HH24”表示獲取24小時制時間的小時。
當在18點50分修改表中的資料時,由於時間在8點至17點(晚5點)之外,所以產生“非法時間修改表錯誤”的使用者自定義錯誤,修改操作終止。
【練習1】設計一個語句級觸發器,限定只能對資料庫進行修改操作,不能對資料庫進行插入和刪除操作。在需要進行插入和刪除時,將觸發器設定為無效狀態,完成後重新設定為生效狀態。
資料庫事件觸發器
資料庫事件觸發器有資料庫級和模式級兩種。前者定義在整個資料庫上,觸發事件是資料庫事件,如資料庫的啟動、關閉,對資料庫的登入或退出。後者定義在模式上,觸發事件包括模式使用者的登入或退出,或對資料庫物件的建立和修改(DDL事件)。
資料庫事件觸發器的觸發事件的種類和級別如表9-3所示。
- 種 類 關 鍵 字 說 明
- 模式級 CREATE 在建立新物件時觸發
- ALTER 修改資料庫或資料庫物件時觸發
- DROP 刪除物件時觸發
- 資料庫級 STARTUP 資料庫開啟時觸發
- SHUTDOWN 在使用NORMAL或IMMEDIATE選項關閉資料庫時觸發
- SERVERERROR 發生伺服器錯誤時觸發
- 資料庫級與模式級 LOGON 當用戶連線到資料庫,建立會話時觸發
- 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所示的一些事件屬性。不同型別的觸發器可以使用的事件屬性有所不同。
- 屬 性 適用觸發器型別 說 明
- Sys.sysevent 所有型別 返回觸發器觸發事件字串
- Sys.instance_num 所有型別 返回Oracle例項號
- Sys.database_name 所有型別 返回資料庫名字
- Sys.server_error(stack_position) SERVERERROR 從錯誤堆疊指定位置返回錯誤號,引數為1表示最近的錯誤
- Is_servererror(error_number) SERVERERROR 判斷堆疊中是否有引數指定的錯誤號
- Sys.login_user 所有型別 返回導致觸發器觸發的使用者名稱
- Sys.dictionary_obj_type CREATE、ALTER、DROP 返回DDL觸發器觸發時涉及的物件型別
- Sys. dictionary_obj_name CREATE、ALTER、DROP 返回DDL觸發器觸發時涉及的物件名稱
- Sys.des_encrypted_password CREATE、ALTER、DROP 建立或修改使用者時,返回加密後的使用者密碼
資料庫事件觸發器
下面是一個綜合的資料庫事件觸發器練習。先為STUDENT賬戶授予建立資料庫事件觸發器的許可權,ADMINISTER DATABASE TRIGGER,然後建立有關的表和觸發器,最後予以驗證。
【訓練1】 建立觸發器,對本次資料庫啟動以來的使用者登入時間進行記錄,每次資料庫啟動後,先清空該表。
步驟1:建立登入事件記錄表:
- CREATETABLE userlog (
- USERNAME VARCHAR2(20),
- LOGON_TIME DATE);
執行結果:
- 表已建立。
步驟2:建立資料庫STARTUP事件觸發器:
- CREATEORREPLACETRIGGER INIT_LOGON
- AFTER
- STARTUP
- ONDATABASE
- BEGIN
- DELETEFROM userlog;
- END;
執行結果:
- 觸發器已建立。
步驟3:建立資料庫LOGON事件觸發器:
- CREATEORREPLACETRIGGER DATABASE_LOGON
- AFTER
- LOGON
- ONDATABASE
- BEGIN
- INSERTINTO userlog
- VALUES(sys.login_user,sysdate);
- END;
執行結果:
- 觸發器已建立。
步驟4:驗證DATABASE_LOGON觸發器:
- CONNECT SCOTT/[email protected];
- CONNECT STUDENT/[email protected];
執行結果:
- 已連線。
- 已連線。
執行查詢:
- SELECT username,TO_CHAR(logon_time,'YYYY/MM/DD HH24:MI:SS') FROM userlog;
執行結果:
- USERNAME TO_CHAR(LOGON_TIME,
- ----------------------------- -----------------------------------------
- SCOTT 2004/03/29 22:42:20
- STUDENT 2004/03/29 22:42:20
步驟5:驗證INIT_LOGON觸發器。
重新啟動資料庫,登入STUDENT賬戶:
- SELECT username,TO_CHAR(logon_time,'YYYY/MM/DD HH24:MI:SS') FROM userlog;
執行結果:
- USERNAME TO_CHAR(LOGON_TIME,
- -------------------------------- ---------------------------------------
- STUDENT 2004/03/29 22:43:59
- 已選擇 1 行
說明:本例中共建立了兩個資料庫級事件觸發器。DATABASE_LOGON在使用者登入時觸發,向表userlog中增加一條記錄,記錄登入使用者 名和登入時間。INIT_LOGON在資料庫啟動時觸發,清除userlog表中記錄的資料。所以當資料庫重新啟動後,重新登入STUDENT賬戶,此時 userlog表中只有一條記錄。
【訓練2】 建立STUDENT_LOGON模式級觸發器,專門記錄STUDENT賬戶的登入時間:
- CREATEORREPLACETRIGGER STUDENT_LOGON
- AFTER
- LOGON ON STUDENT.SCHEMA
- BEGIN
- INSERTINTO userlog
- VALUES(sys.login_user,sysdate);
- END;
執行結果:
- 觸發器已建立。
說明:為當前模式建立觸發器,可以省略SCHEMA前面的模式名。
【練習1】修改DATABASE_LOGON觸發器和userlog表,增加對退出時間的記錄。
DDL事件觸發器
【訓練1】 通過觸發器阻止對emp表的刪除。
步驟1:建立DDL觸發器:
- CREATEORREPLACETRIGGER NODROP_EMP
- BEFORE
- DROPONSCHEMA
- BEGIN
- IF Sys.Dictionary_obj_name='EMP'THEN
- RAISE_APPLICATION_ERROR(-20005,'錯誤資訊:不能刪除emp表!');
- END IF;
- END;
執行結果:
- 觸發器已建立。
步驟2:通過刪除emp表驗證觸發器:
- DROPTABLE emp;
執行結果:
- DROPTABLE emp
- *
- ERROR 位於第 1 行:
- ORA-00604: 遞迴 SQL 層 1 出現錯誤
- ORA-20005: 錯誤資訊:不能刪除emp表!
- ORA-06512: 在line 3
說明:該觸發器阻止在當前模式下對emp表的刪除,但不阻止刪除其他物件。Sys.Dictionary_obj_name屬性返回要刪除的物件名稱。
替代觸發器
【訓練1】 在emp表的檢視上,通過觸發器修改emp表。
步驟1:建立檢視emp_name: