1、觸發(fā)器的概念 觸發(fā)器也是一種帶名的PL/SQL塊。觸發(fā)器類似于過程和函數(shù),因?yàn)樗鼈兌际菗碛新暶鳌?zhí)行和異常處理過程的帶名PL/SQL塊。與包類似,觸發(fā)器必須存儲(chǔ)在數(shù)據(jù)庫(kù)中并且不能被塊進(jìn)行本地化聲明。 對(duì)于觸發(fā)器而言,當(dāng)觸發(fā)事件發(fā)生的時(shí)候就會(huì)顯式地執(zhí)行該觸發(fā)器,并且觸發(fā)器不接受參數(shù)。
創(chuàng)建觸發(fā)器的語(yǔ)法如下
view plaincopy to clipboardprint? {BEFORE | AFTER | INSTEAD OF} triggering_event [referencing_clause] [WHEN trigger_condition] [FOR EACH ROW] Trigger_body; 其中referencing_clause子句的用途是通過一個(gè)不同的名稱,引用當(dāng)前正在被更新的記錄行中的數(shù)據(jù)。WHEN子句中的trigger_condition—如果出現(xiàn)—就應(yīng)該首先執(zhí)行判斷,只有當(dāng)這個(gè)條件值為真的時(shí)候,才會(huì)執(zhí)行觸發(fā)器的主體代碼。
2、DML觸發(fā)器的激活順序 1)執(zhí)行before語(yǔ)句級(jí)觸發(fā)器—如果存在這種觸發(fā)器 2)對(duì)受該語(yǔ)句影響的每一行記錄 執(zhí)行before行級(jí)觸發(fā)器—如果存在這種觸發(fā)器 執(zhí)行該語(yǔ)句本身 執(zhí)行after行級(jí)觸發(fā)器--如果存在這種觸發(fā)器 3)執(zhí)行after語(yǔ)句級(jí)觸發(fā)器--如果存在這種觸發(fā)器
同一種類型的觸發(fā)器的點(diǎn)火次序沒有經(jīng)過定義。如果該次序很重要的話,那么建議將所有這些操作組合到一個(gè)觸發(fā)器當(dāng)中。
3、行級(jí)觸發(fā)器中的關(guān)聯(lián)標(biāo)識(shí)符 觸發(fā)器的激活語(yǔ)句每處理一行數(shù)據(jù),行級(jí)觸發(fā)器就會(huì)激活一次。可以在這種行級(jí)觸發(fā)器內(nèi)部,訪問正被處理的記錄行中的數(shù)據(jù)。這是通過兩個(gè)關(guān)聯(lián)標(biāo)識(shí)符--:old和:new—實(shí)現(xiàn)的。關(guān)聯(lián)標(biāo)識(shí)符也是PL/SQL的一種特殊的綁定變量。標(biāo)識(shí)符前面的冒號(hào),既說明這二者都是綁定變量,同時(shí)也說明它們不是一般的PL/SQL變量。PL/SQL編譯器會(huì)將它們看作下面這個(gè)類型的記錄:
Triggering_table%ROWTYPE
其中triggering_table是在其上定義觸發(fā)器的表名。于是,下面這種引用
:new.field
就只有當(dāng)其中的field是該觸發(fā)表中的字段名時(shí)才會(huì)有效。
觸發(fā)語(yǔ)句
注意:INSERT語(yǔ)句上沒有定義:old標(biāo)識(shí)符,DELETE語(yǔ)句上也沒有定義:new標(biāo)識(shí)符。如果再INSERT語(yǔ)句上使用:old標(biāo)識(shí)符,或者在DELETE語(yǔ)句上使用:new標(biāo)識(shí)符,PL/SQL并不會(huì)產(chǎn)生錯(cuò)誤,但是這兩個(gè)字段值都會(huì)為NULL。
偽記錄 雖然在語(yǔ)法構(gòu)成上,會(huì)將:new和:old看作triggering_table%ROWTYPE類型的記錄,但是,實(shí)際上它們并不是記錄。因此,那些能夠在記錄上正常執(zhí)行的操作,并不能在:new和:old上執(zhí)行。例如,不能將它們作為一個(gè)整體進(jìn)行賦值。只能對(duì)其中的各個(gè)字段分別賦值。
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換一個(gè)不同的名稱。該子句出現(xiàn)在觸發(fā)事件以后,WHEN子句以前。其語(yǔ)法如下:
REFERENCING [OLD AS old_name] [NEW AS new_name]
在觸發(fā)器主體中,可以使用:old_name和:new_name分別代替:old和:new。
注意,在REFERENCING子句中關(guān)聯(lián)標(biāo)識(shí)符都不帶冒號(hào)。
如下面這個(gè)例子所示
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子句只能在行級(jí)觸發(fā)器中使用。如果在行級(jí)觸發(fā)器的定義中給出了WHEN子句,觸發(fā)器主體就只對(duì)滿足WHEN所定義條件的那些記錄行執(zhí)行。WHEN子句的基本形式如下:
WHEN trigger_condition
其中,trigger_condition是一個(gè)布爾表達(dá)式。每處理一行記錄,都會(huì)重新判斷該表達(dá)式的值。
也可以在trigger_condition內(nèi)部使用:new和:old記錄,但是與REFERENCING子句一樣,在trigger_condition內(nèi)部使用:new和:old時(shí),不需要冒號(hào)。僅在觸發(fā)器主體中才需要使用冒號(hào)。
5、觸發(fā)器謂詞 可以在觸發(fā)器內(nèi)部使用3個(gè)布爾函數(shù),判斷觸發(fā)該觸發(fā)器的到底是什么操作。這3個(gè)謂詞分別是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ā)器僅可以定義在視圖上(關(guān)系型的或?qū)ο螅⑶宜鼈兛梢蕴娲c(diǎn)火它們的DML語(yǔ)句進(jìn)行點(diǎn)火。INSTEAD-OF觸發(fā)器必須是行級(jí)的。
7、觸發(fā)器的限制 觸發(fā)器的主體是一個(gè)PL/SQL塊。在PL/SQL塊中可以使用的所有語(yǔ)句在觸發(fā)器主體中都是合法的,但是要受到下面限制的約束:
觸發(fā)器不應(yīng)該使用事務(wù)控制語(yǔ)句—COMMIT、ROLLBACK或SAVEPOINT。觸發(fā)器作為觸發(fā)語(yǔ)句執(zhí)行的一部分被點(diǎn)火,它和觸發(fā)語(yǔ)句在同一個(gè)事務(wù)中。當(dāng)觸發(fā)語(yǔ)句被提交或撤回提交時(shí),觸發(fā)器的工作也相應(yīng)被提交會(huì)撤回提交。 觸發(fā)器P-Code 當(dāng)包或者子程序存儲(chǔ)在數(shù)據(jù)字典中時(shí),存儲(chǔ)的除了該對(duì)象的源代碼還有經(jīng)過編譯的p-code。但是對(duì)于觸發(fā)器來說就不是這樣的。在數(shù)據(jù)字典中唯一存儲(chǔ)的是觸發(fā)器的源代碼,而不是p-code。結(jié)果,每次當(dāng)從數(shù)據(jù)字典中重新讀出觸發(fā)器時(shí),必須要進(jìn)行編譯。這對(duì)觸發(fā)器的定義和使用的方式不會(huì)帶來什么影響,但是會(huì)影響觸發(fā)器的性能。
8、系統(tǒng)觸發(fā)器 我們前面所看到的DML觸發(fā)器和INSTEAD-OF觸發(fā)器都是基于DML事件。而另一方面,系統(tǒng)觸發(fā)器的激活則是基于兩種不同的事件:DDL事件或數(shù)據(jù)庫(kù)事件。DDL事件包括CREATE、ALTER或DROP語(yǔ)句,而數(shù)據(jù)庫(kù)事件包括數(shù)據(jù)庫(kù)服務(wù)器的啟動(dòng)/關(guān)閉事件,用戶的登陸/斷開事件,以及服務(wù)器錯(cuò)誤。創(chuàng)建系統(tǒng)觸發(fā)器的語(yǔ)法如下:
{BEFORE | AFTER} {ddl_event_list | database_event_list} ON {DATABASE | [schema.]SCHEMA} [when_clause] Trigger_body;
其中,ddl_event_list是由OR關(guān)鍵字隔開的一個(gè)或多個(gè)DDL事件,database_event_list則是由OR關(guān)鍵字隔開的一個(gè)或多個(gè)數(shù)據(jù)庫(kù)事件。
注意:不能創(chuàng)建INSTEAD-OF系統(tǒng)級(jí)觸發(fā)器。
通過子句ON {DATABASE | [schema.]SCHEMA}我們可以指定這個(gè)系統(tǒng)觸發(fā)器是定義在數(shù)據(jù)庫(kù)級(jí)上還是模式級(jí)上。只要發(fā)生了激活事件,數(shù)據(jù)庫(kù)級(jí)觸發(fā)器就會(huì)激活。而只有激活事件發(fā)生在某個(gè)具體模式中,相應(yīng)的模式級(jí)觸發(fā)器才會(huì)激活。如果使用SCHEMA關(guān)鍵字的時(shí)候沒有定義某個(gè)具體模式的名稱,那么默認(rèn)設(shè)置為擁有這個(gè)觸發(fā)器的模式。
9、修改觸發(fā)器狀態(tài)和刪除觸發(fā)器
啟動(dòng)或禁用觸發(fā)器
ALTER TRIGGER trigger_name {DISABLE | ENABLE};
刪除觸發(fā)器
DROP TRIGGER trigger_name;
還可以使用ALTER TABLE命令,并附加使用ENABLE ALL TRIGGERS或DISABLE ALL TRIGGERS子句,同時(shí)將某一個(gè)表上的所有觸發(fā)器開啟或關(guān)閉。
ALTER TABLE table_name {ENABLE | DISABLE} ALL TRIGGERS;
可以通過user_triggers來查看相應(yīng)觸發(fā)器信息。
10、變化表和限制表 觸發(fā)器主體(trigger body)可以訪問的表和列上有一些限制。在定義這些限制以前,我們先看兩個(gè)概念—變化表和限制表。 “變化表”(mutating table)是被DML語(yǔ)句正在修改的表。對(duì)于觸發(fā)器而言,它就是定義觸發(fā)器的表。需要作為DELETE CASCADE參考完整性限制(referential integrity constraints)的結(jié)果進(jìn)行更新的表也是變化的(mutating)。 “限制表”(constraining table)是可能需要對(duì)參考完整性限制執(zhí)行讀操作的表。
為了更好的理解定義,我們看下面這個(gè)例子
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有兩個(gè)聲明的參考完整性限制。 Students和classes都是registered_students的限制表。
觸發(fā)器主體中的SQL不允許進(jìn)行: 讀取或修改觸發(fā)語(yǔ)句(triggering statement)的任何變化表。這些表包括觸發(fā)表(triggering table )自己。 轉(zhuǎn)載:http://blog.csdn.net/wh62592855/archive/2009/10/27/4735701.aspx |
|