概述sql
觸發器爲特殊類型的存儲過程,可在執行語言事件時自動生效。SQL Server 包括三種常規類型的觸發器:DML 觸發器、DDL 觸發器和登陸觸發器。數據庫
當服務器或數據庫中發生數據定義語言 (DDL) 事件時將調用 DDL 觸發器。登陸觸發器將爲響應 LOGON 事件而激發存儲過程。與 SQL Server 實例創建用戶會話時將引起此事件。服務器
當數據庫中發生數據操做語言 (DML) 事件時將調用 DML 觸發器。DML 事件包括在指定表或視圖中修改數據的 INSERT 語句、UPDATE 語句或 DELETE 語句。DML 觸發器能夠查詢其餘表,還能夠包含複雜的 Transact-SQL 語句。將觸發器和觸發它的語句做爲可在觸發器內回滾的單個事務對待。若是檢測到錯誤(例如,磁盤空間不足),則整個事務即自動回滾。ui
DML觸發器this
DML觸發器有兩種:AFTER,INSTEAD OF觸發器,同時DML 觸發器使用 deleted 和 inserted 邏輯(概念)表。 它們在結構上相似於定義了觸發器的表,即對其嘗試執行了用戶操做的表。 在 deleted 和 inserted 表保存了可能會被用戶更改的行的舊值或新值。spa
一.語法3d
CREATE TRIGGER [ schema_name . ]trigger_name ON { table | view } [ WITH <dml_trigger_option> [ ,...n ] ] { FOR | AFTER | INSTEAD OF } { [ INSERT ] [ , ] [ UPDATE ] [ , ] [ DELETE ] } AS { sql_statement [ ; ] [ ,...n ] [ ; ] > }
二.建立表日誌
CREATE TABLE Class (Cno INT PRIMARY KEY, Cname nvarchar(20) not null) go CREATE TABLE Student (SNO INT PRIMARY KEY IDENTITY(1,1), Sname CHAR(10) not null, Age int not null, Sex char(2) not null, Cno int NOT NULL ) ALTER TABLE Student ADD CONSTRAINT FK_SNO_Cno FOREIGN KEY (Cno) REFERENCES Class(Cno) go
AFTER觸發器code
AFTER 指定 DML 觸發器僅在觸發 SQL 語句中指定的全部操做都已成功執行時才被觸發。 全部的引用級聯操做和約束檢查也必須在激發此觸發器以前成功完成。blog
若是僅指定 FOR 關鍵字,則 AFTER 爲默認值。
不能對視圖定義 AFTER 觸發器
當向Class表中插入一條數據時,獲取插入的cno,同時向Student表中插入一條數據
IF OBJECT_ID('TR_Class_insert','TR') IS NOT NULL
DROP TRIGGER TR_Class_insert
G0
CREATE TRIGGER TR_Class_insert on Class AFTER INSERT AS BEGIN DECLARE @Cno INT SELECT @Cno=Cno FROM inserted----獲取插入的數據CNO INSERT INTO Student(Sname,Age,Sex,Cno) VALUES('李明',20,'男',@Cno) END go INSERT INTO Class SELECT 101,'一班' SELECT * FROM Class SELECT * FROM Student
獲取修改的Age值,若是Age爲負數則執行回滾操做,不然輸出修改先後的Age值
IF OBJECT_ID('TR_Student_update','TR') IS NOT NULL DROP TRIGGER TR_Student_update GO CREATE TRIGGER TR_Student_update on Student AFTER UPDATE AS BEGIN DECLARE @Age_old int,@Age_new int SELECT @Age_old=Age from deleted ----獲取修改前的 SELECT @Age_new=Age FROM inserted----獲取更改後的數據 if @Age_new<0 begin print '年齡不能爲負數' rollback; end else BEGIN print @Age_old print @Age_new END END go update Student set Age=-20 where SNO=1 SELECT * FROM Class SELECT * FROM Student update Student set Age=25 where SNO=1 SELECT * FROM Class SELECT * FROM Student
獲取被刪除的數據,返回錯誤提示,該步驟正好驗證了「全部的引用級聯操做和約束檢查也必須在激發此觸發器以前成功完成」,該步驟不會返回制定的錯誤提示,由於被刪除的數據做用於外鍵約束,因此先於觸發器操做執行外鍵約束,返回約束錯誤提示,並執行回滾.
IF OBJECT_ID('TR_Class_delete','TR') IS NOT NULL DROP TRIGGER TR_Class_delete GO CREATE TRIGGER TR_Class_delete on Class AFTER DELETE AS BEGIN DECLARE @Cno int SELECT @Cno=Cno from DELETED---獲取被刪除的記錄 IF @Cno>0begin RAISERROR ('數據不能被刪除,被用於外鍵約束', 16, 10); rollback----執行回滾操做 end END SELECT * FROM Class SELECT * FROM Student DELETE FROM Class where CNO=101 SELECT * FROM Class SELECT * FROM Student
對Student表創建外鍵約束,用於級聯操做 ON DELETE,對於表的級聯刪除更新操做這裏就不講述了
刪除以前建立的外鍵約束,並建立具備級聯更新刪除操做的外鍵約束
alter table student drop constraint FK_SNO_Cno ALTER TABLE Student ADD CONSTRAINT FK_SNO_Cno FOREIGN KEY (Cno) REFERENCES Class (Cno) ON DELETE CASCADE ON UPDATE CASCADE
再執行刪除語句,返回制定錯誤提示「數據不能被刪除,被用於外鍵約束」並執行回滾操做
DELETE FROM Class where CNO=101 SELECT * FROM Class SELECT * FROM Student
INSTEAD OF觸發器
指定執行 DML 觸發器而不是觸發 SQL 語句,所以,其優先級高於觸發語句的操做。 不能爲 DDL 或登陸觸發器指定 INSTEAD OF。
對於表或視圖,每一個 INSERT、UPDATE 或 DELETE 語句最多可定義一個 INSTEAD OF 觸發器。 可是,能夠爲具備本身的 INSTEAD OF 觸發器的多個視圖定義視圖。
INSTEAD OF 觸發器不能夠用於使用 WITH CHECK OPTION 的可更新視圖。 若是將 INSTEAD OF 觸發器添加到指定了 WITH CHECK OPTION 的可更新視圖中,則 SQL Server 將引起錯誤。 用戶須用 ALTER VIEW 刪除該選項後才能定義 INSTEAD OF 觸發器
對於 INSTEAD OF 觸發器,不容許對具備指定級聯操做 ON DELETE 的引用關係的表使用 DELETE 選項。 一樣,也不容許對具備指定級聯操做 ON UPDATE 的引用關係的表使用 UPDATE 選項
-------insert 觸發 ----刪除已有的instead of觸發器 declare @name nvarchar(100) select @name=name from sys.triggers where object_name(parent_id)='student' and is_instead_of_trigger=1 set @name='drop trigger '+@name exec (@name) IF OBJECT_ID('TR_Student_instead_insert','TR') IS NOT NULL DROP TRIGGER TR_Student_instead_insert GO CREATE TRIGGER TR_Student_instead_insert on Student INSTEAD OF insert AS BEGIN SELECT * into T_back from inserted ----獲取即將插入的數據 END select * from Student select * from Class INSERT INTO Student(Sname,Age,Sex,Cno) values('張三',23,'男',102) select * from T_back
建立觸發器失敗,由於以前建立外鍵約束時添加了on delete cascade
IF OBJECT_ID('TR_Student_instead_delete','TR') IS NOT NULL DROP TRIGGER TR_Student_instead_delete GO CREATE TRIGGER TR_Student_instead_delete on Student INSTEAD OF DELETE AS BEGIN DECLARE @Cno int SELECT @Cno=Cno from DELETED---獲取被刪除的記錄 IF EXISTS (SELECT * FROM Class where Cno=@cno) begin rollback----執行回滾操做 RAISERROR ('數據不能被刪除,被用於外鍵約束1', 16, 10); end END 消息 2113,級別 16,狀態 1,過程 TR_Student_instead_delete,第 10 行 由於表 'Student' 的 FOREIGN KEY 使用級聯 DELETE 或 UPDATE,因此沒法對該表 建立 INSTEAD OF DELETE 或 INSTEAD OF UPDATE TRIGGER 'TR_Student_instead_delete'。
重建外鍵約束,刪除級聯
alter table student drop constraint FK_SNO_Cno ALTER TABLE Student ADD CONSTRAINT FK_SNO_Cno FOREIGN KEY (Cno) REFERENCES Class (Cno)
-----同一張表中只能定義一個instead of 觸發器,刪除表以前建立的instead of 觸發 declare @name nvarchar(100) select @name=name from sys.triggers where object_name(parent_id)='student' and is_instead_of_trigger=1 set @name='drop trigger '+@name exec (@name) IF OBJECT_ID('TR_Student_instead_update','TR') IS NOT NULL DROP TRIGGER TR_Student_instead_update GO CREATE TRIGGER TR_Student_instead_update on Student INSTEAD OF update AS BEGIN DECLARE @Age_del int ,@Age_up int SELECT @Age_del=Age from DELETED---獲取被更改的記錄 SELECT @Age_up=Age from Inserted begin print @Age_del print @Age_up select * from Student ----查詢數據是否被更改 end END ----查詢更新前的表數據 select * from student SNO Sname Age Sex Cno 13 李明 22 男 101 update Student set age=-2 where CNO=101
----對於前面定義的after觸發器age不能爲負數也不會執行,instead of 觸發器高於執行語句,高於after 觸發
SNO Sname Age Sex Cno 13 李明 22 男 101 select * from student SNO Sname Age Sex Cno 13 李明 22 男 101 (1 行受影響) 22 -2 (1 行受影響) (1 行受影響) 當表上面定義了instead of 觸發器,指定執行 DML 觸發器而不是觸發 SQL 語句,所以,其優先級高於觸發語句的操做,並且也不會執行表上面定義的after觸發器
建立帶字段判斷的觸發器,根據對特定列的 UPDATE 或 INSERT 修改來執行某些操做
------建立字段更新判斷的update觸發器 ALTER TABLE Class ADD Address nvarchar(50) IF OBJECT_ID('TR_Class_Update','TR') IS NOT NULL DROP TRIGGER TR_Class_Update GO CREATE TRIGGER TR_Class_Update on Class AFTER UPDATE AS BEGIN IF UPDATE(Cname) or UPDATE(Address) BEGIN RAISERROR ('數據不能被修改', 16, 10) ROLLBACK END END SELECT * FROM Class UPDATE Class set Address='5棟101' where Cno=101 SELECT * FROM Class
注意:
DLL觸發器
像常規觸發器同樣,DDL 觸發器將激發存儲過程以響應事件。但與 DML 觸發器不一樣的是,它們不會爲響應針對表或視圖的 UPDATE、INSERT 或 DELETE 語句而激發。相反,它們將爲了響應各類數據定義語言 (DDL)事件而激發。這些事件主要與以關鍵字 CREATE、ALTER 和 DROP 開頭的 Transact-SQL 語句對應。執行 DDL 式操做的系統存儲過程也能夠激發 DDL 觸發器。
DLL觸發器有針對服務器級別的觸發事件,也有針對數據庫級別的觸發事件。
語法:
CREATE TRIGGER trigger_name ON { ALL SERVER | DATABASE } [ WITH <ddl_trigger_option> [ ,...n ] ] { FOR | AFTER } { event_type | event_group } [ ,...n ] AS { sql_statement [ ; ] [ ,...n ] | EXTERNAL NAME < method specifier > [ ; ] }
注意:DDL觸發器中不能指定instead of觸發器
DDL觸發器在服務器級別下可用的事件有:
DDL觸發器在數據庫級別下可用的事件有:
----阻止刪除和修改任意表
CREATE TRIGGER TR_safety ---觸發器名 ON DATABASE ---不用修改 FOR DROP_TABLE, ALTER_TABLE AS BEGIN PRINT 'You must disable Trigger "safety" to drop or alter tables!' ROLLBACK ; END
ALTER TRIGGER TR_safety_On_Database ON ALL SERVER FOR DROP_DATABASE,ALTER_DATABASE AS BEGIN PRINT 'You must disable Trigger "TR_safety_On_Database" to drop database or alter database!' ROLLBACK ; END
注意:在當前數據庫下執行
總結
雖然觸發器功能強大,輕鬆可靠地實現許多複雜的功能,同時過多觸發器會形成數據庫及應用程序的維護困難,同時對觸發器過度的依賴,勢必影響數據庫的結構,同時增長了維護的複雜程序.
附加一張全部觸發事件圖:
備註: 做者:pursuer.chen 博客:http://www.cnblogs.com/chenmh 本站點全部隨筆都是原創,歡迎你們轉載;但轉載時必須註明文章來源,且在文章開頭明顯處給明連接,不然保留追究責任的權利。 《歡迎交流討論》 |