1. 觸發器的概念:
觸發器是存儲在服務器中的程序單元,當數據庫中某些事件發生時(比如insert\update\delete),數據庫自動啟動觸發器,執行觸發器中的相應操作。
(1) 觸發器是一種特殊的存儲過程,具備事務的功能;
(2) 觸發器不能被直接調用,而是由事件來觸發;--例如:增刪改
(3) 觸發器常用於加強數據的完整性約束和業務規則等。
簡單點說:觸發器就是個開關,燈就是開關觸發后的操作,觸動了開關燈就亮了。
2. 觸發事件:
Insert,update,delete,create(創建對象時),alter,drop
logon/logoff(用戶的登錄或注銷時執行觸發器)
startup/shutdown(數據庫打開或關閉時執行觸發器)。
3. 觸發時間
before 在指定的事件發生之前執行觸發器
after 在指定的事件發生之后執行觸發器
4. 觸發級別
4.1行級觸發
行觸發:對觸發事件影響的每一行執行觸發器,即觸發機制是基於行的。改一行數據,觸發一次。
關鍵語句:for each row
--案例1
create or replace tirgger t_mydel
after delete
on stuinfo
for each row
begin
dbms_output.put_line('刪的好!');
end;
--執行(刪除了一條記錄,結果顯示一條'刪的好')
delete from stuinfo where stuname='李文才';
--執行(刪除了整個表中的記錄,顯示N條'刪的好')
delete from stuinfo
--說明:這就是講解行級觸發器。
--行級觸發器:一條條的刪,刪一條就觸發一個行級觸發器。
--語句級觸發器:執行一條觸發一次。
4.2語句觸發
語句觸發:對觸發事件只能觸發一次,而且不能該問受觸發器影響的每一行的值。既無論這條SQL語句影響多少條記錄,觸發器都只觸發一次。
4.2.1. 創建觸發器
create [or replace] trigger trigger_name
after|before|instead of --instead反向
[insert][[or] update [of 列列表]][[or] delete]
on table表或view
[for each row] --行級模式
Begin
--pl/sql語句(begin...end)
End;
案例1:
--創建一個觸發器tig_1,當用戶刪除scott.emp表中的數據時提示。
SQL>create or replace trigger tig_1
after delete
on scott.emp //注意:這里沒有用for each row,即不管刪除多少條,只觸發一次該觸發器
begin
if deleting then
dbms_output.put_line('有用戶刪除了emp表中的數據!');
end if;
end;
案例2:
--創建一個觸發器tig_2,當表scott.dept中的deptno列的值發生變化時,自動更新表scott.emp中的deptno列的值,從而保證數據的完整性。
SQL>create or replace trigger tig_2
after update
on scott.emp
for each row
begin
update scott.emp set deptno = :new.deptno
where deptno = :old.deptno;
end;
注意:
這段程序中有兩個概念:new和:old, :new代表執行更新操作之后的新表,:old代表執行更新操作之前的舊表。
通過這兩張表的使用,可以訪問到觸發器執行前后表數據的變化。
insert操作只有:new,delete操作只有:old,update操作二者皆有。
:new 和 :old只用於行級觸發器。
--:new表,將插入的數據先放入到:new表中,確認后放到要更新的表。
--:old表,將不要的數據先放入到:old表中,確認不要了再清除:old表。
--注意::new表和:old表中至始至終就只有一條數據,那請問有多少個列?觸發器的表有多少個列,:new表和:old表就有多少個列。
--案例:
SQL>insert into emp values(…,張三,…,0,……);
SQL>create or replace trigger trig_name
after insert --插入操作之后
on emp --在emp表中
for each row --行級模式
begin
if(:new.sal<=0) then --新表:new中的sal等於0
dbms_output.put_line('警告:干活不能不給薪水');
rollback;(可以用異常:拋異常后回滾數據)
else
dbms_output.put_line('已插入記錄');
commit;
end if;
end;
5.觸發器組成三部分:
a. 觸發器語句(事件)--定義激活觸發器的DML事件和DDL事件;
b. 觸發器限制 --執行觸發器的條件,該條件為真才能激活觸發器;
c. 觸發器操作(主體)--包含SQL語句和代碼,它們在發出了觸發語句且觸發限制的值為真是才運行。
注示:序列通過前觸發保存到數據庫中。
案例:在級聯表中創建觸發器案例
--李斯文不能刪
(什么時候觸發?a.delete時; b.when 條件滿足時; c.代碼中寫明)
SQL>create or replace trigger t_studel
after delete --刪除操作之后
on stuinfo
for each row
begin
if :old.stuname='李斯文' then --如果:old表中存在李斯文,就提示不能刪
--拋出異常
raise_application_error(-20010,'該學生不能刪!!!');
end if;
end;
SQL>delete from emp;
--李斯文不能刪也不能改
只需修改上例代碼中的:
……
after delete or update
……
--怎么知道是(insert\delete\update)哪個操作?不知道沒關系,用case when語句
……
begin
case
when deleting then
--刪除時
if :old.stuname='李斯文' then
raise_application_error(-20010,'該學生不能刪!!!');
end if;
when updating then
--修改時
if :old.stuname='李斯文' then
raise_application_error(-20011,'該學生不能修改!!!');
end if;
when inserting then
--插入時
if :new.stuname='張楊' then
raise_application_error(-20012,'該學生你也敢招!!!');
end if;
end case;
end;
6.多表連接觸發器
在stuinfo表中寫個delete觸發器,指定刪除的人名,
直接刪除stumarks表中該人的成績。
create or replace tirgger t_mydel
after delete
on stuinfo
for each row
declare
stu varchar2(22);
begin
stu:=:old.stuno; --將刪除的學生的學號賦值給該變量
delete from stumarks where stuno=stu;
end;
--運行下
delete from stuinfo where stuname='李斯文';
7. 觸發器的應用(標識列):
標識列:序列+觸發器
--解決:
(1)建表
create table tb_715(
sid number,
sname varchar2(22)
)
(2)創建序列
create sequence seq715;
(3)創建個觸發器,用前觸發,用new表
create or replace trigger t_insert
before insert
on tb_715
for each row
begin
--新表中的id=序列的下一個值
:new.sid:=seq715.nextval;
end;
*****************************************
oracle 11g的語法:
:new.sid:=seq715.nextval;
oracle 10g的語法:
select seq715.nextval into :new.sid from dual;
別用變量,用變量的方法就是11g的寫法。
Oracle觸發器分:前觸發、后觸發