SQL Server 触发器学习总结
生活随笔
收集整理的這篇文章主要介紹了
SQL Server 触发器学习总结
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
SQL菜鳥入門級教程之觸發器
??觸發器簡介:
?
觸發器(trigger)是種特殊的存儲過程,它的執行不是由程序調用,也不需要手動操作,它是由事件來觸發,事件大家應該非常熟悉吧,比如按鈕的Click事件、網頁的Load事件等。按鈕的Click事件是通過鼠標單擊按鈕觸發的,而觸發器的事件,是由對表進行增刪改操
作所觸發的。當對一個數據庫或表進行增刪改( Insert,Delete,Update)的時就會激活觸發器。?
?
從SQL2005開始,根據SQL語句的不同將觸發器分成了兩類,一類是DML觸發器,一類是DLL觸發器。其中DML觸發器又分為兩類:After觸發器和Instead Of觸發器。
?
觸發器的分類:
?
DML觸發器:DML(Data Manipulation Language)觸發器是當數據庫服務器中發生數據操作語言事件時執行的存儲過程。DML觸發器又分為兩類:After觸發器和Instead Of觸發器
DDL觸發器:DDL觸發器是在響應數據定義語言(Data Definition Language)事件時執行的存儲過程。DDL觸發器一般用于執行數據庫中管理任務。如審核和規范數據庫操作、防止數據庫表結構被修改等。
?
DML觸發器:
?
今天我們我們主要介紹DML觸發器,DML觸發器分為After觸發器和Instead Of觸發器。
After觸發器:這類觸發器是在記錄已經改變完之后(after),才會被激活執行,它主要是用于記錄變更后的處理或檢查,一旦發現錯誤,也可以用Rollback Transaction語句來回滾本次的操作。
Instead Of觸發器:這類觸發器一般是用來取代原本的操作,在記錄變更之前發生的,它并不去執行原來SQL語句里的操作(Insert、Update、Delete),而去執行觸發器本身所定義的操作。
?
在SQL Server里,每個DML觸發器都分配有兩個特殊的表,一個是Inserted表,一個是Deleted表。它們兩個存在于數據庫服務器的內存中,是由系統管理的邏輯表,是兩個臨時表,而不是真正存儲在數據庫中的物理表。用戶對這兩個表只有讀取的權限,沒有修改的權限。
這兩個表的結構(主外鍵、字段、數據類型等)與觸發器所在數據表的結構是完全一致的,當觸發器的工作完成之后,這兩個表也將會從內存中刪除。
?
Inserted和Deleted兩個表的作用:
?
Inserted:對于插入記錄操作來說,插入表里存放的是要插入的數據;對于更新記錄操作來說,插入表里存放的是要更新的記錄。
Deleted:對于更新記錄操作來說,刪除表里存放的是被更新記錄;對于刪除記錄操作來說,刪除表里存入的是被刪除的舊記錄。
看上面兩句話可能不太明白,那么看看下面這張表是不是就明白了?
??
工作原理:
?
After觸發器的工作原理:
?
After觸發器是在SQL語句執行之后才被激活的。以刪除記錄為例:當SQL Server接收到一條刪除操作的SQL語句時,SQL Server先將要刪除的記錄存放在Deleted表里,然后把數據表里的記錄刪除,再激活After觸發器,執行After觸發器里的SQL語句。執行完畢之后, 刪
除內存中的Deleted表,操作結束。
還是舉上面的例子:在產品庫存表里,如果要刪除一條產品記錄,在刪除的時候,觸發器可以檢查該產品庫存數量是否為零,如果不為零則取消刪除操作。數據庫的操作如下:
?
1,接收SQL語句,將要從產品庫存表里刪除的產品記錄取出來,放在刪除表里。
2,從產品庫存表里刪除該產品記錄。
3,從刪除表里讀出該產品的庫存數量字段,判斷是不是為零,如果為零的話,完成操作,從內存里清除刪除表;如果不為零的話,用Rollback Transaction語句來回滾操作(即將庫存表還原成刪除之前的狀態)。
?
Instead Of 觸發器的工作原理:
?
Instead Of觸發器與After觸發器不同。After觸發器是在Insert、Update和Delete操作完成后才激活的,而Instead Of觸發器,是在這些操作進行之前就激活了,并且不再去執行原來的SQL操作,而是用觸發器本身的SQL語句代替原來的語句去執行。
還拿上面那個例子來說,刪除一條產品記錄的時候,用Instead Of將刪除操作替換成查詢該產品的庫存。數據庫的操作如下:
?
1,接收SQL語句,但不執行,而是跳轉到Instead Of后面的SQL語句
2,根據傳入的產品ID,將該產品的庫存取出,完成操作。
?
下面讓我們看看觸發器的代碼到底怎么寫:
?
下面的一段代碼是觸發器的一個框架。
?
CREATE TRIGGER ?Trigger_Name --觸發器名,在一個數據庫中觸發器名是唯一的。
?
? ?ON ?Table_Name | View_Name --觸發器所在的表或者視圖。
?
? ?AFTER(FOR)|Instead Of ?INSERT,DELETE,UPDATE --定義成AFTER或Instead Of類型的觸發器。
? ?
? ?--AFTER跟FOR相同,不可在視圖上定義AFTER觸發器
? ?
? ?-- 后面是觸發器被觸發的條件,最少有一個,可以郵多個。如果有多個用逗號分開,順序無要求。 ?www.2cto.com ?
?
AS --觸發器要執行的操作
?
BEGIN
?
? ?--BEGIN跟END組成一個代碼塊,可以寫也可以不寫,如果觸發器中執行的SQL語句比較復雜,用BEGIN和END會讓代碼更加整齊,更容易理解。
?
END
GO --GO就代表結操作完畢
?
注意事項: ?www.2cto.com ?
?
1,After觸發器只能用于數據表不能用于視圖;Instead Of觸發器兩者皆可,設置為With Check Option的視圖也不允許建立Instead Of觸發器。兩種觸發器都不可以建立在臨時表上。
2,一個數據表可以有多個觸發器,但是一個觸發器只能對應一個表。
3,在同一個數據表中,對每個操作(如Insert、Update、Delete)而言可以建立許多個After觸發器,而Instead Of觸發器針對每個操作只有建立一個。
4,如果針對某個操作即設置了After觸發器又設置了Instead Of觸發器,那么Instead of觸發器一定會激活,而After觸發器就不一定會激活。
?
5,不同的SQL語句,可以觸發同一個觸發器,如Insert和Update語句都可以激活同一個觸發器。
6,觸發器名在所在的數據庫里必須是唯一的。由于觸發器是建立中數據表或視圖中的,所以有很多人都以為只要是在不同的數據表中,觸發器的名稱就可以相同,其實觸發器的全名(Server.Database.Owner.TriggerName)是必須 唯一的,這與觸發器在哪個數據表或視圖無關。
7,關鍵字AFTER可以用For來代取,它們的意思都是一樣的,代表只有在數據表的操作都已正確完成后才會激活的觸發器。
========
簡單觸發器的使用 獻給SQL初學者
簡單觸發器的使用 獻給SQL初學者,使用sqlserver的朋友可以參考下。?首先,啰嗦幾句廢話如下:?
(1)觸發器(trigger)是個特殊的存儲過程,它的執行并不需要我們去顯式調用,而是由一些事件觸發,這有點類似C#中的事件處理機制。當使用UPDATE,INSERT 或DELETE的一種或多種對指定的數據庫的相關表進行操作時,會觸發觸發器。?
(2)觸發器可以包含復雜的SQL語句,主要用于強制復雜的業務規則或要求。?
(3)觸發器能夠維持數據庫的完整性,當執行插入、更新或刪除操作時,觸發器會根據表與表之間的關系,強制保持其數據的完整性。?
?
好,啰嗦完了開始貼代碼,首先貼上我創建的兩張表所包含的列,他們的關聯關系是1對多,以UserID進行關聯。?
然后來一個非常簡單的觸發器?
?
IF EXISTS(SELECT * FROM sysobjects WHERE name='tr_Users_OnUpdate' AND TYPE='TR') DROP TRIGGER tr_Users_OnUpdate GO --這里呢創建觸發器與存儲過程類似(都是DDL) --先判斷如否存在同名觸發器就刪除然后重建 CREATE TRIGGER tr_Users_OnUpdate ON Users FOR UPDATE AS PRINT ‘Users表已發生修改' GO
?
上述代碼中,tr_Users_OnUpdate為觸發器名稱,Users為表名。這觸發器的作用是當向Users表執行Update時將打印“Users表已發生修改”。?
好了我們可以看到這個觸發器的實用性不是很大,那么接下來呢我們再來學習下關于觸發器里兩種特殊的表“inserted”和“deleted”。這兩張表主要用于觸發器。Deleted 表用于存儲 執行DELETE 和 UPDATE操作時所影響的行的副本。而Inserted 表則用于存儲?
INSERT 和 UPDATE 語句所影響的行的副本。那么我們看到執行UPDATE操作時都會有記錄分別存儲到“inserted”和“deleted”。其實理解起來不難deleted表存儲的是Update之前的記錄,而inserted存儲的呢則是Update之后的記錄,這里關于理論性東西我不再贅述,官
方資料有更詳細說明。?
現在我們要做的就是本文的重點,當往WordInfo添加一條記錄時,使用觸發器使UserInfo的相應記錄的LeaveCount字段增加1。代碼如下:?
?
--添加留言的觸發器 IF EXISTS(SELECT name FROM sysobjects WHERE name='tr_LeaveWord_Add' AND TYPE='TR') DROP TRIGGER tr_LeaveWord_Add GO CREATE TRIGGER tr_LeaveWord_Add ON WordInfo FOR INSERT AS UPDATE UserInfo SET LeaveCount=LeaveCount+1 WHERE UserID=(SELECT TOP 1 UserID FROM Inserted) GO
OK,到這里就可以收工了,值得注意的是如果觸發器是UPDATE觸發的,那么在執行Update后再查詢更新之前的數據改成查詢deleted表即可。?
========
初學sql server 2008之觸發器
觸發器(trigger):是一種特殊的存儲過程,可以用來對表實施復雜的完整性約束,保持數據的一致性。當觸發器所保護的數據發生改變時,觸發器會自動被激活,并執行觸發器中所定義的相關操作,從而保證對數據的不完整性約束或不正確的修改。
在SQL SERVER 2008中,有三種類型的觸發器:
(1)DML觸發器:是指觸發器在數據庫中發生數據操作語言(DML)事件時將啟用。DML事件即指在表或視圖中修改數據的insert、update、delete語句也。
(2)DDL觸發器:是指當服務器或數據庫中發生數據定義語言(DDL)事件時將啟用。DDL事件即指在表或索引中的create、alter、drop語句也。
(3)登陸觸發器:是指當用戶登錄SQL SERVER實例建立會話時觸發。
不過根據DML觸發器觸發的方式不同又分為以下兩種情況:
(1)AFTER觸發器:它是在執行INSERT、UPDATE、DELETE語句操作之后執行觸發器操作。它主要是用于記錄變更后的處理或檢查,一旦發生錯誤,可以用Rollback Transaction語句來回滾本次扣件,不過不能對視圖定義AFTER觸發器。
(2)INSTEAD OF觸發器:它在執行INSERT、UPDATE、DELETE語句操作之前執行觸發器本身所定義的操作。而INSTEAD OF觸發器是可以定義在視圖上的。
? 在SQL SERVER 2008中,DML觸發器的實現使用兩個邏輯表DELETED和INSERTED。這兩個表是建立在數據庫服務器的內存中,由系統管理的邏輯表,我們對于它只有只讀的權限。DELETED和INSERED表的結構和觸發器所在的數據表的結構是一樣的。當觸發器執行完成后
,它們也就會被自動刪除。
INSERED表用于存放你在操件insert、update、delete語句后,更新的記錄。比如你插入一條數據,那么就會把這條記錄插入到INSERTED表。
DELETED表用于存放你在操作 insert、update、delete語句前,你創建觸發器表中數據庫。比如你原來的表中有三條數據,那么他也有三條數據。
下面我們就開始創建觸發器吧!
我們先創建一張如下的表吧!然后以它為例吧。
下面就是創建一個簡單的after觸發器:
create trigger trigMessageList?
on table1?
after insert,update?
as raiserror('數據一致性驗證',16,1)
此時如果我們手動打開table1,輸入一條,根本就插入不了,我們只能寫一條如下的SQL語句插入一條數據
insert into table1(user_name)values('23')
結果數據是插入成功了,但是會出顯如下圖所示的提示:
下面我再創建一個稍微有點復雜的after觸發器:
--該觸發器作用是:如果向table1中插入數據時,
--先檢查要向table1插入的這條的USER_ID是否USERS(我創建的另一個表)表中的USER_ID字段中有,如果不存在則不允許插入
create trigger trigInsertedMessages?
on table1?
after insert?
as?
if exists (select * from inserted a where a.user_id not in (select USER_ID from USERS))?
begin?
raiserror('數據一致性驗證',16,1)?
rollback transaction?
end
?
inserted of觸發器和after觸發器寫法差不多,在此就不多寫了。
下面創建一個簡單的DDL觸發器:
復制代碼
--它的作用是:防止數據庫Test(我創建的一個實驗數據庫)中的任一表被修改或刪除
create trigger trigDB?
on database?
for drop_table,alter_table?
as?
print '你一定要禁用觸發器“trigDB"才能刪除或修改這個數據庫的表'?
rollback
刪除觸發器:
drop trigger trigDB?
ON DATABASE
一定要記得加上ON DATABASE這條,否則就刪除不了。
最后再來條開啟和禁用觸發器的語句:
disable trigger trigDB on database --禁用觸發器
enable trigger trigDB on database --開啟觸發器
========
SQL Server 觸發器
觸發器是一種特殊類型的存儲過程,它不同于之前的我們介紹的存儲過程。觸發器主要是通過事件進行觸發被自動調用執行的。而存儲過程可以通過存儲過程的名稱被調用。?什么是觸發器?
? ? 觸發器對表進行插入、更新、刪除的時候會自動執行的特殊存儲過程。觸發器一般用在check約束更加復雜的約束上面。觸發器和普通的存儲過程的區別是:觸發器是當對某一個表進行操作。諸如:update、insert、delete這些操作的時候,系統會自動調用執行該表
上對應的觸發器。SQL Server 2005中觸發器可以分為兩類:DML觸發器和DDL觸發器,其中DDL觸發器它們會影響多種數據定義語言語句而激發,這些語句有create、alter、drop語句。?
??
? ? DML觸發器分為:?
? ? 1、 after觸發器(之后觸發)?
? ? ? ? a、 insert觸發器?
? ? ? ? b、 update觸發器?
? ? ? ? c、 delete觸發器???
? ? 2、 instead of 觸發器 (之前觸發)???
? ? 其中after觸發器要求只有執行某一操作insert、update、delete之后觸發器才被觸發,且只能定義在表上。而instead of觸發器表示并不執行其定義的操作(insert、update、delete)而僅是執行觸發器本身。既可以在表上定義instead of觸發器,也可以在視圖上定義。?
? ? 觸發器有兩個特殊的表:插入表(instered表)和刪除表(deleted表)。這兩張是邏輯表也是虛表。有系統在內存中創建者兩張表,不會存儲在數據庫中。而且兩張表的都是只讀的,只能讀取數據而不能修改數據。這兩張表的結果總是與被改觸發器應用的表的結構相同。當觸發器完成工作后,這兩張表就會被刪除。Inserted表的數據是插入或是修改后的數據,而deleted表的數據是更新前的或是刪除的數據。
對表的操作
?Inserted邏輯表
?Deleted邏輯表
?
增加記錄(insert)
?存放增加的記錄
?無
?
刪除記錄(delete)
?無
?存放被刪除的記錄
?
修改記錄(update)
?存放更新后的記錄
?存放更新前的記錄
?
? ? Update數據的時候就是先刪除表記錄,然后增加一條記錄。這樣在inserted和deleted表就都有update后的數據記錄了。注意的是:觸發器本身就是一個事務,所以在觸發器里面可以對修改數據進行一些特殊的檢查。如果不滿足可以利用事務回滾,撤銷操作。?
? 創建觸發器?
? ? 語法?
create trigger tgr_nameon table_namewith encrypion –加密觸發器 ? ?for update...as ? ?Transact-SQL
? ? # 創建insert類型觸發器?
--創建insert插入類型觸發器if (object_id('tgr_classes_insert', 'tr') is not null) ? ?drop trigger tgr_classes_insertgocreate trigger tgr_classes_inserton classes ? ?for insert --插入觸發as ? ?--定義變量 ? ?declare @id int, @name varchar
(20), @temp int; ? ?--在inserted表中查詢已經插入記錄信息 ? ?select @id = id, @name = name from inserted; ? ?set @name = @name + convert(varchar, @id); ? ?set @temp = @id / 2; ? ? ? ?insert into student values(@name, 18 + @id, @temp,?
@id); ? ?print '添加學生成功!';go--插入數據insert into classes values('5班', getDate());--查詢數據select * from classes;select * from student order by id; ? ? insert觸發器,會在inserted表中添加一條剛插入的記錄。?
?
? ? # 創建delete類型觸發器?
--delete刪除類型觸發器if (object_id('tgr_classes_delete', 'TR') is not null) ? ?drop trigger tgr_classes_deletegocreate trigger tgr_classes_deleteon classes ? ?for delete --刪除觸發as ? ?print '備份數據中……'; ? ? ? ?if (object_id
('classesBackup', 'U') is not null) ? ? ? ?--存在classesBackup,直接插入數據 ? ? ? ?insert into classesBackup select name, createDate from deleted; ? ?else ? ? ? ?--不存在classesBackup創建再插入 ? ? ? ?select * into classesBackup from?
deleted; ? ?print '備份數據成功!';go----不顯示影響行數--set nocount on;delete classes where name = '5班';--查詢數據select * from classes;select * from classesBackup; ? delete觸發器會在刪除數據的時候,將剛才刪除的數據保存在deleted表中。?
? ? # 創建update類型觸發器?
--update更新類型觸發器if (object_id('tgr_classes_update', 'TR') is not null) ? ?drop trigger tgr_classes_updategocreate trigger tgr_classes_updateon classes ? ?for updateas ? ?declare @oldName varchar(20), @newName varchar(20); ? ?--更新
前的數據 ? ?select @oldName = name from deleted; ? ?if (exists (select * from student where name like '%'+ @oldName + '%')) ? ? ? ?begin ? ? ? ? ? ?--更新后的數據 ? ? ? ? ? ?select @newName = name from inserted; ? ? ? ? ? ?update student?
set name = replace(name, @oldName, @newName) where name like '%'+ @oldName + '%'; ? ? ? ? ? ?print '級聯修改數據成功!'; ? ? ? ?end ? ?else ? ? ? ?print '無需修改student表!';go--查詢數據select * from student order by id;select * from?
classes;update classes set name = '五班' where name = '5班'; ? ? update觸發器會在更新數據后,將更新前的數據保存在deleted表中,更新后的數據保存在inserted表中。?
? ? # update更新列級觸發器?
if (object_id('tgr_classes_update_column', 'TR') is not null) ? ?drop trigger tgr_classes_update_columngocreate trigger tgr_classes_update_columnon classes ? ?for updateas ? ?--列級觸發器:是否更新了班級創建時間 ? ?if (update
(createDate)) ? ?begin ? ? ? ?raisError('系統提示:班級創建時間不能修改!', 16, 11); ? ? ? ?rollback tran; ? ?endgo--測試select * from student order by id;select * from classes;update classes set createDate = getDate() where id =?
3;update classes set name = '四班' where id = 7; ? ? 更新列級觸發器可以用update是否判斷更新列記錄;?
?
? ? # instead of類型觸發器?
? ? ? ?instead of觸發器表示并不執行其定義的操作(insert、update、delete)而僅是執行觸發器本身的內容。?
? ? ? ?創建語法?
create trigger tgr_nameon table_namewith encryption ? ?instead of update...as ? ?T-SQL ? ?
? ? ? # 創建instead of觸發器
if (object_id('tgr_classes_inteadOf', 'TR') is not null) ? ?drop trigger tgr_classes_inteadOfgocreate trigger tgr_classes_inteadOfon classes ? ?instead of delete/*, update, insert*/as ? ?declare @id int, @name varchar(20); ? ?--查詢被刪
除的信息,病賦值 ? ?select @id = id, @name = name from deleted; ? ?print 'id: ' + convert(varchar, @id) + ', name: ' + @name; ? ?--先刪除student的信息 ? ?delete student where cid = @id; ? ?--再刪除classes的信息 ? ?delete classes where id?
= @id; ? ?print '刪除[ id: ' + convert(varchar, @id) + ', name: ' + @name + ' ] 的信息成功!';go--testselect * from student order by id;select * from classes;delete classes where id = 7; ? ?
? ? ? # 顯示自定義消息raiserror
if (object_id('tgr_message', 'TR') is not null) ? ?drop trigger tgr_messagegocreate trigger tgr_messageon student ? ?after insert, updateas raisError('tgr_message觸發器被觸發', 16, 10);go--testinsert into student values('lily', 22, 1,?
7);update student set sex = 0 where name = 'lucy';select * from student order by id;
? ? # 修改觸發器
alter trigger tgr_messageon studentafter deleteas raisError('tgr_message觸發器被觸發', 16, 10);go--testdelete from student where name = 'lucy';
? ? # 啟用、禁用觸發器?
--禁用觸發器disable trigger tgr_message on student;--啟用觸發器enable trigger tgr_message on student;
? ? # 查詢創建的觸發器信息?
--查詢已存在的觸發器select * from sys.triggers;select * from sys.objects where type = 'TR';--查看觸發器觸發事件select te.* from sys.trigger_events te join sys.triggers ton t.object_id = te.object_idwhere t.parent_class = 0 and t.name =?
'tgr_valid_data';--查看創建觸發器語句exec sp_helptext 'tgr_message';
? ? # 示例,驗證插入數據?
if ((object_id('tgr_valid_data', 'TR') is not null)) ? ?drop trigger tgr_valid_datagocreate trigger tgr_valid_dataon studentafter insertas ? ?declare @age int, ? ? ? ? ? ?@name varchar(20); ? ?select @name = s.name, @age = s.age from?
inserted s; ? ?if (@age < 18) ? ?begin ? ? ? ?raisError('插入新數據的age有問題', 16, 1); ? ? ? ?rollback tran; ? ?endgo--testinsert into student values('forest', 2, 0, 7);insert into student values('forest', 22, 0, 7);select * from?
student order by id;
? ? # 示例,操作日志?
if (object_id('log', 'U') is not null) ? ?drop table loggocreate table log( ? ?id int identity(1, 1) primary key, ? ?action varchar(20), ? ?createDate datetime default getDate())goif (exists (select * from sys.objects where name =?
'tgr_student_log')) ? ?drop trigger tgr_student_loggocreate trigger tgr_student_logon studentafter insert, update, deleteas ? ?if ((exists (select 1 from inserted)) and (exists (select 1 from deleted))) ? ?begin ? ? ? ?insert into log
(action) values('updated'); ? ?end ? ?else if (exists (select 1 from inserted) and not exists (select 1 from deleted)) ? ?begin ? ? ? ?insert into log(action) values('inserted'); ? ?end ? ?else if (not exists (select 1 from inserted) and?
exists (select 1 from deleted)) ? ?begin ? ? ? ?insert into log(action) values('deleted'); ? ?endgo--testinsert into student values('king', 22, 1, 7);update student set sex = 0 where name = 'king';delete student where name =?
'king';select * from log;select * from student order by id;
========
?SQL Server觸發器創建、刪除、修改、查看
一:觸發器是一種特殊的存儲過程,它不能被顯式地調用,而是在往表中插入記錄﹑更新記錄或者刪除記錄時被自動地激活。所以觸發器可以用來實現對表實施復雜的完整性約束。
二:SQL Server為每個觸發器都創建了兩個專用表:Inserted表和Deleted表。這兩個表由系統來維護,它們存在于內存中而不是在數據庫中。這兩個表的結構總是與被該觸發器作用的表的結構相同。觸發器執行 完成后,與該觸發器相關的這兩個表也被刪除。
Deleted表存放由于執行Delete或Update語句而要從表中刪除的所有行。
Inserted表存放由于執行Insert或Update語句而要向表中插入的所有行。
三:Instead of 和 After觸發器
SQL Server2000提供了兩種觸發器:Instead of 和After 觸發器。這兩種觸發器的差別在于他們被激活的同:
Instead of觸發器用于替代引起觸發器執行的T-SQL語句。除表之外,Instead of 觸發器也可以用于視圖,用來擴展視圖可以支持的更新操作。
After觸發器在一個Insert,Update或Deleted語句之后執行,進行約束檢查等動作都在After觸發器被激活之前發生。After觸發器只能用于表。
一個表或視圖的每一個修改動作(insert,update和delete)都可以有一個instead of 觸發器,一個表的每個修改動作都可以有多個After觸發器。
四:觸發器的執行過程
如果一個Insert﹑update或者delete語句違反了約束,那幺After觸發器不會執行,因為對約束的檢查是在After觸發器被激動之前發生的。所以After觸發器不能超越約束。
Instead of 觸發器可以取代激發它的操作來執行。它在Inserted表和Deleted表剛剛建立,其它任何操作還沒有發生時被執行。因為Instead of 觸發器在約束之前執行,所以它可以對約束進行一些預處理。
五:使用T-SQL語句來創建觸發器
基本語句如下:
create trigger trigger_name
on {table_name | view_name}
{for | After | Instead of }
[ insert, update,delete ]
as
sql_statement
六:刪除觸發器:
基本語句如下:
drop trigger trigger_name
七:查看數據庫中已有觸發器:
-- 查看數據庫已有觸發器
use jxcSoftware
go
select * from sysobjects where xtype='TR'
-- 查看單個觸發器
exec sp_helptext '觸發器名'
八:修改觸發器:
基本語句如下:
alter trigger trigger_name
on {table_name | view_name}
{for | After | Instead of }
[ insert, update,delete ]
as
sql_statement
九:相關示例:
1:在Orders表中建立觸發器,當向Orders表中插入一條訂單記錄時,檢查goods表的貨品狀態status是否為1(正在整理),是,則不能往Orders表加入該訂單。
create trigger orderinsert
on orders
after insert
as
if (select status from goods,inserted
where goods.name=inserted.goodsname)=1
begin
print 'the goods is being processed'
print 'the order cannot be committed'
rollback transaction --回滾,避免加入
end
2:在Orders表建立一個插入觸發器,在添加一條訂單時,減少Goods表相應的貨品記錄中的庫存。
create trigger orderinsert1
on orders
after insert
as
update goods set storage=storage-inserted.quantity
from goods,inserted
where
goods.name=inserted.goodsname
3:在Goods表建立刪除觸發器,實現Goods表和Orders表的級聯刪除。
create trigger goodsdelete
on goods
after delete
as
delete from orders
where goodsname in
(select name from deleted)
4:在Orders表建立一個更新觸發器,監視Orders表的訂單日期(OrderDate)列,使其不能手工修改.
create trigger orderdateupdate
on orders
after update
as
if update(orderdate)
begin
raiserror(' orderdate cannot be modified',10,1)
rollback transaction
end
5:在Orders表建立一個插入觸發器,保證向Orders表插入的貨品名必須要在Goods表中一定存在。
create trigger orderinsert3
on orders
after insert
as
if (select count(*) from goods,inserted where goods.name=inserted.goodsname)=0
begin
print ' no entry in goods for this order'
rollback transaction
end
6:Orders表建立一個插入觸發器,保證向Orders表插入的貨品信息要在Order表中添加
alter trigger addOrder
on Orders
for insert
as
insert into Order
select inserted.Id, inserted.goodName,inserted.Number from inserted
========
SQL Server:觸發器詳解
1. 概述2. 觸發器的分類
3. Inserted和Deleted表
4. 觸發器的執行過程
5. 創建觸發器
6. 修改觸發器:
7. 刪除觸發器:
8. 查看數據庫中已有觸發器:
9. “Instead of”相關示例:
10. “After”觸發器
11. 參考資源
1. 概述
觸發器是一種特殊的存儲過程,它不能被顯式地調用,而是在往表中插入記錄﹑更新記錄或者刪除記錄時被自動地激活。 所以觸發器可以用來實現對表實施復雜的完整性約束。
2. 觸發器的分類
SQL Server2000提供了兩種觸發器:“Instead of” 和“After” 觸發器。
一個表或視圖的每一個修改動作(Insert、Update和Delete)都可以有一個“Instead of” 觸發器,一個表的每個修改動作都可以有多個“After”觸發器。
2.1 “Instead of”觸發器
“Instead of”觸發器在執行真正“插入”之前被執行。除表之外,“Instead of” 觸發器也可以用于視圖,用來擴展視圖可以支持的更新操作。
“Instead of”觸發器會替代所要執行的SQL語句,言下之意就是所要執行SQL并不會“真正執行”
alter trigger trigger_學生_Delete
on 學生
instead of Delete
as
begin
? ? select 學號, 姓名 from deleted
end
?
delete from 學生 where 學號 = 4
上例中定義了“trigger學生_Delete”觸發器,該觸發器從“delete”表中打印出所要刪除的學生.在執行“delete”操作后,會發現“學號 = 4”的學生并未被刪除, 原因在于“trigger學生Delete”替代了所要執行的“delete from 學生 where 學號 = 4”語句,而
在“trigger學生_Delete”中并未真正刪除學生。
2.2 “After”觸發器
“After”觸發器在Insert、Update或Deleted語句執行之后被觸發。“After”觸發器只能用于表。
“After”觸發器主要用于表在修改后(insert、update或delete操作之后),來修改其他表
3. Inserted和Deleted表
SQL Server為每個觸發器都創建了兩個專用表:Inserted表和Deleted表。
這兩個表由系統來維護,它們存在于內存中而不是在數據庫中,可以理解為一個虛擬的表。
這兩個表的結構總是與被該觸發器作用的表的結構相同。
觸發器執行完成后,與該觸發器相關的這兩個表也被刪除。
Deleted表存放由于執行Delete或Update語句而要從表中刪除的所有行。
Inserted表存放由于執行Insert或Update語句而要向表中插入的所有行。
對表的操作 Inserted邏輯表 Deleted邏輯表
增加記錄(insert) 存放增加的記錄 無
刪除記錄(delete) 無 存放被刪除的記錄
修改記錄(update) 存放更新后的記錄 存放更新前的記錄
4. 觸發器的執行過程
如果一個Insert﹑update或者delete語句違反了約束,那么這條SQL語句就沒有執行成功,因此“After”觸發器也不會被激活。
“Instead of” 觸發器可以取代激發它的操作來執行。它在Inserted表和Deleted表剛剛建立,其它任何操作還沒有發生時被執行。因為“Instead of” 觸發器在約束之前執行,所以它可以對約束進行一些預處理。
5. 創建觸發器
create trigger trigger_name?
on ?{table_name|view_name}?
{After|Instead of} {insert|update|delete}
as 相應T-SQL語句
6. 修改觸發器:
alter trigger trigger_name?
on ?{table_name|view_name}?
{After|Instead of} {insert|update|delete}
as 相應T-SQL語句
7. 刪除觸發器:
drop trigger trigger_name
8. 查看數據庫中已有觸發器:
8.1 查看數據庫中所有觸發器
select * from sysobjects where xtype='TR'
8.2 查看單個觸發器
exec sp_helptext '觸發器名'
9. “Instead of”相關示例:
兩張表:學生(學號 int, 姓名 varchar)、借書記錄(學號 int, 圖書編號 int)
實現功能:在刪除學生表時,如果該學生仍有借書記錄(未還)則不能刪除
alter trigger trigger_學生_Delete
on 學生
instead of Delete
as
begin
? ? if not exists(select * from 借書記錄, deleted where 借書記錄.學號 = deleted.學號)
? ? ? ? delete from 學生 where 學生.學號 in (select 學號 from deleted)
end
10. “After”觸發器
10.1 在“訂單”表中建立觸發器,當向“訂單”表中插入一條訂單記錄時,檢查“商品”表的貨品狀態“狀態”是否為1(正在整理),則不能往“訂單”表加入該訂單。
create trigger trigger_訂單_insert
on 訂單
after insert
as
? ? if (select 狀態 from 商品, inserted where 商品.pid = inserted.pid)=1?
? ? begin
? ? ? ? print 'the goods is being processed'
? ? ? ? print 'the order cannot be committed'
? ? ? ? rollback transaction --回滾,避免加入?
? ? end
該示例中“pid”為商品編碼
該示例的if判斷嚴格來講是不準確的,因為“訂單”表如果每次插入一條記錄,該判斷沒有問題;如果一次插入多條記錄,則“select 狀態”返回的是多行。
10.2 在“訂單”表建立一個插入觸發器,在添加一條訂單時,減少“商品”表相應的貨品記錄中的庫存。
create trigger trigger_訂單_insert2
on 訂單
after insert
as
? ? update 商品 set 數量 = 數量 - inserted.數量
? ? from 商品, inserted?
? ? where 商品.pid = inserted.pid
10.3 在“商品”表建立刪除觸發器,實現“商品”表和“訂單”表的級聯刪除。
create trigger goodsdelete trigger_商品_delete
on 商品
after delete
as
? ? delete from 訂單 where 訂單.pid in (select pid from deleted)
10.4 在“訂單”表建立一個更新觸發器,監視“訂單”表的“訂單日期”列,使其不能被“update”.
create trigger trigger_訂單_update
on 訂單
after update
as
? ? if update(訂單日期)?
? ? begin
? ? ? ? raiserror('訂單日期不能手動修改',10,1)?
? ? ? ? rollback transaction
? ? end
10.5 在“訂單”表建立一個插入觸發器,保證向“訂單”表插入的貨品必須要在“商品”表中一定存在。
create trigger trigger_訂單_insert3
on 訂單
after insert
as
? ? if (select count(*) from 商品, inserted where 商品.pid = inserted.pid)=0?
? ? begin
? ? ? ? print '商品不存在'
? ? ? ? rollback transaction
? ? end
10.6 “訂單”表建立一個插入觸發器,保證向“訂單”表插入的貨品信息要在“訂單日志”表中添加
alter trigger trigger_訂單_insert
on 訂單?
for insert
as
? ? insert into 訂單日志 select inserted.Id, inserted.pid,inserted.數量 from inserted
========
SQL觸發器經驗詳解
觸發器的介紹
1
觸發器(trigger)是個特殊的存儲過程,它的執行不是由程序調用,也不是手工啟動,而是由事件來觸發,當對一個表進行操作( insert,delete, update)時就會激活它執行,觸發器經常用于加強數據的完整性約束和業務規則等。
觸發器的分類
1
DML( 數據操縱語言 Data Manipulation Language)觸發器:是指觸發器在數據庫中發生DML事件時將啟用。DML事件即指在表或視圖中修改數據的insert、update、delete語句。
2
DDL(數據定義語言 Data Definition Language)觸發器:是指當服務器或數據庫中發生(DDL事件時將啟用。DDL事件即指在表或索引中的create、alter、drop語句也。
3
登陸觸發器:是指當用戶登錄SQL SERVER實例建立會話時觸發。
DML觸發器介紹
1
在SQL SERVER 2008中,DML觸發器的實現使用兩個邏輯表DELETED和INSERTED。這兩個表是建立在數據庫服務器的內存中,我們只有只讀的權限。DELETED和INSERED表的結構和觸發器所在的數據表的結構是一樣的。當觸發器執行完成后,它們也就會被自動刪除:INSERED
表用于存放你在操件insert、update、delete語句后,更新的記錄。比如你插入一條數據,那么就會把這條記錄插入到INSERTED表:DELETED表用于存放你在操作 insert、update、delete語句前,你創建觸發器表中數據庫。
2
觸發器可通過數據庫中的相關表實現級聯更改,可以強制比用CHECK約束定義的約束更為復雜的約束。與 CHECK 約束不同,觸發器可以引用其它表中的列,例如觸發器可以使用另一個表中的 SELECT 比較插入或更新的數據,以及執行其它操作。觸發器也可以根據數據修
改前后的表狀態,再行采取對策。一個表中的多個同類觸發器(INSERT、UPDATE 或 DELETE)允許采取多個不同的對策以響應同一個修改語句。
3
與此同時,雖然觸發器功能強大,輕松可靠地實現許多復雜的功能,為什么又要慎用?過多觸發器會造成數據庫及應用程序的維護困難,同時對觸發器過分的依賴,勢必影響數據庫的結構,同時增加了維護的復雜程序。
觸發器步驟詳解
1
首先,我們來嘗試創建一個觸發器,要求就是在AddTable這個表上創建一個Update觸發器,語句為:
create trigger mytrigger on AddTable
for update
2
然后就是sql語句的部分了,主要是如果發生update以后,要求觸發器觸發一個什么操作。這里的意思就是如果出現update了,觸發器就會觸發輸出:the table was updated!
3
接下來我們來將AddTable表中的數據執行一個更改的操作:
4
執行后,我們會發現,觸發器被觸發,輸出了我們設置好的文本:
5
那觸發器創建以后呢,它就正式開始工作了,這時候我們需要更改觸發器的話,只需要將開始的create創建變為alter,然后修改邏輯即可:
6
如果我們想查看某一個觸發器的內容,直接運行:exec sp_helptext [觸發器名]
7
如果我想查詢當前數據庫中有多少觸發器,以方便我進行數據庫維護,只需要運行: select * from sysobjects where xtype='TR'
8
我們如果需要關閉或者開啟觸發器的話,只需要運行:
disable trigger [觸發器名] on database --禁用觸發器
enable trigger [觸發器名] on database --開啟觸發器
9
那觸發器的功能雖大,但是一旦觸發,恢復起來就比較麻煩了,那我們就需要對數據進行保護,這里就需要用到rollback數據回滾~
10
第九步的意思就是查詢AddTable表,如果里面存在TableName=newTable的,數據就回滾,觸發器中止,那我們再進行一下測試,對AddTable表進行更改,發現,觸發update觸發器之后,因為有數據保護,觸發器中止:
注意事項
禁用和開啟觸發器都需要一定的權限,如果權限不夠是無法進行操作的。
========
觸發器說明
CREATE
? ? /*[DEFINER = { user | CURRENT_USER }]*/
? ? TRIGGER `qqfs_db_gm`.`a` BEFORE/AFTER INSERT/UPDATE/DELETE
? ? ON `qqfs_db_gm`.`<Table Name>`
? ? FOR EACH ROW BEGIN
? ? END
根據以上語法,做幾點解釋!
在游戲行業,所面對的數據,都是高并發,讀寫頻繁,但是數據并不一定海量!這個時候,我們對性能的要求非常高!觸發器,對性能影響過大!所以,在我們的幾個項目中,我從沒有引入觸發器!不過對于小數據,或者是低并發、修改不頻繁的應用,適當的引入觸發
器還是可以行的!
DEFINER:觸發器的創建者,可以手動指定創建者,默認為當前用戶
BEFORE/AFTER:BEFORE,就是在觸發的動作之前執行你所想要執行的語句(begin后面的sql語句);AFTER,在觸發動作之后執行你所想要的語句!
INSERT/UPDATE/DELETE:你所要觸發的條件。分別是insert、update、delete。這里不單單的針對這三個關鍵字,同樣的有同類效果的語句也會觸發!如LOAD DATA和REPLACE語句也會觸發insert
`qqfs_db_gm`.`<Table Name>`:觸發的對象都是表
語法解釋非常簡單!需要注意以下幾點:
1.觸發器里面不允許執行動態語句!或者是執行帶動態語句的存儲過程、存儲函數等!
2.對于具有相同觸發程序動作時間和事件的給定表,不能有兩個觸發程序。例如,對于某一表,不能有兩個BEFORE UPDATE觸發程序。但可以有1個BEFORE UPDATE觸發程序和1個BEFORE INSERT觸發程序,或1個BEFORE UPDATE觸發程序和1個AFTER UPDATE觸發程序(官方說明
)
3.觸發的對象和觸發執行的語句不能為同一個表!如:觸發器a觸發b表的insert操作,然后在b表執行insert操作,會報錯!這里應該是觸發器的一種強制的鎖機制!所以就帶有很大的性能損耗!
4.不能讓兩個觸發器觸發兩個表,并使之循環!如:觸發器a觸發b表的insert操作,并往d表insert數據;觸發器c觸發d表的insert操作,并往表b insert數據;這樣是不行的!會報錯如下:Can't update table 'test' in stored function/trigger because it is?
already used by ? ? statement which invoked this stored function/trigger.(第三點也會報這樣的錯誤!)
5.觸發器中有new和old關鍵字。old是指老的數據,很容易想到,會產生老數據的是update和delete操作,因為insert之前沒有舊數據和該insert有直接關系!new關鍵字是指新數據,同理可知道,delete操作是沒有新數據產生的,所有new關鍵字使用的觸發條件是insert
和update!其實從這里可以看出,觸發器又保存了兩份數據,結合上面的對表的觸發鎖定,觸發器的性能是不敢恭維的!
6.如果要在觸發update的同時,修改該數據加1!用傳統的方法update table set id = old.id + 1;這樣肯定是不行的,違背了第三點,會報錯:Can't update table 'test' in stored function/trigger because it is already used by statement which invoked?
this stored function/trigger.注意,這個錯在觸發器編譯的時候,是能夠通過的,但是在更新的時候,數據庫會拋這個異常!
如果一定要這樣做,那該怎么辦呢?借助關鍵字new和old.
SET new.id = new.id + 1;
========
9 觸發器要點
SQL觸發器
?觸發器是一種特殊的存儲過程,它在表的數據變化時發生作用。
?觸發器可以維護數據完整性。
?觸發器在數據庫里以獨立的對象存儲。
?存儲過程通過其他程序來啟動運行,觸發器是由一個事件來啟動運行。
?觸發器不能接收參數。
?SQL支持3種類型的觸發器:插入,更新,刪除。
?觸發器執行環境還包括一個或兩個測試表,稱之為INSERTED表和DELETED表。
?測試表是虛表,用于保存目標表更新、插入或刪除的數據信息。
?Sql Server 2000及其以后的版本支持兩種類型的觸發器:AFTER觸發器,INSTEAD OF觸發器。
?AFTER觸發器即為前面介紹的UPDATE、INSERT、DELETE觸發器;INSTEAD OF觸發器表示并不執行其所定義的操作(INSERT,UPDATE,DELETE),而僅是執行觸發器本身。
總結
以上是生活随笔為你收集整理的SQL Server 触发器学习总结的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux Shell 编程学习总结
- 下一篇: VC访问数据库学习总结