1,、觸發(fā)器的概念 觸發(fā)器也是一種帶名的PL/SQL塊。觸發(fā)器類似于過程和函數(shù),,因為它們都是擁有聲明,、執(zhí)行和異常處理過程的帶名PL/SQL塊。與包類似,,觸發(fā)器必須存儲在數(shù)據(jù)庫中并且不能被塊進行本地化聲明,。 對于觸發(fā)器而言,當觸發(fā)事件發(fā)生的時候就會顯式地執(zhí)行該觸發(fā)器,,并且觸發(fā)器不接受參數(shù),。
創(chuàng)建觸發(fā)器的語法如下
view plaincopy to clipboardprint? {BEFORE | AFTER | INSTEAD OF} triggering_event [referencing_clause] [WHEN trigger_condition] [FOR EACH ROW] Trigger_body; 其中referencing_clause子句的用途是通過一個不同的名稱,引用當前正在被更新的記錄行中的數(shù)據(jù)。WHEN子句中的trigger_condition—如果出現(xiàn)—就應該首先執(zhí)行判斷,,只有當這個條件值為真的時候,,才會執(zhí)行觸發(fā)器的主體代碼。
2,、DML觸發(fā)器的激活順序 1)執(zhí)行before語句級觸發(fā)器—如果存在這種觸發(fā)器 2)對受該語句影響的每一行記錄 執(zhí)行before行級觸發(fā)器—如果存在這種觸發(fā)器 執(zhí)行該語句本身 執(zhí)行after行級觸發(fā)器--如果存在這種觸發(fā)器 3)執(zhí)行after語句級觸發(fā)器--如果存在這種觸發(fā)器
同一種類型的觸發(fā)器的點火次序沒有經(jīng)過定義,。如果該次序很重要的話,那么建議將所有這些操作組合到一個觸發(fā)器當中,。
3,、行級觸發(fā)器中的關聯(lián)標識符 觸發(fā)器的激活語句每處理一行數(shù)據(jù),行級觸發(fā)器就會激活一次,??梢栽谶@種行級觸發(fā)器內(nèi)部,訪問正被處理的記錄行中的數(shù)據(jù),。這是通過兩個關聯(lián)標識符--:old和:new—實現(xiàn)的,。關聯(lián)標識符也是PL/SQL的一種特殊的綁定變量。標識符前面的冒號,,既說明這二者都是綁定變量,,同時也說明它們不是一般的PL/SQL變量。PL/SQL編譯器會將它們看作下面這個類型的記錄:
Triggering_table%ROWTYPE
其中triggering_table是在其上定義觸發(fā)器的表名,。于是,,下面這種引用
:new.field
就只有當其中的field是該觸發(fā)表中的字段名時才會有效。
觸發(fā)語句
注意:INSERT語句上沒有定義:old標識符,DELETE語句上也沒有定義:new標識符,。如果再INSERT語句上使用:old標識符,,或者在DELETE語句上使用:new標識符,PL/SQL并不會產(chǎn)生錯誤,,但是這兩個字段值都會為NULL,。
偽記錄 雖然在語法構成上,會將:new和:old看作triggering_table%ROWTYPE類型的記錄,,但是,,實際上它們并不是記錄,。因此,,那些能夠在記錄上正常執(zhí)行的操作,并不能在:new和:old上執(zhí)行,。例如,,不能將它們作為一個整體進行賦值。只能對其中的各個字段分別賦值,。
view plaincopy to clipboardprint? BEFORE DELETE ON temp_table FOR EACH ROW DECLARE v_TempRec temp_table%ROWTYPE; BEGIN /* This is not a legal assignment, since :old is not truly a record. */ v_TempRec := :old;
/* We can accomplish the same thing, however, by assigning the fields individually. */ v_TempRec.char_col := :old.char_col; v_TempRec.num_col := :old.num_col; END TempDelete; /
REFERENCING子句 還可以使用REFERENCING子句,,為:old和:new換一個不同的名稱,。該子句出現(xiàn)在觸發(fā)事件以后,WHEN子句以前,。其語法如下:
REFERENCING [OLD AS old_name] [NEW AS new_name]
在觸發(fā)器主體中,,可以使用:old_name和:new_name分別代替:old和:new。
注意,,在REFERENCING子句中關聯(lián)標識符都不帶冒號,。
如下面這個例子所示
BEFORE INSERT OR UPDATE ON authors REFERENCING new AS new_author FOR EACH ROW BEGIN /* Fill in the ID field of authors with the next value from author_sequence. Since ID is a column in authors, :new.ID is a valid reference. */ SELECT author_sequence.NEXTVAL INTO :new_author.ID FROM dual; END GenerateAuthorID; /
4、WHEN子句 WHEN子句只能在行級觸發(fā)器中使用,。如果在行級觸發(fā)器的定義中給出了WHEN子句,,觸發(fā)器主體就只對滿足WHEN所定義條件的那些記錄行執(zhí)行。WHEN子句的基本形式如下:
WHEN trigger_condition
其中,,trigger_condition是一個布爾表達式,。每處理一行記錄,都會重新判斷該表達式的值,。
也可以在trigger_condition內(nèi)部使用:new和:old記錄,,但是與REFERENCING子句一樣,在trigger_condition內(nèi)部使用:new和:old時,,不需要冒號,。僅在觸發(fā)器主體中才需要使用冒號。
5,、觸發(fā)器謂詞 可以在觸發(fā)器內(nèi)部使用3個布爾函數(shù),,判斷觸發(fā)該觸發(fā)器的到底是什么操作。這3個謂詞分別是INSERTING,、UPDATING和DELETING.
view plaincopy to clipboardprint? BEFORE INSERT OR DELETE OR UPDATE ON inventory FOR EACH ROW DECLARE v_ChangeType CHAR(1); BEGIN /* Use 'I' for an INSERT, 'D' for DELETE, and 'U' for UPDATE. */ IF INSERTING THEN v_ChangeType := 'I'; ELSIF UPDATING THEN v_ChangeType := 'U'; ELSE v_ChangeType := 'D'; END IF;
/* Record all the changes made to inventory in inventory_audit. Use SYSDATE to generate the timestamp, and USER to return the userid of the current user. */ INSERT INTO inventory_audit (change_type, changed_by, timestamp, old_isbn, old_status, old_status_date, old_amount, new_isbn, new_status, new_status_date, new_amount) VALUES (v_ChangeType, USER, SYSDATE, :old.isbn, :old.status, :old.status_date, :old.amount, :new.isbn, :new.status, :new.status_date, :new.amount); END LogInventoryChanges; /
6,、INSTEAD-OF觸發(fā)器 INSTEAD-OF觸發(fā)器僅可以定義在視圖上(關系型的或?qū)ο螅⑶宜鼈兛梢蕴娲c火它們的DML語句進行點火,。INSTEAD-OF觸發(fā)器必須是行級的,。
7、觸發(fā)器的限制 觸發(fā)器的主體是一個PL/SQL塊,。在PL/SQL塊中可以使用的所有語句在觸發(fā)器主體中都是合法的,,但是要受到下面限制的約束:
觸發(fā)器不應該使用事務控制語句—COMMIT、ROLLBACK或SAVEPOINT,。觸發(fā)器作為觸發(fā)語句執(zhí)行的一部分被點火,,它和觸發(fā)語句在同一個事務中。當觸發(fā)語句被提交或撤回提交時,,觸發(fā)器的工作也相應被提交會撤回提交,。 觸發(fā)器P-Code 當包或者子程序存儲在數(shù)據(jù)字典中時,,存儲的除了該對象的源代碼還有經(jīng)過編譯的p-code,。但是對于觸發(fā)器來說就不是這樣的。在數(shù)據(jù)字典中唯一存儲的是觸發(fā)器的源代碼,,而不是p-code,。結果,每次當從數(shù)據(jù)字典中重新讀出觸發(fā)器時,,必須要進行編譯,。這對觸發(fā)器的定義和使用的方式不會帶來什么影響,但是會影響觸發(fā)器的性能,。
8,、系統(tǒng)觸發(fā)器 我們前面所看到的DML觸發(fā)器和INSTEAD-OF觸發(fā)器都是基于DML事件。而另一方面,,系統(tǒng)觸發(fā)器的激活則是基于兩種不同的事件:DDL事件或數(shù)據(jù)庫事件,。DDL事件包括CREATE、ALTER或DROP語句,,而數(shù)據(jù)庫事件包括數(shù)據(jù)庫服務器的啟動/關閉事件,,用戶的登陸/斷開事件,以及服務器錯誤,。創(chuàng)建系統(tǒng)觸發(fā)器的語法如下:
{BEFORE | AFTER} {ddl_event_list | database_event_list} ON {DATABASE | [schema.]SCHEMA} [when_clause] Trigger_body;
其中,,ddl_event_list是由OR關鍵字隔開的一個或多個DDL事件,database_event_list則是由OR關鍵字隔開的一個或多個數(shù)據(jù)庫事件,。
注意:不能創(chuàng)建INSTEAD-OF系統(tǒng)級觸發(fā)器,。
通過子句ON {DATABASE | [schema.]SCHEMA}我們可以指定這個系統(tǒng)觸發(fā)器是定義在數(shù)據(jù)庫級上還是模式級上。只要發(fā)生了激活事件,,數(shù)據(jù)庫級觸發(fā)器就會激活,。而只有激活事件發(fā)生在某個具體模式中,相應的模式級觸發(fā)器才會激活,。如果使用SCHEMA關鍵字的時候沒有定義某個具體模式的名稱,,那么默認設置為擁有這個觸發(fā)器的模式。
9,、修改觸發(fā)器狀態(tài)和刪除觸發(fā)器
啟動或禁用觸發(fā)器
ALTER TRIGGER trigger_name {DISABLE | ENABLE};
刪除觸發(fā)器
DROP TRIGGER trigger_name;
還可以使用ALTER TABLE命令,,并附加使用ENABLE ALL TRIGGERS或DISABLE ALL TRIGGERS子句,同時將某一個表上的所有觸發(fā)器開啟或關閉,。
ALTER TABLE table_name {ENABLE | DISABLE} ALL TRIGGERS;
可以通過user_triggers來查看相應觸發(fā)器信息,。
10,、變化表和限制表 觸發(fā)器主體(trigger body)可以訪問的表和列上有一些限制,。在定義這些限制以前,,我們先看兩個概念—變化表和限制表。 “變化表”(mutating table)是被DML語句正在修改的表,。對于觸發(fā)器而言,,它就是定義觸發(fā)器的表。需要作為DELETE CASCADE參考完整性限制(referential integrity constraints)的結果進行更新的表也是變化的(mutating),。 “限制表”(constraining table)是可能需要對參考完整性限制執(zhí)行讀操作的表,。
為了更好的理解定義,我們看下面這個例子
view plaincopy to clipboardprint? student_id NUMBER(5) NOT NULL, department CHAR(3) NOT NULL, course NUMBER(3) NOT NULL, grade CHAR(1), CONSTRAINT rs_grade CHECK (grade IN ('A', 'B', 'C', 'D', 'E')), CONSTRAINT rs_student_id FOREIGN KEY (student_id) REFERENCES students (id), CONSTRAINT rs_department_course FOREIGN KEY (department, course) REFERENCES classes (department, course) ); --...
registered_students有兩個聲明的參考完整性限制,。 Students和classes都是registered_students的限制表,。
觸發(fā)器主體中的SQL不允許進行: 讀取或修改觸發(fā)語句(triggering statement)的任何變化表。這些表包括觸發(fā)表(triggering table )自己,。 轉(zhuǎn)載:http://blog.csdn.net/wh62592855/archive/2009/10/27/4735701.aspx |
|
來自: 艾雪溪 > 《Oracle勉強》