游标和触发器
視頻課:https://edu.csdn.net/course/play/7940
本章將學(xué)習(xí)oracle游標(biāo)和觸發(fā)器。在實(shí)際開發(fā)過程中,有一些復(fù)雜的邏輯必須對(duì)表中每一條記錄分別進(jìn)行單獨(dú)處理,此時(shí)必須使用游標(biāo)。游標(biāo)提供了一種用于實(shí)現(xiàn)更加復(fù)雜的業(yè)務(wù)邏輯的途徑。游標(biāo)是指向上下文的指針。Oracle觸發(fā)器是一種特殊的過程,它也有聲明段,可執(zhí)行段和異常處理段。在表或視圖上創(chuàng)建針對(duì)INSERT,UPDATE,DELETE操作的觸發(fā)器,只要在表或視圖上發(fā)生INSERT,UPDATE,DELETE操作時(shí)自動(dòng)觸發(fā)。
?
FETCH…INTO語句每次只能處理一行數(shù)據(jù),為了處理結(jié)果集中的多行數(shù)據(jù),必須使用循環(huán)語句
進(jìn)行處理。
?
?
從Oracle 9i開始,通過使用?FETCH…BULK COLLECT INTO語句,可以一次性提取結(jié)果集中的所有數(shù)據(jù)。
6.1?.2參數(shù)游標(biāo)
參數(shù)游標(biāo)是指帶有參數(shù)的游標(biāo)。在定義了參數(shù)游標(biāo)之后,使用不同參數(shù)值多次打開游標(biāo)可以生成不同的結(jié)果集。
語法:
Cursor cursor_name(parameter_namedatatype) is ?select_statement
上述語法中,當(dāng)定義參數(shù)游標(biāo)時(shí),需要指定參數(shù)名及其數(shù)據(jù)類型。
?
6.1?游標(biāo)
SQL語言是面向集合的,其結(jié)果一般是集合量?(多條記錄),而PL/SQL語言的變量一般是標(biāo)量,一組變量一次只能存放一條記錄。查詢結(jié)果的記錄數(shù)是不確定的,事先無法確定需要聲明多少個(gè)變量,所以僅使用變量并不能完全滿足?SQL語句向應(yīng)用輸出數(shù)據(jù)的要求。為此,PL/SQL 中引入了游標(biāo)?(cursor)的概念,使用游標(biāo)來協(xié)調(diào)這兩種不同的處理方式。當(dāng)在PL/SQL塊中執(zhí)行查詢語句?(SELECT)和數(shù)據(jù)操縱語句?(DML)時(shí),0racle會(huì)為其分配上下文區(qū)?(Context Area)。游標(biāo)是指向上下文區(qū)的指針,它為應(yīng)用提供了一種對(duì)具有多行數(shù)據(jù)查詢結(jié)果集中的每一行數(shù)據(jù)分別進(jìn)行單獨(dú)處理的方法。
6.1?.1顯式游標(biāo)
游標(biāo)分為顯式游標(biāo)和隱含游標(biāo)兩種。其中,隱含游標(biāo)用于處理SELECT…INTO和DML語句,而顯式游標(biāo)則用于處理SELECT語句返回的多行數(shù)據(jù)。
為了處理SELECT語句返回的多行數(shù)據(jù),開發(fā)人員可以使用顯式游標(biāo)。使用顯式游標(biāo)包括定義游標(biāo)?(DECLARE)、打開游標(biāo)?(OPEN)、提取數(shù)據(jù)?(FETCH)和關(guān)閉游標(biāo)?(CLOSE)4個(gè)階段。
(1?)定義游標(biāo)。
在使用顯式游標(biāo)之前,必須首先在定義部分定義游標(biāo),用于指定游標(biāo)所對(duì)應(yīng)的?SELECT語句。
語法:
Cursor cursor_nameisselect_statement
上述語法中,cursor_name用于指定游標(biāo)名稱,select_statement用于指定游標(biāo)對(duì)應(yīng)的SELECT語句。
(2)打開游標(biāo)。
當(dāng)打開游標(biāo)時(shí),Oracle會(huì)執(zhí)行游標(biāo)所對(duì)應(yīng)的?SELECT語句,并將?SELECT語句的結(jié)果暫時(shí)存放在結(jié)果集中。
語法:
Open ?cursor_name;
上述語法中,cursor_name必須是在定義部分已經(jīng)被定義的游標(biāo)。
(3)提取數(shù)據(jù)。
在打開游標(biāo)之后,SELECT語句的結(jié)果被臨時(shí)存放在游標(biāo)結(jié)果集中。為了處理結(jié)果集合中的數(shù)據(jù),需要使用FETCH語句提取游標(biāo)數(shù)據(jù)。在Oracle 9i之前,使用FETCH語句一次只能提取一行數(shù)據(jù)。從Oracle 9i開始,通過使用FETCH…BULK COLLECT INTO語句,一次可以提取多行數(shù)據(jù)。
語法:
Fetch ??cursor_name ?into variable1,variable2,…;
或者
Fetch cursor_name ?bulk ?collect ?into ?collect1,collect2,…;
上述語法中,variablevariable1,variable2,…用于指定接收游標(biāo)數(shù)據(jù)的變量,collectcollect1,collect2,…用于指定接收游標(biāo)結(jié)果的集合變量。
(4)關(guān)閉游標(biāo)。
在提取并處理了結(jié)果集的所有數(shù)據(jù)之后,就可以關(guān)閉游標(biāo)并釋放其結(jié)果集了。
語法:
Close ?cursor_name;
在實(shí)際應(yīng)用中,我們需要對(duì)游標(biāo)進(jìn)行判斷操作,顯式游標(biāo)屬性用于返回顯式游標(biāo)的執(zhí)行信息,包括%ISOPEN、%FOUND、%NOTFOUND 以及?% ROWCOUNT等屬性。當(dāng)使用顯式游標(biāo)屬性時(shí),必須在顯式游標(biāo)屬性之前添加顯式游標(biāo)名作為前綴,其格式為:
游標(biāo)名. 屬性名
顯示游標(biāo)的屬性如表3.1.23-1-3所示。
表3.1.23-1-3?顯式游標(biāo)屬性
屬性名 | 說明 |
%isopen | 確定游標(biāo)是否已經(jīng)打開,如果打開返回true,否則返回false。 |
%found | 用于檢查是否從結(jié)果集中提取到數(shù)據(jù),如果提取到返回true,否則返回false。 |
%notfound | 如果提取到數(shù)據(jù)返回false,否則返回true。 |
%rowcount | 用于返回到當(dāng)前為止已經(jīng)提取到的實(shí)際行數(shù)。 |
注意:
定義參數(shù)游標(biāo)時(shí),游標(biāo)參數(shù)只能指定數(shù)據(jù)類型而不能指定長度。
6.1?.3游標(biāo)FOR循環(huán)
游標(biāo)FOR循環(huán)是在PL/SQL塊中使用游標(biāo)的最簡單方式,它可以簡化對(duì)游標(biāo)的處理。當(dāng)使用游標(biāo)。For循環(huán)時(shí),?Oracle會(huì)隱含地打開游標(biāo),提取游標(biāo)數(shù)據(jù)并關(guān)閉游標(biāo)。
語法:
For ?record_name ??in ??cursor_name ?loop
……
End loop;
上述語法中,cursor_name是已經(jīng)定義的游標(biāo)名,record_name是Oracle 隱含定義的記錄變量名。當(dāng)使用游標(biāo)FOR循環(huán)時(shí),在執(zhí)行循環(huán)體內(nèi)容之前Oracle會(huì)隱含地打開游標(biāo),并且每循環(huán)一次提取一次數(shù)據(jù),在提取了所有數(shù)據(jù)之后自動(dòng)退出循環(huán)并隱含地關(guān)閉游標(biāo)。
6.1?使用游標(biāo)變量
當(dāng)使用顯式游標(biāo)時(shí),需要在定義部分指定其所對(duì)應(yīng)的靜態(tài)?SELECT語句;而當(dāng)使用游標(biāo)變量時(shí),開發(fā)人員可以在打開游標(biāo)變量時(shí)指定其所對(duì)應(yīng)的?SELECT語句。開發(fā)人員可以在應(yīng)用中直接使用PL/SQL游標(biāo)變量。在PL/SQL塊中使用游標(biāo)變量包括定義游標(biāo)變量、打開游標(biāo)、提取游標(biāo)數(shù)據(jù)、關(guān)閉游標(biāo)4個(gè)階段,具體步驟如下:
1. 定義REF CURSOR類型和游標(biāo)變量
為了在PL/SQL塊中定義游標(biāo)變量,必須首先定義REF CURSOR類型,然后才能定義游標(biāo)變量。
語法:
Type ?ref_type_name ?is ref ?cursor;
Cursor_variable??ref_type_name;
上述語法中,ref_type_name用于指定自定義類型名,cursor_variable用于指定游標(biāo)變量名。另外,不能在包內(nèi)定義游標(biāo)變量。
隱含游標(biāo)
隱含游標(biāo)由?PL/SQL控制。當(dāng)執(zhí)行一條DML語句或者?SELECT…INTO語句時(shí),都會(huì)創(chuàng)建一個(gè)隱含游標(biāo)。隱含游標(biāo)的名稱是?SQL,不能對(duì)?SQL游標(biāo)顯式地執(zhí)行OPEN、FETCH和?CLOSE語句。Oracle 隱式地打開、提取,并總是自動(dòng)地關(guān)閉?SQL 游標(biāo)。隱含游標(biāo)屬性包括?SQL%FOUND、SQL%NOTFOUND、SQL%ROWCOUNT、SQL%ISOPEN等。
1. SQL% FOUND
只有DML語句影響一行或多行時(shí),SQL%FOUND屬性才返回true。?
SQL% NOT FOUND
SQL%NOTFOUND屬性的作用與?SQL%FOUND屬性的剛好相反。如果?DML語句沒有影響任何行數(shù),則?SQL%NOTFOUND屬性返回?TRUBTRUE,否則返回?FALSE。
3. SQL% ROW COUNT
SQL%ROWCOUNT?屬性會(huì)返回?DML語句影響的行數(shù)。如果?DML語句沒有影響任何行,則SQL%ROWCOUNT屬性將返回?0。SQL%ROWCOUNT屬性的使用方法可參考圖3.1.20中sql%found的用法。
4. SQL% ISOPEN
SQL%ISOPEN屬性用于判斷SQL游標(biāo)是否已經(jīng)打開。在執(zhí)行?SQL語句之后,Oracle?自動(dòng)地關(guān)閉SQL游標(biāo),所以隱含游標(biāo)的SQL%ISOPEN屬性始終為FALSE。
6.2?觸發(fā)器
觸發(fā)器是許多關(guān)系數(shù)據(jù)庫系統(tǒng)都提供的一項(xiàng)技術(shù)。在ORACLE系統(tǒng)里,觸發(fā)器類似過程和函數(shù),都有聲明,執(zhí)行和異常處理過程的PL/SQL塊。
6.2.1觸發(fā)器類型
????觸發(fā)器在數(shù)據(jù)庫里以獨(dú)立的對(duì)象存儲(chǔ),它與存儲(chǔ)過程和函數(shù)不同的是,存儲(chǔ)過程與函數(shù)需要用戶顯示調(diào)用才執(zhí)行,而觸發(fā)器是由一個(gè)事件來啟動(dòng)運(yùn)行。即觸發(fā)器是當(dāng)某個(gè)事件發(fā)生時(shí)自動(dòng)地隱式運(yùn)行。并且,觸發(fā)器不能接收參數(shù)。所以運(yùn)行觸發(fā)器就叫觸發(fā)或點(diǎn)火(firing)。ORACLE事件指的是對(duì)數(shù)據(jù)庫的表進(jìn)行的INSERT、UPDATE及DELETE操作或?qū)σ晥D進(jìn)行類似的操作。ORACLE將觸發(fā)器的功能擴(kuò)展到了ORACLE系統(tǒng)事件的發(fā)生,如數(shù)據(jù)庫的啟動(dòng)與關(guān)閉等,也會(huì)觸發(fā)觸發(fā)器。所以觸發(fā)器常用來完成由數(shù)據(jù)庫的完整性約束難以完成的復(fù)雜業(yè)務(wù)規(guī)則的約束,或用來監(jiān)視對(duì)數(shù)據(jù)庫的各種操作,實(shí)現(xiàn)審計(jì)的功能。
1 DML觸發(fā)器
????ORACLE可以在DML語句進(jìn)行觸發(fā),可以在DML操作前或操作后進(jìn)行觸發(fā),并且可以對(duì)每個(gè)行或語句操作上進(jìn)行觸發(fā)。
2 替代觸發(fā)器
????由于在ORACLE里,不能直接對(duì)由兩個(gè)以上的表建立的視圖進(jìn)行操作。所以給出了替代觸發(fā)器。它就是ORACLE 8專門為進(jìn)行視圖操作的一種處理方法。
3 系統(tǒng)觸發(fā)器
ORACLE 11g?提供了第三種類型的觸發(fā)器叫系統(tǒng)觸發(fā)器。它可以在ORACLE數(shù)據(jù)庫系統(tǒng)的事件中進(jìn)行觸發(fā),如ORACLE系統(tǒng)的啟動(dòng)與關(guān)閉等。
?
觸發(fā)器組成:
l 觸發(fā)事件:引起觸發(fā)器被觸發(fā)的事件。 例如:DML語句(INSERT, UPDATE, DELETE語句對(duì)表或視圖執(zhí)行數(shù)據(jù)處理操作)、DDL語句(如CREATE、ALTER、DROP語句在數(shù)據(jù)庫中創(chuàng)建、修改、刪除模式對(duì)象)、數(shù)據(jù)庫系統(tǒng)事件(如系統(tǒng)啟動(dòng)或退出、異常錯(cuò)誤)、用戶事件(如登錄或退出數(shù)據(jù)庫)。
觸發(fā)時(shí)間:即該TRIGGER 是在觸發(fā)事件發(fā)生之前(BEFORE)還是之后(AFTER)觸發(fā),也就是觸發(fā)事件和該TRIGGER 的操作順序。
觸發(fā)操作:即該TRIGGER 被觸發(fā)之后的目的和意圖,正是觸發(fā)器本身要做的事情。 例如:PL/SQL 塊。
觸發(fā)對(duì)象:包括表、視圖、模式、數(shù)據(jù)庫。只有在這些對(duì)象上發(fā)生了符合觸發(fā)條件的觸發(fā)事件,才會(huì)執(zhí)行觸發(fā)操作。
觸發(fā)條件:由WHEN子句指定一個(gè)邏輯表達(dá)式。只有當(dāng)該表達(dá)式的值為TRUE時(shí),遇到觸發(fā)事件才會(huì)自動(dòng)執(zhí)行觸發(fā)器,使其執(zhí)行觸發(fā)操作。
觸發(fā)頻率:說明觸發(fā)器內(nèi)定義的動(dòng)作被執(zhí)行的次數(shù)。即語句級(jí)(STATEMENT)觸發(fā)器和行級(jí)(ROW)觸發(fā)器。
語句級(jí)(STATEMENT)觸發(fā)器:是指當(dāng)某觸發(fā)事件發(fā)生時(shí),該觸發(fā)器只執(zhí)行一次;
行級(jí)(ROW)觸發(fā)器:是指當(dāng)某觸發(fā)事件發(fā)生時(shí),對(duì)受到該操作影響的每一行數(shù)據(jù),觸發(fā)器都單獨(dú)執(zhí)行一次。
編寫觸發(fā)器時(shí),需要注意以下幾點(diǎn):
1. 觸發(fā)器不接受參數(shù)。
2. 一個(gè)表上最多可有12個(gè)觸發(fā)器,但同一時(shí)間、同一事件、同一類型的觸發(fā)器只能有一個(gè)。并各觸發(fā)器之間不能有矛盾。
3.?在一個(gè)表上的觸發(fā)器越多,對(duì)在該表上的DML操作的性能影響就越大。
4.?觸發(fā)器最大為32KB。若確實(shí)需要,可以先建立過程,然后在觸發(fā)器中用CALL語句進(jìn)行調(diào)用。
5. 在觸發(fā)器的執(zhí)行部分只能用DML語句(SELECT、INSERT、UPDATE、DELETE),不能使用DDL語句(CREATE、ALTER、DROP)。
6. 觸發(fā)器中不能包含事務(wù)控制語句(COMMIT,ROLLBACK,SAVEPOINT)。因?yàn)橛|發(fā)器是觸發(fā)語句的一部分,觸發(fā)語句被提交、回退時(shí),觸發(fā)器也被提交、回退了。在觸發(fā)器主體中調(diào)用的任何過程、函數(shù),都不能使用事務(wù)控制語句。在觸發(fā)器主體中不能申明任何Long和blob變量。新值new和舊值old也不能向表中的任何long和blob列。
7. 不同類型的觸發(fā)器(如DML觸發(fā)器、INSTEAD OF觸發(fā)器、系統(tǒng)觸發(fā)器)的語法格式和作用有較大區(qū)別。
?
6.2.2創(chuàng)建觸發(fā)器
創(chuàng)建觸發(fā)器的一般語法是:
CREATE [OR REPLACE] TRIGGER trigger_name
{BEFORE | AFTER }
{INSERT | DELETE | UPDATE [OF column [, column …]]}
[OR {INSERT | DELETE | UPDATE [OF column [, column …]]}...]
ON [schema.]table_name | [schema.]view_name
[REFERENCING {OLD [AS] old | NEW [AS] new}]
[FOR EACH ROW ]
[WHEN condition]
PL/SQL_BLOCK | CALL procedure_name;
?
其中:
BEFORE 和AFTER指出觸發(fā)器的觸發(fā)時(shí)序分別為前觸發(fā)和后觸發(fā)方式,前觸發(fā)是在執(zhí)行觸發(fā)事件之前觸發(fā)當(dāng)前所創(chuàng)建的觸發(fā)器,后觸發(fā)是在執(zhí)行觸發(fā)事件之后觸發(fā)當(dāng)前所創(chuàng)建的觸發(fā)器。
FOR EACH ROW選項(xiàng)說明觸發(fā)器為行觸發(fā)器。行觸發(fā)器和語句觸發(fā)器的區(qū)別表現(xiàn)在:行觸發(fā)器要求當(dāng)一個(gè)DML語句操走影響數(shù)據(jù)庫中的多行數(shù)據(jù)時(shí),對(duì)于其中的每個(gè)數(shù)據(jù)行,只要它們符合觸發(fā)約束條件,均激活一次觸發(fā)器;而語句觸發(fā)器將整個(gè)語句操作作為觸發(fā)事件,當(dāng)它符合約束條件時(shí),激活一次觸發(fā)器。當(dāng)省略FOR EACH ROW 選項(xiàng)時(shí),BEFORE 和AFTER 觸發(fā)器為語句觸發(fā)器,而INSTEAD OF 觸發(fā)器則只能為行觸發(fā)器。
REFERENCING 子句說明相關(guān)名稱,在行觸發(fā)器的PL/SQL塊和WHEN 子句中可以使用相關(guān)名稱參照當(dāng)前的新、舊列值,默認(rèn)的相關(guān)名稱分別為OLD和NEW。觸發(fā)器的PL/SQL塊中應(yīng)用相關(guān)名稱時(shí),必須在它們之前加冒號(hào)(:),但在WHEN子句中則不能加冒號(hào)。
WHEN 子句說明觸發(fā)約束條件。Condition 為一個(gè)邏輯表達(dá)時(shí),其中必須包含相關(guān)名稱,而不能包含查詢語句,也不能調(diào)用PL/SQL 函數(shù)。WHEN 子句指定的觸發(fā)約束條件只能用在BEFORE 和AFTER 行觸發(fā)器中,不能用在INSTEAD OF 行觸發(fā)器和其它類型的觸發(fā)器中。
當(dāng)一個(gè)基表被修改( INSERT, UPDATE, DELETE)時(shí)要執(zhí)行的存儲(chǔ)過程,執(zhí)行時(shí)根據(jù)其所依附的基表改動(dòng)而自動(dòng)觸發(fā),因此與應(yīng)用程序無關(guān),用數(shù)據(jù)庫觸發(fā)器可以保證數(shù)據(jù)的一致性和完整性。
?
每張表最多可建立12 種類型的觸發(fā)器,它們是:
BEFORE INSERT
BEFORE INSERT FOR EACH ROW
AFTER INSERT
AFTER INSERT FOR EACH ROW
BEFORE UPDATE
BEFORE UPDATE FOR EACH ROW
AFTER UPDATE
AFTER UPDATE FOR EACH ROW
BEFORE DELETE
BEFORE DELETE FOR EACH ROW
AFTER DELETE
AFTER DELETE FOR EACH ROW
6.2.3觸發(fā)器觸發(fā)次序
1. 執(zhí)行 BEFORE語句級(jí)觸發(fā)器;
2. 對(duì)與受語句影響的每一行:
l 執(zhí)行 BEFORE行級(jí)觸發(fā)器
l 執(zhí)行 DML語句
l 執(zhí)行 AFTER行級(jí)觸發(fā)器
3. 執(zhí)行 AFTER語句級(jí)觸發(fā)器
?
6.2.4創(chuàng)建DML觸發(fā)器
????觸發(fā)器名與過程名和包的名字不一樣,它是單獨(dú)的名字空間,因而觸發(fā)器名可以和表或過程有相同的名字,但在一個(gè)模式中觸發(fā)器名不能相同。
1. DML觸發(fā)器的限制
??CREATE TRIGGER語句文本的字符長度不能超過32KB;
觸發(fā)器體內(nèi)的SELECT 語句只能為SELECT … INTO …結(jié)構(gòu),或者為定義游標(biāo)所使用的SELECT 語句。
觸發(fā)器中不能使用數(shù)據(jù)庫事務(wù)控制語句 COMMIT; ROLLBACK, SVAEPOINT
由觸發(fā)器所調(diào)用的過程或函數(shù)也不能使用數(shù)據(jù)庫事務(wù)控制語句;
觸發(fā)器中不能使用LONG, LONG RAW 類型;
觸發(fā)器內(nèi)可以參照LOB 類型列的列值,但不能通過 :NEW 修改LOB列中的數(shù)據(jù);
?
2.DML觸發(fā)器基本要點(diǎn)
觸發(fā)時(shí)機(jī):指定觸發(fā)器的觸發(fā)時(shí)間。如果指定為BEFORE,則表示在執(zhí)行DML操作之前觸發(fā),以便防止某些錯(cuò)誤操作發(fā)生或?qū)崿F(xiàn)某些業(yè)務(wù)規(guī)則;如果指定為AFTER,則表示在執(zhí)行DML操作之后觸發(fā),以便記錄該操作或做某些事后處理。
觸發(fā)事件:引起觸發(fā)器被觸發(fā)的事件,即DML操作(INSERT、UPDATE、DELETE)。既可以是單個(gè)觸發(fā)事件,也可以是多個(gè)觸發(fā)事件的組合(只能使用OR邏輯組合,不能使用AND邏輯組合)。
條件謂詞:當(dāng)在觸發(fā)器中包含多個(gè)觸發(fā)事件(INSERT、UPDATE、DELETE)的組合時(shí),為了分別針對(duì)不同的事件進(jìn)行不同的處理,需要使用ORACLE提供的如下條件謂詞。
1)INSERTING:當(dāng)觸發(fā)事件是INSERT時(shí),取值為TRUE,否則為FALSE。
2)UPDATING [(column_1,column_2,…,column_x)]:當(dāng)觸發(fā)事件是UPDATE ?????時(shí),如果修改了column_x列,則取值為TRUE,否則為FALSE。其中column_x是可選的。
3)DELETING:當(dāng)觸發(fā)事件是DELETE時(shí),則取值為TRUE,否則為FALSE。
觸發(fā)對(duì)象:指定觸發(fā)器是創(chuàng)建在哪個(gè)表、視圖上。
觸發(fā)類型:是語句級(jí)還是行級(jí)觸發(fā)器。
觸發(fā)條件:由WHEN子句指定一個(gè)邏輯表達(dá)式,只允許在行級(jí)觸發(fā)器上指定觸發(fā)條件,指定UPDATING后面的列的列表。
?
使用觸發(fā)器謂詞
????ORACLE 提供三個(gè)參數(shù)INSERTING, UPDATING, DELETING 用于判斷觸發(fā)了哪些操作。
表3-1-4 觸發(fā)器謂詞
謂詞 | 行為 |
INSERTING | 如果觸發(fā)語句是 INSERT 語句,則為TRUE,否則為FALSE |
UPDATING | 如果觸發(fā)語句是 UPDATE語句,則為TRUE,否則為FALSE |
DELETING | 如果觸發(fā)語句是 DELETE 語句,則為TRUE,否則為FALSE |
?
示例6.8: 建立一個(gè)觸發(fā)器, 當(dāng)職工表 emp 表被刪除一條記錄時(shí),把被刪除記錄寫到職工表刪除日志表中去。
示例6.9:限制對(duì)Departments表修改(包括INSERT,DELETE,UPDATE)的時(shí)間范圍,即不允許在非工作時(shí)間修改departments表。
創(chuàng)建替代(INSTEAD OF)觸發(fā)器
創(chuàng)建觸發(fā)器的一般語法是:
?
CREATE [OR REPLACE] TRIGGER trigger_name
INSTEAD OF
{INSERT | DELETE | UPDATE [OF column [, column …]]}
[OR {INSERT | DELETE | UPDATE [OF column [, column …]]}...]
ON [schema.] view_name --只能定義在視圖上
[REFERENCING {OLD [AS] old | NEW [AS] new| PARENT as parent}]
[FOR EACH ROW ] --因?yàn)镮NSTEAD OF觸發(fā)器只能在行級(jí)上觸發(fā),所以沒有必要指定
[WHEN condition]
PL/SQL_block | CALL procedure_name;
?
其中: INSTEAD OF 選項(xiàng)使ORACLE激活觸發(fā)器,而不執(zhí)行觸發(fā)事件。只能對(duì)視圖和對(duì)象視圖建立INSTEAD OF觸發(fā)器,而不能對(duì)表、模式和數(shù)據(jù)庫建立INSTEAD OF 觸發(fā)器。
FOR EACH ROW選項(xiàng)說明觸發(fā)器為行觸發(fā)器。行觸發(fā)器和語句觸發(fā)器的區(qū)別表現(xiàn)在:行觸發(fā)器要求當(dāng)一個(gè)DML語句操走影響數(shù)據(jù)庫中的多行數(shù)據(jù)時(shí),對(duì)于其中的每個(gè)數(shù)據(jù)行,只要它們符合觸發(fā)約束條件,均激活一次觸發(fā)器;而語句觸發(fā)器將整個(gè)語句操作作為觸發(fā)事件,當(dāng)它符合約束條件時(shí),激活一次觸發(fā)器。當(dāng)省略FOR EACH ROW 選項(xiàng)時(shí),BEFORE 和AFTER 觸發(fā)器為語句觸發(fā)器,而INSTEAD OF 觸發(fā)器則為行觸發(fā)器。
?REFERENCING 子句說明相關(guān)名稱,在行觸發(fā)器的PL/SQL塊和WHEN 子句中可以使用相關(guān)名稱參照當(dāng)前的新、舊列值,默認(rèn)的相關(guān)名稱分別為OLD和NEW。觸發(fā)器的PL/SQL塊中應(yīng)用相關(guān)名稱時(shí),必須在它們之前加冒號(hào)(:),但在WHEN子句中則不能加冒號(hào)。
WHEN 子句說明觸發(fā)約束條件。Condition 為一個(gè)邏輯表達(dá)時(shí),其中必須包含相關(guān)名稱,而不能包含查詢語句,也不能調(diào)用PL/SQL 函數(shù)。WHEN 子句指定的觸發(fā)約束條件只能用在BEFORE 和AFTER 行觸發(fā)器中,不能用在INSTEAD OF 行觸發(fā)器和其它類型的觸發(fā)器中。
INSTEAD_OF 用于對(duì)視圖的DML觸發(fā),由于視圖有可能是由多個(gè)表進(jìn)行聯(lián)結(jié)(join)而成,因而并非是所有的聯(lián)結(jié)都是可更新的。但可以按照所需的方式執(zhí)行更新,例如下面情況:
示例3.13:創(chuàng)建instead of觸發(fā)器
圖6.1.13 創(chuàng)建視圖
?
在此視圖中直接刪除是非法:
SQL>DELETE FROM emp_view WHERE deptno=10;
ERROR 位于第 1 行:
ORA-01732: 此視圖的數(shù)據(jù)操縱操作非法
但是我們可以創(chuàng)建INSTEAD_OF觸發(fā)器來為 DELETE 操作執(zhí)行所需的處理,即刪除EMP表中所有基準(zhǔn)行:
?
DELETE FROM emp_view WHERE deptno=10;
DROP TRIGGER emp_view_delete;
DROP VIEW emp_view;
?
創(chuàng)建INSTEAD OF觸發(fā)器需要注意以下幾點(diǎn):
1.只能被創(chuàng)建在視圖上,并且該視圖沒有指定WITH CHECK OPTION選項(xiàng)。
????????2.不能指定BEFORE 或 AFTER選項(xiàng)。
3.FOR EACH ROW子可是可選的,即INSTEAD OF觸發(fā)器只能在行級(jí)上觸發(fā)、或只能是行級(jí)觸發(fā)器,沒有必要指定。
4.沒有必要在針對(duì)一個(gè)表的視圖上創(chuàng)建INSTEAD OF觸發(fā)器,只要?jiǎng)?chuàng)建DML觸發(fā)器就可以了。
?
6.2.6創(chuàng)建系統(tǒng)事件觸發(fā)器
????ORACLE ?11G提供的系統(tǒng)事件觸發(fā)器可以在DDL或數(shù)據(jù)庫系統(tǒng)上被觸發(fā)。DDL指的是數(shù)據(jù)定義語言,如CREATE 、ALTER及DROP 等。而數(shù)據(jù)庫系統(tǒng)事件包括數(shù)據(jù)庫服務(wù)器的啟動(dòng)或關(guān)閉,用戶的登錄與退出、數(shù)據(jù)庫服務(wù)錯(cuò)誤等。創(chuàng)建系統(tǒng)觸發(fā)器的語法如下:
創(chuàng)建觸發(fā)器的一般語法是:
CREATE OR REPLACE TRIGGER [sachema.]trigger_name
{BEFORE|AFTER}
{ddl_event_list | database_event_list}
ON { DATABASE | [schema.]SCHEMA }
[WHEN condition]
PL/SQL_block | CALL procedure_name;
?
其中: ddl_event_list:一個(gè)或多個(gè)DDL 事件,事件間用 OR 分開;
?database_event_list:一個(gè)或多個(gè)數(shù)據(jù)庫事件,事件間用 OR 分開;
?系統(tǒng)事件觸發(fā)器既可以建立在一個(gè)模式上,又可以建立在整個(gè)數(shù)據(jù)庫上。當(dāng)建立在模式(SCHEMA)之上時(shí),只有模式所指定用戶的DDL操作和它們所導(dǎo)致的錯(cuò)誤才激活觸發(fā)器, 默認(rèn)時(shí)為當(dāng)前用戶模式。當(dāng)建立在數(shù)據(jù)庫(DATABASE)之上時(shí),該數(shù)據(jù)庫所有用戶的DDL操作和他們所導(dǎo)致的錯(cuò)誤,以及數(shù)據(jù)庫的啟動(dòng)和關(guān)閉均可激活觸發(fā)器。要在數(shù)據(jù)庫之上建立觸發(fā)器時(shí),要求用戶具有ADMINISTER DATABASE TRIGGER權(quán)限。
?
事件 | 允許的時(shí)機(jī) | 說明 |
STARTUP | AFTER | 啟動(dòng)數(shù)據(jù)庫實(shí)例之后觸發(fā) |
SHUTDOWN | BEFORE | 關(guān)閉數(shù)據(jù)庫實(shí)例之前觸發(fā)(非正常關(guān)閉不觸發(fā)) |
SERVERERROR | AFTER | 數(shù)據(jù)庫服務(wù)器發(fā)生錯(cuò)誤之后觸發(fā) |
LOGON | AFTER | 成功登錄連接到數(shù)據(jù)庫后觸發(fā) |
LOGOFF | BEFORE | 開始斷開數(shù)據(jù)庫連接之前觸發(fā) |
CREATE | BEFORE,AFTER | 在執(zhí)行CREATE語句創(chuàng)建數(shù)據(jù)庫對(duì)象之前、之后觸發(fā) |
DROP | BEFORE,AFTER | 在執(zhí)行DROP語句刪除數(shù)據(jù)庫對(duì)象之前、之后觸發(fā) |
ALTER | BEFORE,AFTER | 在執(zhí)行ALTER語句更新數(shù)據(jù)庫對(duì)象之前、之后觸發(fā) |
DDL | BEFORE,AFTER | 在執(zhí)行大多數(shù)DDL語句之前、之后觸發(fā) |
GRANT | BEFORE,AFTER | 執(zhí)行GRANT語句授予權(quán)限之前、之后觸發(fā) |
REVOKE | BEFORE,AFTER | 執(zhí)行REVOKE語句收權(quán)限之前、之后觸犯發(fā) |
RENAME | BEFORE,AFTER | 執(zhí)行RENAME語句更改數(shù)據(jù)庫對(duì)象名稱之前、之后觸犯發(fā) |
AUDIT /NOAUDIT | BEFORE,AFTER | 執(zhí)行AUDIT或NOAUDIT進(jìn)行審計(jì)或停止審計(jì)之前、之后觸發(fā) |
表3-1-5:系統(tǒng)觸發(fā)器的種類和事件出現(xiàn)的時(shí)機(jī)(前或后)
?
?
示例3.15:創(chuàng)建觸發(fā)器,存放有關(guān)事件信息。
?
?
示例3.16:創(chuàng)建登錄、退出觸發(fā)器。
?
?
6.2.7重新編譯觸發(fā)器
如果在觸發(fā)器內(nèi)調(diào)用其它函數(shù)或過程,當(dāng)這些函數(shù)或過程被刪除或修改后,觸發(fā)器的狀態(tài)將被標(biāo)識(shí)為無效。當(dāng)DML語句激活一個(gè)無效觸發(fā)器時(shí),ORACLE將重新編譯觸發(fā)器代碼,如果編譯時(shí)發(fā)現(xiàn)錯(cuò)誤,這將導(dǎo)致DML語句執(zhí)行失敗。
在PL/SQL程序中可以調(diào)用ALTER TRIGGER語句重新編譯已經(jīng)創(chuàng)建的觸發(fā)器,格式為: ???????????
ALTER TRIGGER [schema.] trigger_name COMPILE [ DEBUG]
???????其中:DEBUG 選項(xiàng)要器編譯器生成PL/SQL 程序條使其所使用的調(diào)試代碼。
6.2.8 刪除和使能觸發(fā)器
DROP TRIGGER trigger_name;
當(dāng)刪除其他用戶模式中的觸發(fā)器名稱,需要具有DROP ANY TRIGGER系統(tǒng)權(quán)限,當(dāng)刪除建立在數(shù)據(jù)庫上的觸發(fā)器時(shí),用戶需要具有ADMINISTER DATABASE TRIGGER系統(tǒng)權(quán)限。
此外,當(dāng)刪除表或視圖時(shí),建立在這些對(duì)象上的觸發(fā)器也隨之刪除。
?
6.2.9 禁用或啟用觸發(fā)器
數(shù)據(jù)庫TRIGGER 的狀態(tài):
1. 有效狀態(tài)(ENABLE):當(dāng)觸發(fā)事件發(fā)生時(shí),處于有效狀態(tài)的數(shù)據(jù)庫觸發(fā)器TRIGGER 將被觸發(fā)。
2. 無效狀態(tài)(DISABLE):當(dāng)觸發(fā)事件發(fā)生時(shí),處于無效狀態(tài)的數(shù)據(jù)庫觸發(fā)器TRIGGER 將不會(huì)被觸發(fā),此時(shí)就跟沒有這個(gè)數(shù)據(jù)庫觸發(fā)器(TRIGGER) 一樣。
數(shù)據(jù)庫TRIGGER的這兩種狀態(tài)可以互相轉(zhuǎn)換。格式為:
ALTER TIGGER trigger_name [DISABLE | ENABLE ];
--例:ALTER TRIGGER emp_view_delete DISABLE;
ALTER TRIGGER語句一次只能改變一個(gè)觸發(fā)器的狀態(tài),而ALTER TABLE語句則一次能夠改變與指定表相關(guān)的所有觸發(fā)器的使用狀態(tài)。格式為: ????????????
ALTER TABLE [schema.]table_name {ENABLE|DISABLE} ALL TRIGGERS;
--例:使表EMP 上的所有TRIGGER 失效:
ALTER TABLE emp DISABLE ALL TRIGGERS;
?
6.2.10觸發(fā)器和數(shù)據(jù)字典
相關(guān)數(shù)據(jù)字典:USER_TRIGGERS、ALL_TRIGGERS、DBA_TRIGGERS?
SELECT TRIGGER_NAME, TRIGGER_TYPE, TRIGGERING_EVENT,
TABLE_OWNER, BASE_OBJECT_TYPE, REFERENCING_NAMES,
STATUS, ACTION_TYPE
FROM user_triggers;
?
?
?
?
?
??本章總結(jié)
??游標(biāo)提供了一種對(duì)具有多行數(shù)據(jù)查詢結(jié)果集中的每一行數(shù)據(jù)分別進(jìn)行單獨(dú)處理的方法。
??游標(biāo)分為顯式游標(biāo)和隱含游標(biāo)兩種。其中,隱含游標(biāo)用于處理SELECT…INTO和DML語句,而顯式游標(biāo)則用于處理SELECT語句返回的多行數(shù)據(jù)。
??顯式游標(biāo)包括定義游標(biāo)?(DECLARE)、打開游標(biāo)?(OPEN)、提取數(shù)據(jù)?(FETCH)和關(guān)閉游標(biāo)?(CLOSE)4個(gè)階段
??參數(shù)游標(biāo)是指帶有參數(shù)的游標(biāo)。在定義了參數(shù)游標(biāo)之后,使用不同參數(shù)值多次打開游標(biāo)可以生成不同的結(jié)果集。
??游標(biāo)For循環(huán)時(shí),?Oracle會(huì)隱含地打開游標(biāo),提取游標(biāo)數(shù)據(jù)并關(guān)閉游標(biāo)
??當(dāng)執(zhí)行一條DML語句或者?SELECT…INTO語句時(shí),都會(huì)創(chuàng)建一個(gè)隱含游標(biāo)。隱含游標(biāo)的名稱是?SQL,不能對(duì)?SQL游標(biāo)顯式地執(zhí)行OPEN、FETCH和?CLOSE語句。Oracle 隱式地打開、提取,并總是自動(dòng)地關(guān)閉?SQL 游標(biāo)。隱含游標(biāo)屬性包括?SQL%FOUND、SQL%NOTFOUND、SQL%ROWCOUNT、SQL%ISOPEN等。
??觸發(fā)器在數(shù)據(jù)庫里以獨(dú)立的對(duì)象存儲(chǔ),它與存儲(chǔ)過程和函數(shù)不同的是,存儲(chǔ)過程與函數(shù)需要用戶顯示調(diào)用才執(zhí)行,而觸發(fā)器是由一個(gè)事件來啟動(dòng)運(yùn)行。
??觸發(fā)器分為DML觸發(fā)器、替代觸發(fā)器、系統(tǒng)觸發(fā)器
??觸發(fā)器分為語句級(jí)觸發(fā)器和行級(jí)觸發(fā)器
??
?
?
任務(wù)實(shí)訓(xùn)部分
1創(chuàng)建和使用游標(biāo)
訓(xùn)練技能點(diǎn)
??游標(biāo)的使用
需求說明
假定存在一張記錄學(xué)員分?jǐn)?shù)的表tb_score,,其數(shù)據(jù)結(jié)構(gòu)如圖3.2.6所示。要求使用游標(biāo)更新tb_score中的rank字段,求出每位學(xué)員總分名次。
?
?
實(shí)現(xiàn)思路
(1) 創(chuàng)建過程,命名為“proc_update_rank”,在其中定義基于tb_score表的可更新游標(biāo),用于根據(jù)總分更新rank字段
?
?(2) 執(zhí)行proc_update_rank過程,實(shí)現(xiàn)更新rank字段并求名次的功能
?
?
2.?任意執(zhí)行一個(gè)update操作,用隱式游標(biāo)sql的屬性%found,%notfound,%rowcount,%isopen觀察update語句的執(zhí)行情況。
訓(xùn)練技能點(diǎn):
????隱式游標(biāo)sql的屬性的使用
?
?
3.將每位員工工作了多少年零多少月零多少天輸出出來
技能訓(xùn)練點(diǎn):
游標(biāo)FOR循環(huán)
?
?
4.輸入部門編號(hào),按照下列加薪比例執(zhí)行(用CASE實(shí)現(xiàn),創(chuàng)建一個(gè)emp1表,修改emp1表的數(shù)據(jù)),并將更新前后的數(shù)據(jù)輸出出來
-- ?deptno ?raise(%)
-- ?10 ?????5%
-- ?20 ?????10%
-- ?30 ?????15%
-- ?40 ?????20%
-- ?加薪比例以現(xiàn)有的sal為標(biāo)準(zhǔn)
技能訓(xùn)練點(diǎn):
更改游標(biāo)的當(dāng)前行
?
?
5.觸發(fā)器的使用
技能訓(xùn)練點(diǎn):
使用觸發(fā)器實(shí)現(xiàn)自動(dòng)編號(hào),在SQL SERVER數(shù)據(jù)庫中,如果將字段屬性設(shè)置為IDENTITY,則該字段值由SQL Server在插入數(shù)據(jù)時(shí)自動(dòng)填充。但Oracle中沒有此功能,需要使用觸發(fā)器來實(shí)現(xiàn)自動(dòng)編號(hào)功能。
(1)?創(chuàng)建序列,命名為“stu_seq”,創(chuàng)建一張表,命名為“tb_stud”
?
(2)?在tb_stud表中創(chuàng)建行觸發(fā)器以實(shí)現(xiàn)自動(dòng)編號(hào)
?
6.觸發(fā)器實(shí)現(xiàn)計(jì)算列
(1). 創(chuàng)建一張表,命名為“tb_stud_score”
?
(2). 在表tb_stud_score中創(chuàng)建行級(jí)觸發(fā)器,命名為“tr_stud_score”
?
?
??本章總結(jié)
?
??Oracle游標(biāo)和觸發(fā)器
n?Oracle游標(biāo)
n?Oracle觸發(fā)器
?
鞏固練習(xí)
一.選擇題
1. 在使用顯式游標(biāo)時(shí),在執(zhí)行了語句?( ?)后應(yīng)該檢查游標(biāo)是否包含行。
????A. OPEN
????B. FETCH
????C. CLOSE
????D. CURSOR?
2.下列選項(xiàng)中,有關(guān)觸發(fā)器和存儲(chǔ)過程的描述正確的是()
????A.二者都可以傳遞參數(shù)
????B.二者都可以被其他程序調(diào)用
????C.兩種模塊中都可以包含數(shù)據(jù)庫事務(wù)語句
????D.二者創(chuàng)建的系統(tǒng)權(quán)限不同
3.關(guān)于行級(jí)觸發(fā)器的偽記錄,下列說法正確的是()
????A. INSERT事件觸發(fā)器中,可以使用:OLD偽記錄
????B.DELETE事件觸發(fā)器中,可以使用:NEW偽記錄
????C.UPDATE事件觸發(fā)器中,可以使用:NEW偽記錄
????D.UPDATE事件觸發(fā)器中,可以使用:OLD偽記錄
4.下列選項(xiàng)中,關(guān)于替代觸發(fā)器的描述正確的是()
???A.替代觸發(fā)器創(chuàng)建在表上
???B.替代觸發(fā)器可以創(chuàng)建在數(shù)據(jù)庫上
???C.通過替代觸發(fā)器可以向基表中插入數(shù)據(jù)
???D.通過替代觸發(fā)器可以向視圖中插入數(shù)據(jù)
5.下列事件中屬于DDL事件的是()
???A.INSERT
???B.LOGON
???C.DROP
???D.SERVERERROR
總結(jié)
- 上一篇: mybatis入门常见错误
- 下一篇: Flex与外部的数据通信