摘 要: 針對初學者容易混淆AFTER觸發器與INSTEAD OF觸發器的問題,首先用通俗的語言對觸發器進行了概述,接著闡述了觸發器的工作原理,然后結合實例分析了AFTER觸發器與INSTEAD OF觸發器的主要區別與應用,最后總結了觸發器應用的注意事項。
關鍵詞: SQL Server;數據庫;觸發器;AFTER;INSTEAD OF
0 引言
觸發器是SQL Server數據庫教學中的重要內容之一,觸發器的教學重點是DML觸發器的創建、管理與應用,而DML觸發器的難點是AFTER觸發器與INSTEAD OF觸發器的區別與應用。初學者往往對此比較容易混淆,不知道何時選用AFTER觸發器、何時選用INSTEAD OF觸發器。為此,本文對SQL Server數據庫中DML觸發器的教學內容進行優化探討,以幫助初學者準確快速地掌握DML觸發器的精髓。
1 觸發器概述
觸發器是一種特殊的存儲過程,它是針對表或視圖定義的數據庫對象,它不能被顯式地調用,而是當對定義了觸發器的表或視圖進行Create、Alter或Drop操作時,或者對定義了觸發器的表或視圖進行Insert、Update或Delete操作時,觸發器才被自動執行。在觸發器中主要是定義通過主鍵、外鍵、默認值或CHECK約束等無法實現的復雜的參照完整性和數據完整性的業務邏輯。當表或視圖被刪除時,其上定義的觸發器也一同被刪除[1]。使用觸發器主要有以下幾點優點:
?。?)級聯修改數據庫中的所有相關表。
(2)撤銷或回滾違反引用完整性的操作,防止非法數據修改。
?。?)強制執行比外鍵參照完整性、CHECK約束更為復雜的業務邏輯。
?。?)查找在數據修改前后表狀態之間的差別,并根據差別分別采取相應的措施。
(5)觸發器是自動執行的,不需要管理員手動維護數據庫的數據完整性[2]。
需要注意以下幾點:
(1)只有表的所有者才可以在表上創建或刪除觸發器,且這種權限不能轉授。
?。?)可以在觸發器中引用臨時表,但不能在臨時表上創建觸發器。
?。?)在執行修改語句的過程中,觸發器的執行是執行修改語句的一部分,所以如果觸發器執行不成功則整個事務回滾[3]。
在SQL Server2008中,觸發器主要有DML(Data Manipulation Language)觸發器、DDL(Data Definition Language)觸發器和登錄觸發器。其中DML觸發器又可以分為6種類型:AFTER-INSERT觸發器、AFTER-UPDATE觸發器、AFTER-DELETE觸發器與INSTEAD OF-INSERT觸發器、INSTEAD OF-UPDATE觸發器、INSTEAD OF-DELETE觸發器[1]。
2 觸發器工作原理
觸發器被觸發時,系統將在內存中自動創建兩個特殊的臨時表,分別是INSERTED表和DELETED表。INSERTED表用于存儲INSERT和UPDATE語句所影響的記錄行的副本。DELETED表用于存儲DELETE和UPDATE語句所影響的記錄行的副本。INSERTED表和DELETED表只是存儲于內存的邏輯表,而不是存儲在數據庫中的物理表,但其結構與觸發器所關聯的表結構一致。
這兩個表由系統進行創建和管理,用戶不允許直接讀取和修改其內容,但可以在觸發器中訪問它們的數據。當觸發器執行完畢后,這兩個表由系統自動刪除[4]。
當通過插入(INSERT)語句引發觸發器時,新的記錄的副本會添加到臨時表INSERTED表中。當通過刪除(DELETE)語句引發觸發器時,被刪除的記錄會添加到臨時表DELETED表中。當通過更新(UPDATE)語句引發觸發器時,首先刪除原有的舊記錄,并將該被刪除的記錄添加到臨時表DELETED表中,然后添加更新后的新記錄,并將更新后的新記錄添加到臨時表INSERTED表中。在觸發器內部可以引用INSERTED表和DELETED表中相關數據實現數據的操縱。
創建觸發器的基本語法結構如下:
CREATE TRIGGER [<所有者名稱>.]<觸發器名> /*指明
觸發器的名稱*/
ON { <表名> | <視圖名> } /*指定觸發器依賴的基表或視
圖*/
[ WITH ENCRYPTION ] /*指定對觸發器的源碼進行加密*/
{
{ { FOR | AFTER | INSTEAD OF } { [ INSERT ] [ , ] [ UPDATE ] [,][DELETE]}
AS
[BEGIN]
<T-SQL語句>[ ...n ] /*指定觸發器執行的SQL語句,
是觸發器的核心*/
[END]
}
}
說明:上面基本語法結構中,INSERT、UPDATE、DELETE選項用來指定觸發器的事件類型,三個選項至少要指定一個,允許任意次序組合這三個選項。FOR與AFTER關鍵字含義完全相同,與INSTEAD OF一起組成指定觸發的方式,AFTER為后觸發,INSTEAD OF為替代觸發。
3 AFTER觸發器與INSTEAD OF觸發器的區別
AFTER觸發器也稱后觸發,是只有執行了某一個操作(如INSERT、UPDATE、DELETE等)之后,觸發器才被觸發。也即只有引發觸發器的操作語句已經完成,并通過各類約束驗證后才會去執行觸發器的語句;如果引發觸發器的操作語句有錯誤或違反了約束而導致執行失敗,觸發器是不會執行的。
INSTEAD OF觸發器也稱替代觸發,該類型觸發器并不會執行引發觸發器的操作語句(如INSERT、UPDATE、DELETE等T-SQL語句),而只是去執行觸發器里面的T-SQL語句。即由觸發器里面的T-SQL語句替代引發觸發器的T-SQL語句的執行。
假如在一個StudentManager數據庫中有tbStudent表及tbDepartment表,兩個表的結構如表1、表2所示(由于只是為了說明問題,在此對表結構做了簡化處理)。
現假定tbStudent表中有如下3條記錄:1001,張三,女,1;1002,李四,男,2;1003,王五,男,3。tbDepartment表中有如下4條記錄:1,計算機系,小張;2,藝術系,小李;3,服裝工程系,小朱;4,物理系,老譚。
例:假如要從tbDepartment表中刪除某系部信息,如果該系部下存在學生信息,則不允許刪除,要求利用觸發器來實現。
現編寫替代觸發器delete_DepInfo_instead,代碼如下:
USE StudentManager
GO
CREATE TRIGGER delete_DepInfo_instead ON tbDepartment
INSTEAD OF DELETE -- 替代觸發
AS
-- 從表deleted中獲取刪除記錄的部門編號
DECLARE @depid varchar(20)
DECLARE @stuname varchar(20)
SELECT @depid = DepID FROM deleted
-- 判斷要刪除的部門編號是否存在學生信息
SELECT @stuname= StuName FROM tbStudent WHERE DepID=@depid
IF @stuname IS NOT NULL
PRINT '指定系部存在學生,請先刪除或修改學生信息!' -- 提示錯誤信息
ELSE
DELETE FROM tbDepartment WHERE DepId=@depid
GO
編寫引發該觸發器T-SQL語句代碼如下:
USE StudentManager
GO
DELETE FROM tbDepartment WHERE DepId=1
GO
結果分析:由于tbStudent表中存在系部編號為1的學生信息,所以結果為彈出“指定系部存在學生,請先刪除或修改學生信息!”。但是把引發觸發器的SQL語句修改為“DELETE FROM Department WHERE DepId=4”,由于在學生表tbStudent中不存在系部編號為4的學生信息,所以會執行觸發器本身所含的“DELETE FROM tbDepartment WHERE DepId=@depid”SQL語句刪除系部編號為4的系部信息,而不是通過引發觸發器的SQL語句“DELETE FROM tbDepartment WHERE DepId=4”刪除系部編號為4的系部信息。換句話說假如上面觸發器delete_DepInfo_instead中T-SQL語句中沒有“ELSE DELETE FROM tbDepartment WHERE DepId=@depid”語句,即使引發該觸發器T-SQL語句要刪除系部編號為4的記錄(DELETE FROM tbDepartment WHERE DepId=4),也不能完成刪除操作。
但是如果把上面觸發器(delete_DepInfo_instead)修改為后觸發的觸發器(delete_DepInfo_after):
USE StudentManager
GO
CREATE TRIGGER delete_DepInfo_after ON tbDepartment
after DELETE -- 后觸發
AS
-- 從表deleted中獲取刪除記錄的部門編號
DECLARE @depid varchar(20)
DECLARE @stuname varchar(20)
SELECT @depid = DepID FROM deleted
-- 判斷要刪除的部門編號是否存在學生信息
SELECT @stuname= StuName FROM tbStudent WHERE DepID=@depid
IF @stuname IS NOT NULL
PRINT '指定系部存在學生,請先刪除或修改學生信息!' -- 提示錯誤信息
ELSE
DELETE FROM tbDepartment WHERE DepId=@depid
GO
編寫引發該觸發器T-SQL語句代碼如下:
USE StudentManager
GO
DELETE FROM tbDepartment WHERE DepId=4
GO
結果是不論觸發器T-SQL語句中有沒有“ELSE DELETE FROM tbDepartment WHERE DepId=@depid”語句,系部編號為4的記錄都將刪除,因為此時會先執行引發觸發器的T-SQL語句(DELETE FROM tbDepartment WHERE DepId=4),從而把系部編號為4的記錄刪除。
此外,AFTER觸發器只能定義在表上,INSTEAD OF觸發器可以定義在表上,也可以定義在視圖上。一個表上可以定義多個AFTER觸發器,但是只能在一個表或視圖上定義一個INSTEAD OF觸發器。
4 觸發器應用注意事項
觸發器功能強大,可輕松地實現許多復雜的功能。觸發器主要用來實現比較復雜的數據完整性、一致性。例如監督某一列數據的變化范圍,并在超出規定范圍以后,對兩個以上的表進行修改。但當使用約束、規則、默認值就可以實現數據完整性時,應優先使用前三種措施,因為濫用觸發器會造成數據庫及應用程序維護困難。對表執行修改操作時,約束優先于觸發器。如果約束和觸發器發生沖突,觸發器將被屏蔽,不再執行。一般來說,只要不影響數據的修改,AFTER觸發器比INSTEAD OF觸發器效率更高,因此,AFTER觸發器和INSTEAD OF觸發器都能實現某功能需求時,優先選用AFTER觸發器。
5 結束語
DML觸發器是用得最廣泛的觸發器,在SQL SERVER教學中占有重要的地位。教學中的難點往往是ALTER觸發器與INSTEAD OF觸發器的區別與應用。本文通過通俗的語言對觸發器進行了概述,闡述了觸發器被觸發時兩個臨時邏輯表INSERTED表和DEKETED表的作用,結合實例分析了AFTER觸發器與INSTEAD OF觸發器的主要區別與應用。AFTER觸發器為后觸發器,也即AFTER觸發器會先執行引發觸發器中的T-SQL語句,后再執行觸發器本身的T-SQL語句,而INSTEAD OF觸發器為替代觸發器,即通過執行觸發器中的T-SQL語句來替代執行引發觸發器的T-SQL語句,也即INSTEAD OF觸發器中引發觸發器的T-SQL語句不會執行。
參考文獻
[1] 高曉黎,韓曉霞. SQL Server2008案例教程[M]. 北京:清華大學出版社, 2010.
[2] 邱李華,李曉黎,任華,等. SQL Server 2008數據庫應用教程(第2版)[M]. 北京:人民郵電出版社, 2012.
[3] 仝春靈,沈祥玖. 數據庫原理與應用[M]. 北京:中國水利水電出版社, 2006.
[4] 程志梅,邱霞明,王曉燕. SQL Server2000數據庫中觸發器的妙用[J]. 計算機應用與軟件, 2009(3):188-189.