數據庫觸發器


SQL觸發器,是一種特殊類型的存儲過程,不由用戶直接調用。它在指定的表中的數據發生變化時自動生效。喚醒調用觸發器以響應 INSERT、UPDATE 或 DELETE 語句。他可以查詢其它表,並可以包含復雜的Transact-SQL語句。將觸發器和觸發它的語句作為可在觸發器內回滾的單個事務對待。如果檢測到嚴重錯誤(例如,磁盤空間不足),則整個事務即自動回滾。常常用於強制業務規則和數據完整性

  • DML( 數據操縱語言 Data Manipulation Language)觸發器:是指觸發器在數據庫中發生DML事件時啟用。DML事件即指在表或視圖中修改數據的insert、update、delete語句。

    a、在SQL SERVER 2008中,DML觸發器的實現使用兩個邏輯表DELETED和INSERTED。這兩個表是建立在數據庫服務器的內存中,我們只有只讀的權限。DELETED和INSERED表的結構和觸發器所在的數據表的結構是一樣的。當觸發器執行完成后,它們也就會被自動刪除:INSERED表用於存放你在操件insert、update、delete語句后,更新的記錄。比如你插入一條數據,那么就會把這條記錄插入到INSERTED表:DELETED表用於存放你在操作 insert、update、delete語句前,你創建觸發器表中數據庫。

    b、觸發器可通過數據庫中的相關表實現級聯更改,可以強制比用CHECK約束定義的約束更為復雜的約束。與 CHECK 約束不同,觸發器可以引用其它表中的列,例如觸發器可以使用另一個表中的 SELECT 比較插入或更新的數據,以及執行其它操作。觸發器也可以根據數據修改前后的表狀態,再行采取對策。一個表中的多個同類觸發器(INSERT、UPDATE 或 DELETE)允許采取多個不同的對策以響應同一個修改語句。

    c、與此同時,雖然觸發器功能強大,輕松可靠地實現許多復雜的功能,為什么又要慎用?過多觸發器會造成數據庫及應用程序的維護困難,同時對觸發器過分的依賴,勢必影響數據庫的結構,同時增加了維護的復雜程序。

  • DDL(數據定義語言 Data Definition Language)觸發器:是指當服務器或數據庫中發生(DDL事件時啟用。DDL事件即指在表或索引中的create、alter、drop語句也。

  • 登陸觸發器:是指當用戶登錄SQL SERVER實例建立會話時觸發。

2優點

編輯

觸發器可通過數據庫中的相關表實現級聯更改;通過級聯引用完整性約束可以更有效地執行這些更改。

觸發器可以強制比用 CHECK 約束定義的約束更為復雜的約束。

與 CHECK 約束不同,觸發器可以引用其它表中的列。例如,觸發器可以使用另一個表中的 SELECT 比較插入或更新的數據,以及執行其它操作,如修改數據或顯示用戶定義錯誤信息。

觸發器也可以評估數據修改前后的表狀態,並根據其差異采取對策。

比較觸發器與約束

約束和觸發器在特殊情況下各有優勢。觸發器的主要好處在於它們可以包含使用 Transact-SQL 代碼的復雜處理邏輯。因此,觸發器可以支持約束的所有功能;但它在所給出的功能上並不總是最好的方法。

實體完整性總應在最低級別上通過索引進行強制,這些索引或是 PRIMARY KEY 和 UNIQUE 約束的一部分,或是在約束之外獨立創建的。假設功能可以滿足應用程序的功能需求,域完整性應通過 CHECK 約束進行強制,而引用完整性 (RI) 則應通過 FOREIGN KEY 約束進行強制。

在約束所支持的功能無法滿足應用程序的功能要求時,觸發器就極為有用。例如:

除非 REFERENCES 子句定義了級聯引用操作,否則 FOREIGN KEY 約束只能以與另一列中的值完全匹配的值來驗證列值。

CHECK 約束只能根據邏輯表達式或同一表中的另一列來驗證列值。如果應用程序要求根據另一個表中的列驗證列值,則必須使用觸發器。

約束只能通過標准的系統錯誤信息傳遞錯誤信息。如果應用程序要求使用(或能從中獲益)自定義信息和較為復雜的錯誤處理,則必須使用觸發器。

觸發器可通過數據庫中的相關表實現級聯更改;不過,通過級聯引用完整性約束可以更有效地執行這些更改。

觸發器可以禁止或回滾違反引用完整性的更改,從而取消所嘗試的數據修改。當更改外鍵且新值與主鍵不匹配時,此類觸發器就可能發生作用。例如,可以在 titleauthor.title_id 上創建一個插入觸發器,使它在新值與 titles.title_id 中的某個值不匹配時回滾一個插入。不過,通常使用 FOREIGN KEY 來達到這個目的。

如果觸發器表上存在約束,則在 INSTEAD OF觸發器執行后但在 AFTER觸發器執行前檢查這些約束。如果約束破壞,則回滾INSTEAD OF觸發器操作並且不執行 AFTER觸發器。

語法

編輯

CREATE TRIGGER trigger_name

ON { table|view }

[ WITH ENCRYPTION ]

{

{ { FOR|AFTER|INSTEAD OF } { [ INSERT ] [ DELETE ] [ UPDATE ] }

[ WITH APPEND ]

[ NOT FOR REPLICATION ]

AS

[ { IF UPDATE ( column )

[ { AND|OR } UPDATE ( column ) ]

[ ...n ]

|IF ( COLUMNS_UPDATED ( ) updated_bitmask )

column_bitmask [ ...n ]

} ]

sql_statement [ ...n ]

}

}

參數

trigger_name

是觸發器的名稱。觸發器名稱必須符合標識符規則,並且在數據庫中必須唯一。可以選擇是否指定觸發器所有者名稱。

Table|view

是在其上執行觸發器的表或視圖,有時稱為觸發器表或觸發器視圖。可以選擇是否指定表或視圖的所有者名稱。

WITH ENCRYPTION

加密 syscomments 表中包含 CREATE TRIGGER 語句文本的條目。使用 WITH ENCRYPTION 可防止觸發器作為 SQL Server 復制的一部分發布。

AFTER

指定觸發器只有在觸發 SQL 語句中指定的所有操作都已成功執行后才激發。所有的引用級聯操作和約束檢查也必須成功完成后,才能執行此觸發器。

如果僅指定 FOR 關鍵字,則 AFTER 是默認設置。

不能在視圖上定義 AFTER 觸發器。

INSTEAD OF

指定執行觸發器而不是執行觸發 SQL 語句,從而替代觸發語句的操作。

在表或視圖上,每個 INSERT、UPDATE 或 DELETE 語句最多可以定義一個 INSTEAD OF 觸發器。然而,可以在每個具有 INSTEAD OF觸發器的視圖上定義視圖。

INSTEAD OF觸發器不能在 WITH CHECK OPTION 的可更新視圖上定義。如果向指定了 WITH CHECK OPTION 選項的可更新視圖添加 INSTEAD OF觸發器,SQL Server產生一個錯誤。用戶必須用 ALTER VIEW 刪除該選項后才能定義 INSTEAD OF 觸發器。

{ [DELETE] [,] [INSERT] [,] [UPDATE] }

是指定在表或視圖上執行哪些數據修改語句時激活觸發器的關鍵字。必須至少指定一個選項。在觸發器定義中允許使用以任意順序組合的這些關鍵字。如果指定的選項多於一個,需用逗號分隔這些選項。

對於 INSTEAD OF觸發器,不允許在具有 ON DELETE 級聯操作引用關系的表上使用 DELETE 選項。同樣,也不允許在具有 ON UPDATE 級聯操作引用關系的表上使用 UPDATE 選項。

WITH APPEND

指定應該添加現有類型的其它觸發器。只有當兼容級別是 65 或更低時,才需要使用該可選子句。如果兼容級別是 70 或更高,則不必使用 WITH APPEND 子句添加現有類型的其它觸發器(這是兼容級別設置為 70 或更高的 CREATE TRIGGER 的默認行為)。有關更多信息,請參見 sp_dbcmptlevel。

WITH APPEND 不能與 INSTEAD OF觸發器一起使用,或者,如果顯式聲明 AFTER 觸發器,也不能使用該子句。只有當出於向后兼容而指定 FOR 時(沒有 INSTEAD OF 或 AFTER),才能使用 WITH APPEND。以后的版本不支持 WITH APPEND 和 FOR(被解釋為 AFTER)。

NOT FOR REPLICATION

表示當復制進程更改觸發器所涉及的表時,不應執行該觸發器。

AS

是觸發器要執行的操作。

sql_statement

是觸發器的條件和操作。觸發器條件指定其它准則,以確定 DELETE、INSERT 或 UPDATE 語句是否導致執行觸發器操作。

當嘗試 DELETE、INSERT 或 UPDATE 操作時,Transact-SQL語句中指定的觸發器操作生效。

觸發器可以包含任意數量和種類的 Transact-SQL 語句。觸發器旨在根據數據修改語句檢查或更改數據;它不應數據返回給用戶。觸發器中的 Transact-SQL 語句常常包含控制流語言。CREATE TRIGGER 語句中使用幾個特殊的表:

* deleted 和 inserted 是邏輯(概念)表。這些表在結構上類似於定義觸發器的表(也就是在其中嘗試用戶操作的表);這些表用於保存用戶操作可能更改的行的舊值或新值。例如,若要檢索 deleted 表中的所有值,請使用:

SELECT *

FROM deleted

* 如果兼容級別等於 70,那么在 DELETE、INSERT 或 UPDATE觸發器中,SQL Server不允許引用 inserted 和 deleted 表中的 text、ntext 或 image 列。不能訪問 inserted 和 deleted 表中的 text、ntext 和 image 值。若要在 INSERT 或 UPDATE觸發器中檢索新值,請inserted 表與原始更新表聯接。當兼容級別是 65 或更低時,對 inserted 或 deleted 表中允許空值的text、ntext 或 image 列,返回空值;如果這些列不可為空,則返回零長度字符串。

當兼容級別是 80 或更高時,SQL Server 允許在表或視圖上通過 INSTEAD OF觸發器更新 text、ntext 或 image 列。

n

是表示觸發器中可以包含多條 Transact-SQL 語句的占位符。對於 IF UPDATE (column) 語句,可以通過重復 UPDATE (column) 子句包含多列。

IF UPDATE (column)

測試在指定的列上進行的 INSERT 或 UPDATE 操作,不能用於 DELETE 操作。可以指定多列。因為在 ON 子句中指定了表名,所以在 IF UPDATE 子句中的列名前不要包含表名。若要測試在多個列上進行的 INSERT 或 UPDATE 操作,請在第一個操作后指定單獨的 UPDATE(column) 子句。在 INSERT 操作中 IF UPDATE返回 TRUE 值,因為這些列插入了顯式值或隱性 (NULL) 值。

說明 IF UPDATE (column) 子句的功能等同於 IF、IF...ELSE 或 WHILE 語句,並且可以使用 BEGIN...END 語句塊。有關更多信息,請參見控制流語言。

可以在觸發器主體中的任意位置使用 UPDATE (column)。

column

是要測試 INSERT 或 UPDATE 操作的列名。該列可以是 SQL Server 支持的任何數據類型。但是,計算列不能用於該環境中。有關更多信息,請參見數據類型。

IF (COLUMNS_UPDATED())

測試是否插入或更新了提及的列,僅用於 INSERT 或 UPDATE觸發器中。COLUMNS_UPDATED 返回 varbinary 位模式,表示插入或更新了表中的哪些列。

COLUMNS_UPDATED 函數以從左到右的順序返回位,最左邊的為最不重要的位。最左邊的位表示表中的第一列;向右的下一位表示第二列,依此類推。如果在表上創建的觸發器包含 8 列以上,則 COLUMNS_UPDATED 返回多個字節,最左邊的為最不重要的字節。在 INSERT 操作中 COLUMNS_UPDATED對所有列返回 。

可以在觸發器主體中的任意位置使用 COLUMNS_UPDATED。

bitwise_operator

是用於比較運算的位運算符。

updated_bitmask

是整型位掩碼,表示實際更新或插入的列。例如,表 t1 包含列 C1、C2、C3、C4 和 C5。假定表 t1 上有 UPDATE觸發器,若要檢查列 C2、C3 和 C4 是否都有更新,指定值 14;若要檢查是否只有列 C2 有更新,指定值 2。

comparison_operator

比較運算符。使用等號 (=) 檢查 updated_bitmask 中指定的所有列是否都實際進行了更新。使用大於號 (>) 檢查 updated_bitmask 中指定的任一列或某些列是否已更新。

column_bitmask

是要檢查的列的整型位掩碼,用來檢查是否已更新或插入了這些列。

注釋

觸發器常常用於強制業務規則和數據完整性。SQL Server 通過表創建語句(ALTER TABLE 和 CREATE TABLE)提供聲明引用完整性(DRI);但是 DRI 不提供數據庫間的引用完整性。若要強制引用完整性(有關表的主鍵和外鍵之間關系的規則),請使用主鍵和外鍵約束(ALTER TABLE 和 CREATE TABLE 的 PRIMARY KEY 和 FOREIGN KEY關鍵字)。如果觸發器表存在約束,則在 INSTEAD OF觸發器執行之后和 AFTER觸發器執行之前檢查這些約束。如果違反了約束,則回滾INSTEAD OF觸發器操作且不執行(激發)AFTER觸發器。

可用 sp_settriggerorder 指定表上第一個和最后一個執行的 AFTER觸發器。在表上只能為每個 INSERT、UPDATE 和 DELETE 操作指定一個第一個執行和一個最后一個執行的 AFTER觸發器。如果同一表上還有其它 AFTER觸發器,則這些觸發器以隨機順序執行。

如果 ALTER TRIGGER 語句更改了第一個或最后一個觸發器,則除去已修改觸發器上設置的第一個或最后一個特性,而且必須用 sp_settriggerorder 重置排序值。

只有當觸發 SQL 語句(包括所有與更新或刪除的對象關聯的引用級聯操作和約束檢查)成功執行后,AFTER觸發器才會執行。AFTER觸發器檢查觸發語句的運行效果,以及所有由觸發語句引起的 UPDATE 和 DELETE 引用級聯操作的效果。

觸發器限制

CREATE TRIGGER 必須是批處理中的第一條語句,並且只能應用到一個表中。

觸發器只能在當前的數據庫中創建,不過觸發器可以引用當前數據庫的外部對象。

如果指定觸發器所有者名稱以限定觸發器,請以相同的方式限定表名。

在同一條 CREATE TRIGGER 語句中,可以為多種用戶操作(如 INSERT 和 UPDATE)定義相同的觸發器操作。

如果一個表的外鍵在 DELETE/UPDATE 操作上定義了級聯,則不能在該表上定義 INSTEAD OF DELETE/UPDATE 觸發器。

在觸發器內可以指定任意的 SET 語句。所選擇的 SET 選項在觸發器執行期間有效,並在觸發器執行完后恢復到以前的設置。

與使用存儲過程一樣,當觸發器激發時,向調用應用程序返回結果。若要避免由於觸發器激發而向應用程序返回結果,請不要包含返回結果的 SELECT 語句,也不要包含在觸發器中進行變量賦值的語句。包含向用戶返回結果的 SELECT 語句或進行變量賦值的語句的觸發器需要特殊處理;這些返回的結果必須寫入允許修改觸發器表的每個應用程序中。如果必須在觸發器中進行變量賦值,則應該在觸發器的開頭使用 SET NOCOUNT 語句以避免返回任何結果集。

DELETE觸發器不能捕獲 TRUNCATE TABLE 語句。盡管 TRUNCATE TABLE 語句實際上是沒有 WHERE 子句的 DELETE(它刪除所有行),但它是無日志記錄的,因而不能執行觸發器。因為 TRUNCATE TABLE 語句的權限默認授予表所有者且不可轉讓,所以只有表所有者才需要考慮無意中用 TRUNCATE TABLE 語句規避 DELETE觸發器的問題。

無論有日志記錄還是無日志記錄,WRITETEXT 語句都不激活觸發器。

觸發器中不允許以下 Transact-SQL 語句:

ALTER DATABASE CREATE DATABASE DISK INIT

DISK RESIZE DROP DATABASE LOAD DATABASE

LOAD LOG RECONFIGURE RESTORE DATABASE

RESTORE LOG

說明 由於 SQL Server 不支持系統表中的用戶定義觸發器,因此建議不要在系統表中創建用戶定義觸發器。

多個觸發器

SQL Server 允許為每個數據修改事件(DELETE、INSERT 或 UPDATE)創建多個觸發器。例如,如果對已有 UPDATE觸發器的表執行 CREATE TRIGGER FOR UPDATE,則創建另一個更新觸發器。在早期版本中,在每個表上,每個數據修改事件(INSERT、UPDATE 或 DELETE)只允許有一個觸發器。

說明 如果觸發器名稱不同,則 CREATE TRIGGER(兼容級別為 70)的默認行為是在現有的觸發器中添加其它觸發器。如果觸發器名稱相同,則 SQL Server 返回一條錯誤信息。但是,如果兼容級別等於或小於 65,則使用 CREATE TRIGGER 語句創建的新觸發器替換同一類型的任何現有觸發器,即使觸發器名稱不同。有關更多信息,請參見 sp_dbcmptlevel。

遞歸觸發器

當在 sp_dboption 中啟用 recursive triggers 設置時,SQL Server 還允許觸發器的遞歸調用。

遞歸觸發器允許發生兩種類型的遞歸:

* 間接遞歸

* 直接遞歸

使用間接遞歸時,應用程序更新表 T1,從而激發觸發器TR1,該觸發器更新表 T2。在這種情況下,觸發器T2激發並更新 T1。

使用直接遞歸時,應用程序更新表 T1,從而激發觸發器TR1,該觸發器更新表 T1。由於表 T1 被更新,觸發器TR1 再次激發,依此類推。

下例既使用了間接觸發器遞歸,又使用了直接觸發器遞歸。假定在表 T1 中定義了兩個更新觸發器TR1 和 TR2。觸發器 TR1 遞歸地更新表 T1。UPDATE 語句使 TR1 和 TR2 各執行一次。而 TR1 的執行觸發 TR1(遞歸)和 TR2 的執行。給定觸發器的 inserted 和 deleted 表只包含與喚醒調用觸發器的 UPDATE 語句相對應的行。

說明 只有啟用 sp_dboption 的 recursive triggers 設置,才會發生上述行為。對於為給定事件定義的多個觸發器,並沒有確定的執行順序。每個觸發器都應是自包含的。

禁用 recursive triggers 設置只能禁止直接遞歸。若要也禁用間接遞歸,請使用 sp_configurenested triggers 服務器選項設置為 0。

如果任一觸發器執行了 ROLLBACK TRANSACTION 語句,則無論嵌套級是多少,都不會進一步執行其它觸發器。

嵌套觸發器

觸發器最多可以嵌套 32 層。如果一個觸發器更改了包含另一個觸發器的表,則第二個觸發器激活,然后該觸發器可以再調用第三個觸發器,依此類推。如果鏈中任意一個觸發器引發了無限循環,則會超出嵌套級限制,從而導致取消觸發器。若要禁用嵌套觸發器,請用 sp_configurenested triggers 選項設置為 0(關閉)。默認配置允許嵌套觸發器。如果嵌套觸發器是關閉的,則也禁用遞歸觸發器,與 sp_dboption 的 recursive triggers 設置無關。

延遲名稱解析

SQL Server 允許 Transact-SQL存儲過程、觸發器和批處理引用編譯時不存在的表。這種能力稱為延遲名稱解析。但是,如果 Transact-SQL存儲過程、觸發器或批處理引用在存儲過程或觸發器中定義的表,則只有當兼容級別設置(通過執行 sp_dbcmptlevel 設置)等於 65 時,才會在創建時發出警告。如果使用批處理,則在編譯時發出警告。如果引用的表不存在,在運行時返回錯誤信息。有關更多信息,請參見延遲名稱解析和編譯。

權限

CREATE TRIGGER 權限默認授予定義觸發器的表所有者、sysadmin 固定服務器角色成員以及 db_owner 和 db_ddladmin固定數據庫角色成員,並且不可轉讓。

若要檢索表或視圖中的數據,用戶必須在表或視圖中擁有 SELECT 語句權限。若要更新表或視圖的內容,用戶必須在表或視圖中擁有 INSERT、DELETE 和 UPDATE 語句權限。

如果視圖中存在 INSTEAD OF觸發器,用戶必須在該視圖中有 INSERT、DELETE 和 UPDATE 特權,以對該視圖發出 INSERT、DELETE 和 UPDATE 語句,而不管實際上是否在視圖上執行了這樣的操作。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM