1, insert觸發器;
2, update觸發器;
3, delete觸發器;
觸發器的組成部分:
觸發器的聲明,指定觸發器定時,事件,表名以類型
觸發器的執行,PL/SQL塊或對過程的調用
觸發器的限制條件,通過where子句實現
類型:
應用程序觸發器,前臺開發工具提供的;
數據庫觸發器,定義在數據庫內部由某種條件引發;分為:
DML觸發器;
數據庫級觸發器;
替代觸發器;
DML觸發器組件:
1,觸發器定時
2,觸發器事件
3,表名
4, 觸發器類型
5, When子句
6, 觸發器主體
可創建觸發器的對象:數據庫表,數據庫視圖,用戶模式,數據庫實例
創建DML觸發器:
Create [or replace] trigger [模式.]觸發器名
Before| after insert|delete|(update of 列名)
On 表名
[for each row]
When 條件
PL/SQL塊
For each row的意義是:在壹次操作表的語句中,每操作成功壹行就會觸發壹次;不寫的話,表示是表級觸發器,則無論操作多少行,都只觸發壹次;
When條件的出現說明了,在DML操作的時候也許壹定會觸發觸發器,但是觸發器不壹定會做實際的工作,比如when 後的條件不為真的時候,觸發器只是簡單地跳過了PL/SQL塊;
Insert觸發器的創建:
create or replace trigger tg_insert
before insert on student
begin
dbms_output.put_line('insert trigger is chufa le .....');
end;
/
執行的效果:
SQL> insert into student
2 values(202,'dongqian','f');
insert trigger is chufa le .....
update表級觸發器的例子:
create or replace trigger tg_updatestudent
after update on student
begin
dbms_output.put_line('update trigger is chufale .....');
end;
/
運行效果:
SQL> update student set se='f';
update trigger is chufale .....
已更新8行;
可見,表級觸發器在更新了多行的情況下,只觸發了壹次;
如果在after update on student後加上
For each row的話就成為行級觸發器,運行效果:
SQL> update student set se='m';
update trigger is chufale .....
update trigger is chufale .....
update trigger is chufale .....
update trigger is chufale .....
update trigger is chufale .....
update trigger is chufale .....
update trigger is chufale .....
update trigger is chufale .....
已更新8行;
:new 與: old:必須是針對行級觸發器的,也就是說要使用這兩個變量的觸發器壹定有for each row
這兩個變量是系統自動提供的數組變量,:new用來記錄新插入的值,old用來記錄被刪除的值;
使用insert的時候只有:new裏有值;
使用delete的時候只有:old裏有值;
使用update的時候:new和:old裏都有值;
可以這樣使用: dbms_output.put_line('insert trigger is chufa
dbms_output.put_line('new id is : '||:new.stui
dbms_output.put_line('new name is : '||:new.st
dbms_output.put_line('new se is : '||:new.se);
可以這樣從數據字典中查看壹個表上有哪幾個觸發器:
SQL> select trigger_name from user_triggers
2 where table_name=upper('student');
TRIGGER_NAME
------------------------------
TG_INSERT
TG_UPDATESTUDENT
帶有:old變量的行級delete觸發器:
create or replace trigger tg_deletestudent
before delete on student
for each row
begin
dbms_output.put_line('old is: '||:old.stuid);
dbms_output.put_line('old name: '||:old.stuname);
end;
/
運行效果:
SQL> delete from student;
old is: 202
old name: dongqian
old is: 101
old name: liudehua
old is: 102
old name: lingqingxia
old is: 103
old name: lichanggong
old is: 104
old name: zhenxiuwen
old is: 1001
old name: lilianjie
old is: 1009
old name: tongleifuck
old is: 203
old name: kfdj
old is: 209
old name: fuck
已刪除9行
When的使用:如果在begin也就是說觸發器的PL/SQL主體塊執行前加上when(old.se=’f’)的話,DML操作照做不誤,但是只會在刪除
Se=’f’的那行的時候才會執行觸發器的主體動作,執行效果:
SQL> delete from student;
old is: 209
old name: fuck
已刪除9行; 這裏雖然刪了9行,但是只執行了壹次觸發器的主體,做為壹個行級觸發器;
混合類型觸發器:
Inserting,deleting,updating三個謂詞可以分別指示當前操作到底是哪個;
create or replace trigger hunhetrigger
before insert or update or delete on student
for each row
begin
if inserting then
dbms_output.put_line('insert le.........');
end if;
if deleting then
dbms_output.put_line('delete le .......');
end if;
end;
/
插入的時候就自動判斷當前動作為插入:
SQL> insert into student values(303,'me','f');
insert le.........
刪除的時候就自動判斷當前動作為刪除:
SQL> delete from student;
delete le .......
註意,既然觸發器內部的主體PL/SQL是語句,那麽它同樣也可以是插入刪除操作而不壹定只是dbms_output打印壹些信息;
這正是日誌表的原理:在用戶執行了DML語句的時候觸發主體為插入日誌表以記錄操作軌跡的觸發器;
為什麽用觸發器? 當我們有兩個表用來記錄商品的出庫入庫情況,good_store用來記錄庫存的產品類別和數量,
而good_out用來記錄出庫的產品類別和數量,那麽每當我們出庫的某個類別的產品壹定數量的時候,我們應該在good_out中插入該產品的類別和
出庫數量,而同時也應該在good_store表中用update來更新庫存的相應類別的產品的數量;這就交給了我們兩個必須完成的任務:插入good_out
表後更新good_store表,這樣的手工過程使得我們覺得非常ugly,如果只做其中壹個那造成數據的不壹致;所以現在我們可以用觸發器,在
Good_out表的插入操作上綁定壹個對good_store進行更新的觸發器;當然這個過程應該是壹個事務,妳不必擔心插入good_out表執行了,而綁定在這個動作上的觸發器操作不會執行,相信Oracle設計為原子性了;
註意:觸發器會使得原來的SQL語句速度變慢;
替代觸發器:
創建在視圖上的觸發器,就是替代觸發器,只能是行級觸發器;
為什麽要用替代觸發器?
假如妳有壹個視圖是基於多個表的字段連接查詢得到的;現在如果妳想直接對著這個視圖insert;那妳壹定在想,我對視圖的插入操作
怎麽來反應到組成這個視圖的各個表中呢?事實上,除了定義壹個觸發器來綁定在對視圖上的插入動作上外,妳沒有別的辦法通過系統的報錯而直接向視圖中插入數據;這就是我們用替代觸發器的原因;替換的意思實際上是觸發器的主體部分把對視圖的插入操作轉換成詳細的對各個表的插入;
變異表:變異表就是當前SQL語句正在修改的表,所以在壹個變異表上綁定的觸發器不可以使用cout()函數,原因很簡單:SQL語句剛剛修改了表,妳怎麽統計
約束表:
維護:
Alter trigger …..disenable; 使得觸發器不可用;
Alter trigger ……enable; 開啟觸發器;
Oracle的內置程序包
擴展數據庫的功能;
為PL/SQL提供對SQL功能的訪問;
壹般具有sys權限的高級管理人員使用;
壹個典型的程序包就是dbms_output,妳老是用它的過程put_line();
Dbms_standard 提供語言工具;
Dbms_lob操作Oracle LOB;就是針對大型數據的操作設計的;
Dbms_lock用戶定義的鎖;
Dbms_job 允許對PL/SQL過程進行調度;
Dbms_alert 支持數據庫事件的異步通知;
1,dbms_output的壹些過程:
a):enable
b):disable
c):put只是把數據放到緩存(SQL-Plus的緩存,實際就是整個窗口)中,無輸出功能;
d):put_line可以使得以前放在緩存中所有數據輸出;並且換到下壹行;
e):new_line
f):get_line
g):get_lines
2,dmbs_lob ,這個包只能是由系統管理員來操作;
Clob以字符數據存儲可達2G;
Blob以二進制數據存儲可達4G;
Nclob以unicode字符存儲;
壹個文件下載列表的例子:
創建下載目錄表:
create table downfilelist
(
id varchar(20) not null primary key,
name varchar(40) not null,
filelocation bfile,
description clob
)
/
創建目錄:
create or replace directory filedir as 'f:\oracle'
/只是向Oralce註冊了目錄,實際上並不會真的建立目錄在磁盤上;Oracle無權管理和鎖定操作系統的文件系統;
向目錄表中插入數據:
insert into downfilelist
values('10001','oracle plsal編程指南',bfilename(upper('filedir'),'demo.mp3'),'this is a mp3 music')
insert into downfilelist
values('10002','java 大權', bfilename(upper('filedir'),'x.jpg'),'good super girl')
/在filedir的目錄f:\oracle下實際存儲著demo.mp3 ,x.jpg;
註意,如果妳試圖查詢,效果是 :
sys>select * from downfilelist;
SP2-0678: 列或屬性類型無法通過 SQL*Plus 顯示
因為第三列是無法顯示的,是壹個二進制的;
下面使用dbms_lob的壹些過程來進行操作:
1,read過程
declare
tempdesc clob;
ireadcount int;
istart int;
soutputdesc varchar(100);
begin
ireadcount:=5;
istart:=1;
select description into tempdesc from downfilelist where id='10001';
dbms_lob.read(tempdesc,ireadcount,istart,soutputdesc); 把clob類型的tempdesc中的數據讀到字符類型的soutputdesc裏;
dbms_output.put_line('Top 5 character is: '||soutputdesc);
end;
/註意,對unicode來說,漢字和字母所占的位數是壹樣的;
2,getlength函數
select description into tempclob from downfilelist where id=‘10001’;
ilen:=dbms_lob.GetLength(tempclob);
append,copy……..
發現這樣的現象:select x into y的時候,y並不是獨立於x的拷貝,因為當修改y的時候x也被修改了;
3, fileexists函數
select id ,dbms_lob.fileexists(filelocation) from downfilelist;
如果在bfile類型字段filelocation指定的系統下的目錄中存在filelocation指定的系統文件,則返回int 1,否則返回0;
這說明Oracle還是可以檢測到系統的文件情況的,如同java.io包裏的類壹樣;
對bfile類型數據的操作函數有fileisopen,fileopen,fileclose等等;