目錄
4.3觸發器中可使用的特殊表(inserted表和deleted表)
觸發器(Trigger)不僅能實現完整性規則,而且能保證一些較複雜業務規則的實施。
所謂觸發器就是一類由事件驅動的特殊過程(特殊類型的存儲過程),當一個觸發器建立後,它作爲一個數據庫對象被存儲。當某個觸發事件發生時,觸發器被觸發,執行一系列操作。
觸發器一旦由某個用戶建立,任何用戶對該觸發器指定的數據進行增、刪或改操作時,DBMS系統將自動激活相應的觸發器,定義在觸發器中的功能將被DBMS執行,在覈心層進行集中的完整性控制。
觸發器使用戶定義在關係表上的一類由事件驅動的特殊過程。一旦定義就被保存在數據庫服務器中。觸發器類似於約束,單是比約束更加靈活,可以實施更爲複雜的檢查和操作,具有更精細和更強大的數據控制能力。
一、觸發器的主要優點
觸發器的主要優點
⑴ 觸發器能夠實施比外鍵約束,檢查約束和規則對象
等更爲複雜的數據完整性檢查。
⑵ 和約束相比,觸發器提供了更多的靈活性。約束將
系統錯誤信息返回給用戶,而觸發器可以打印錯誤
信息,調用其他存儲過程,或根據需要糾正錯誤。
⑶ 無論對錶中的數據進行何種更新(增刪改操作),
相應的觸發器都能被激活,對數據實施完整性檢查
和處理。
⑷ 觸發器能夠級聯更新數據庫中的表內容
二、觸發器支持的功能
⑴ 觸發器可以在事件之前、之後執行,還可以替代觸
發語句的操作。例如可以定義觸發器在對某關係執
行INSERT、 UPDATE和DELETE操作之前後觸發。
⑵ 觸發器有語句級觸發器和行級觸發器之分。對被事
件影響修改的每一行(FOR EACH ROW)即每一元組
執行一次觸發過程,稱爲行級觸發器。對整個事件
只執行一次觸發過程(FOR EACH STATEMENT),稱
爲語句級觸發器,該方式是觸發器的默認方式。
⑶ 對於UPDATE事件可以定義對哪個關係、或關係
中的哪一列修改時,觸發器觸發。
⑷ 可以指定執行條件,當觸發器被觸發後,觸發器
功能代碼只有在條件成立時才執行。
⑸ 觸發器代碼可以引用事件中對於元組修改前後的值(OLD值和NEW值)。
⑹ 觸發器可以完成一些複雜的數據檢查,可以實現某些操作的前後處理等。
⑺ 觸發器定義的約束可以在任何顆粒級別上實現、表示動態的或靜態的約
束、延遲或不延遲進行觸發檢查、可以用SQL語句定義約束觸發器的功能。
三、觸發器的類別
⑴ 按觸發事件分:有INSERT觸發器、 UPDATE觸發器和DELETE觸發器之分。
⑵ 按觸發時間分:有BEFORE觸發器和AFTER觸發器之分。
BEFORE觸發器是在事件發生之前觸發,AFTER觸發器是在事件發生之後觸發。
⑶ 按觸發方式分:有語句級觸發器和行級觸發器之分。
注:SQL Server 對上述部分功能可實現,但在語法描述上有區別。
四、SQL Server中觸發器的創建、刪除和修改
觸發器的定義包括兩個方面:指明觸發器的觸發事件和指明觸發器執行的動作。
4.1創建觸發器的語句
創建觸發器的語句一般格式爲:
CREATE TRIGGER <觸發器名> ON {<表名>|<視圖名>}
[WITH ENCRYPTION]
FOR {[INSERT][,][UPDATA][,][DELETE]}
AS
T-SQL語句序列
說明:
① 表名,視圖名:爲觸發該觸發器的表名或視圖名。
SQL Server中,只有表的所有者纔有權建立觸發器。
② INSERT,UPDATA,DELETE :說明觸發觸發器的事件。
一個定義語句允許定義多個觸發事件,用逗號分開。
③ WITH ENCRYPTION:該選項對觸發器定義文本加密。
④ T-SQL操作語句序列:指定觸發器動作。該語句中可以指定多個觸發器操作,
這時要用BEGIN…END將它們組成語句塊。
4.2刪除和修改觸發器
(1)刪除觸發表時,觸發器被隨之刪除。
(2)可以用DROP語句刪除已定義的觸發器。
也可以使用ALTER TRIGGER語句修改觸發器定義。
例如,刪除已定義觸發器的語句格式:
DROP TRIGGER <觸發器名> [,<觸發器名>…]
4.3觸發器中可使用的特殊表(inserted表和deleted表)
使用觸發器時,SQL Server提供了兩張特殊的臨時表:
inserted表和deleted表
這兩張表存在於高速緩存中,它們與創建觸發器的表有相同的結構。
用戶可以使用該表檢查某些修改操作的效果。
但用戶不能直接修改該表中的數據。
用戶可以使用該表的內容作爲查詢操作的判斷條件,但要在FROM中寫出使用的表名(inserted或deleted)。
① inserted表:
存放被INSERTE插入和UPDATE更新的新數據。當向表中插入數據時,INSERT觸發器被觸發。新的記錄增加到觸發器表中和inserted表中。
inserted表是一個邏輯表,保存了所插入記錄的拷貝,觸發器可以檢查inserted表,來確定該觸發器的操作是否應該執行和如何執行。
② deleted表:
存放被DELETE刪除和UPDATE更新的舊數據。
當觸發一個DELETE觸發器時,被刪除的記錄放在一個特殊的deleted表中。
deleted表是一個邏輯表,用來保存已經從表中刪除的記錄。DELETE觸發器可以參考deleted表中的數據。
注:
UPDATE觸發器可使用deleted表和inserted表修改一條記錄等於刪除一條舊記錄和插入一條新記錄。
UPDATE可以看成是由DELETE語句和 INSERT 語句組成。當在一個有UPDATE觸發器的表上修改一條記
錄時,表中原來的記錄移動到deleted表中,修改過的記錄插入到inserted表中。UPDATE觸發器可以
參考deleted表和inserted表,以便確定如何執行觸發器的操作。
五、 觸發器應用舉例
創建觸發器的語句一般格式爲:
CREATE TRIGGER <觸發器名> ON {<表名>|<視圖名>}
[WITH ENCRYPTION]
FOR {[INSERT][,][UPDATA][,][DELETE]}
AS
T-SQL語句序列
假設學生表S新增一屬性Cnum(類型爲INT,初值均爲0), 記錄該學生的選課數,分別創建如下觸發器:
5.1INSERT 觸發器
例1.創建INSERT 觸發器Tri1,其功能是:在學習表SC插入一條記錄後,立即更新學生表S的Cnum屬性,即將原值加一。
CREATE TRIGGER Tri1 ON SC FOR INSERT AS UPDATE Student SET Cnum=Cnum+1 WHERE Student.Sno=(SELECT Sno FROM inserted WHERE Student.Sno=inserted.Sno)
執行:
go create trigger tri1 on Cj for insert as update Student set Cnum=Cnum+1 where Student.sno=(select Sno from inserted where Student.Sno=inserted.Sno) go insert into Cj values(2000101,1,92); -- 運行結果: (1 行受影響) (1 行受影響) -- 也影響了student表的一行 go -- 存儲過程 create procedure fs as select * from Student; exec fs; 運行結果: 2000101 李勇 男 20 00311 1 --果然Cnum也加1了 2000102 劉詩晨 女 19 00311 0
5.2 DELETE觸發器
例9.創建DELETE觸發器Tri2,其功能是:在刪除學習表SC一條記錄後,立即更新學生表S的Cnum屬性,即將原值減一.
CREATE TRIGGER Tri2 ON SC FOR DELETE AS UPDATE Student SET Cnum=Cnum-1 WHERE Student.Sno=(SELECT Sno FROM deleted WHERE Student.Sno=deleted.Sno)
執行過程:
go create trigger tri2 on Cj for delete as update Student set Cnum=Cnum-1 where Student.Sno=(Select Sno from deleted where Student.Sno=deleted.Sno); -- 命令已成功完成。 delete Cj where Sno='2000101' and Cno='1'; -- 運行結果 (1 行受影響) (1 行受影響) -- 說明影響2行 exec fc; exec fs; -- 運行結果: 2000101 李勇 男 20 00311 0 -- Cnum果然減1了 2000102 劉詩晨 女 19 00311 0
5.3 UPDATE觸發器
例10 創建UPDATE 觸發器Tri3,功能是:在SC表更新一條記錄的學號後,立即更新學
生表S的Cnum屬性,改前學號學生的Cnum值減1,改後學號學生的Cnum值加1。go create trigger tri3 on Cj for update as if update(Sno) begin update Student set Cnum=Cnum-1 where Sno=(select Sno from deleted where deleted.Sno=Student.Sno); update Student set Cnum=Cnum+1 where Sno=(select Sno from inserted where inserted.Sno=Student.Sno); end
執行過程:
go create trigger tri3 on Cj for update as if update(Sno) -- 不可少 不然修改一下grade的值Sno並未刪除 也會執行下面明顯不合理 begin update Student set Cnum=Cnum-1 where Sno=(select Sno from deleted where deleted.Sno=Student.Sno); update Student set Cnum=Cnum+1 where Sno=(select Sno from inserted where inserted.Sno=Student.Sno); end insert into Cj values(2000101,1,92); exec fs; exec fc; update Cj set Sno=2000103 where Sno=2000101; 運行結果: (1 行受影響) (0 行受影響) (1 行受影響) --說明確實進行了3次操作 注:if update(Sno)有了此句: 只有改Sno的值纔會觸發觸發器 改其他值不會(運行結果僅一行)
六、使用觸發器的考慮
觸發器最大的用途是維護數據完整性,而不是返回結果。
只是在必要的時候使用觸發器。如果使用約束、規則,
默認就可以實現預定的數據完整性時,應優先考慮使用這3種措施使觸發器的定義語句儘可能清晰簡單。
觸發器一般定義在操作發生之後執行,約束在操作發生之前起作用。如果在觸發器表上有約
束,那麼這些約束在觸發器執行之前進行檢查。如果操作與約束有衝突,那麼觸發器不執行。有的DBMS系統的觸發器不能在臨時表或視圖上創建,但可以參照這些對象。
觸發器和激活它的語句作爲單個事務處理,如果檢查到嚴重錯誤,整個事務自動撤銷。
附錄:
-- 觸發器
create database Trig;
use Trig;
create table Student(
Sno Char(7) primary key,--學號
Sname Char(10) not null,--學生姓名
Ssex Char(2) check(Ssex in('男','女')) default '男'not null,--性別
Sage Smallint check(Sage>14 and Sage<65),--年齡
Clno Char(5) not null,--學生所在班級號
Cnum int default 0 -- 選課數
);
create table Cj(
Sno Char(7),--學號
Cno Char(1),--課程號
Grade Decimal(4,1) check(Grade>0 and Grade<100),--成績
primary key(Sno,Cno)
);
-- 預備語句
insert into Student values(2000101,'李勇','男',20,'00311',0);--漢字字符型必須''
insert into Student values(2000102,'劉詩晨','女','19','00311',0);--int型可以傳遞字符串(不打'')
select * from Student;
select * from Cj;
insert into Cj values(2000101,1,92);
-- 往Cj表新增一條記錄 對Studnet表相應學號的學生Cnum+1(選課數+1)
go
create trigger tri1 on Cj for insert
as
update Student set Cnum=Cnum+1
where Student.sno=(select Sno from inserted where Student.Sno=inserted.Sno)
go
create procedure fs
as select * from Student;
--也ok
go
create procedure fc
as select * from Cj;
exec fs
-- delete
go
create trigger tri2 on Cj for delete
as
update Student set Cnum=Cnum-1
where Student.Sno=(Select Sno from deleted where Student.Sno=deleted.Sno);
-- 命令已成功完成。
delete Cj where Sno='2000101' and Cno='1';
-- 運行結果
(1 行受影響)
(1 行受影響)
exec fc;
exec fs;
-- update
go
create trigger tri3 on Cj for update
as
if update(Sno)
begin
update Student set Cnum=Cnum-1
where Sno=(select Sno from deleted where deleted.Sno=Student.Sno);
update Student set Cnum=Cnum+1
where Sno=(select Sno from inserted where inserted.Sno=Student.Sno);
end
insert into Cj values(2000101,1,92);
exec fs;
exec fc;
update Cj set Sno=2000103 where Sno=2000101;