SQL SERVER TRIGGER 觸發器

1.觸發器簡介

觸發器是一種特殊的存儲過程,它的執行不是由程序調用,也不是手動執行,而是由事件來觸發。觸發器是當對某一個表進行操做。例如:update、insert、delete這些操做的時候,系統會自動調用執行該表上對應的觸發器。sql

2.觸發器類型

一、DML( 數據操縱語言 Data Manipulation Language)觸發器:是指觸發器在數據庫中發生 DML 事件時將啓用。DML事件是指在表或視圖中對數據進行的 insert、update、delete 操做的語句。數據庫

二、DDL(數據定義語言 Data Definition Language)觸發器:是指當服務器或數據庫中發生 DDL 事件時將啓用。DDL事件是指在表或索引中的 create、alter、drop 操做語句。安全

三、登錄觸發器:是指當用戶登陸 SQL SERVER 實例創建會話時觸發。若是身份驗證失敗,登陸觸發器不會觸發。服務器

其中 DML 觸發器比較經常使用,根據 DML 觸發器觸發的方式不一樣又分爲如下兩種狀況:測試

after 觸發器(以後觸發):其中 after 觸發器要求只有執行 insert、update、delete 某一操做以後觸發器纔會被觸發,且只能定義在表上。加密

instead of 觸發器 (以前觸發):instead of 觸發器並不執行其定義的操做(insert、update、delete)而僅是執行觸發器自己。能夠在表或視圖上定義 instead of 觸發器。3d

3.觸發器語法結構

AFTER 觸發器語法:對象

CREATE [ OR ALTER ] TRIGGER [ schema_name . ]trigger_name   
ON { table }   
[ WITH <dml_trigger_option> [ ,...n ] ]  
{ FOR | AFTER }   
{ [ INSERT ] [ , ] [ UPDATE ] [ , ] [ DELETE ] }   
AS { sql_statement  [ ; ] [ ,...n ] }  

<dml_trigger_option> ::=  
    [ NATIVE_COMPILATION ]  
    [ SCHEMABINDING ]  
    [ EXECUTE AS Clause ]

INSTEAD OF 觸發器語法:blog

CREATE [ OR ALTER ] TRIGGER [ schema_name . ]trigger_name   
ON { table | view }   
[ WITH <dml_trigger_option> [ ,...n ] ]  
{ FOR | AFTER | INSTEAD OF }   
{ [ INSERT ] [ , ] [ UPDATE ] [ , ] [ DELETE ] }   
[ WITH APPEND ]  
[ NOT FOR REPLICATION ]   
AS { sql_statement  [ ; ] [ ,...n ] | EXTERNAL NAME <method specifier [ ; ] > }  

<dml_trigger_option> ::=  
    [ ENCRYPTION ]  
    [ EXECUTE AS Clause ]  

<method_specifier> ::=  
    assembly_name.class_name.method_name

DDL 觸發器語法:索引

CREATE [ OR ALTER ] 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_trigger_option> ::=  
    [ ENCRYPTION ]  
    [ EXECUTE AS Clause ]

登錄觸發器語法:

CREATE [ OR ALTER ] TRIGGER trigger_name   
ON ALL SERVER   
[ WITH <logon_trigger_option> [ ,...n ] ]  
{ FOR| AFTER } LOGON    
AS { sql_statement  [ ; ] [ ,...n ] | EXTERNAL NAME < method specifier >  [ ; ] }  

<logon_trigger_option> ::=  
    [ ENCRYPTION ]  
    [ EXECUTE AS Clause ]

 參數介紹:

  • CREATE OR ALTER:建立或者有條件的修改觸發器(即要修改的觸發器必須已經存在)
  • schema_name:ML觸發器所屬的模式的名稱(即全部者,例如:dbo)。
  • trigger_name:觸發器的名稱
  • table | view:執行 DML 觸發器的表或視圖,有時稱爲觸發器表或觸發器視圖。指定表格或視圖的徹底限定名稱是可選的。視圖只能由 INSTEAD OF 觸發器引用
  • DATABASE:將 DDL 觸發器的範圍應用於當前數據庫。若是指定,觸發器會在當前數據庫中發生 event_type 或 event_group 時觸發。
  • ALL SERVER:將 DDL 或登陸觸發器的做用域應用於當前服務器。若是指定,觸發器會在當前服務器的任何地方發生 event_type 或 event_group 時觸發
  • WITH ENCRYPTION:加密 CREATE TRIGGER 語句的文本。使用 WITH ENCRYPTION 能夠防止觸發器做爲 SQL Server 複製的一部分進行發佈。沒法爲 CLR 觸發器指定 WITH ENCRYPTION。
  • EXECUTE AS:指定執行觸發器的安全上下文。以便可以控制 SQL Server 實例用於驗證觸發器引用的任何數據庫對象的權限的用戶賬戶。
  • NATIVE_COMPILATION:表示觸發器是本地編譯的。
  • SCHEMABINDING:指定觸發器引用的表不能被刪除或更改。
  • FOR | AFTER:AFTER 指定僅在觸發 SQL 語句中指定的全部操做成功執行時觸發 DML 觸發器。全部引用級聯操做和約束檢查在此觸發器觸發以前也必須成功。當 FOR 是指定的惟一關鍵字時,AFTER 是默認值。視圖沒法定義AFTER觸發器。
  • INSTEAD OF:指定執行 DML 觸發器而不是觸發 SQL 語句,所以覆蓋觸發語句的操做。沒法爲 DDL 或登陸觸發器指定 INSTEAD OF。對於 INSTEAD OF 觸發器,在具備指定級聯動做 ON DELETE 的引用關係的表上不容許使用 DELETE 選項。相似地,在具備指定級聯動做 ON UPDATE 的引用關係的表上,不容許 UPDATE 選項。
  • {[DELETE] [,] [INSERT] [,] [UPDATE]} :指定在針對此表或視圖進行嘗試時激活 DML 觸發器的數據修改語句。必須至少指定一個選項。在觸發器定義中容許以任何順序對這些選項進行任意組合。
  • event_type:是執行後致使 DDL 觸發器觸發的 Transact-SQL 語言事件的名稱。
  • event_group:是 Transact-SQL 語言事件的預約義分組的名稱。屬於任何 Transact-SQL 語言事件執行後的 DDL 觸發器觸發 event_group。
  • sql_statement:是觸發條件和動做。觸發條件指定附加條件,以肯定嘗試的 DML,DDL 或登陸事件是否致使執行觸發器操做。
  • method_specifier:對於 CLR 觸發器,指定要與觸發器綁定的程序集的方法。該方法不得不引用任何參數並返回 void。class_name 必須是有效的 SQL Server 標識符,而且必須做爲具備程序集可見性的程序集中的類存在。

DML觸發器例子

1. 建立AFTER INSERT 觸發器:當下單後更新tbOrderTotalPrice 的統計信息

準備一張訂單表(tbOrder),包含訂單ID,訂單交易金額,訂單建立時間,準備訂單交易分段時間總額(tbOrderTotalPrice ),用來統計每月的交易合計金額

USE [TEST]
GO

/****** Object:  Trigger [dbo].[tSumTotalOrderPrice]    Script Date: 2018/5/15 11:10:04 ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TRIGGER [dbo].[tSumTotalOrderPrice] on [dbo].[tbOrder]
AFTER INSERT
AS
BEGIN
	DECLARE @DT INT
	SET @DT= CONVERT(varchar(6),GETDATE(),112)

	DECLARE @SUM DECIMAL(18, 2)
	SET @SUM=(SELECT SUM(OPrice) FROM tbOrder WHERE @DT = CONVERT(varchar(6),CreateDT,112))

	IF(EXISTS(SELECT * FROM tbOrderTotalPrice WHERE YearMoth=@DT))
	BEGIN
		UPDATE tbOrderTotalPrice SET TotalPrice=@SUM WHERE YearMoth=@DT
	END
	ELSE
	BEGIN
		INSERT INTO tbOrderTotalPrice VALUES (@DT,@SUM)
	END
END

GO

執行INSERT 行爲:INSERT INTO [dbo].[tbOrder]([OPrice],[CreateDT])VALUES(9,GETDATE())

 2.建立 instead of  insert 觸發器,當添加用戶成績記錄時候,驗證學號和學科存在才能進行添加操做

準備學生表(tbStudent),學科表(tbSubject),成績表(tbStuSubScore)

  

在學生表中添加測試學生,在學科標準添加測試學科

 

新增instead of insert 觸發器,在執行INSERT 語句前驗證學號和學科存在才能進行添加操做

USE [TEST]
GO

/****** Object:  Trigger [dbo].[tCheckStuSubScore]    Script Date: 2018/5/17 14:20:53 ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

-- =============================================
-- Author:		yangyi
-- Create date: 2018/5/17
-- Description:	新增學科分數
-- =============================================
CREATE TRIGGER [dbo].[tCheckStuSubScore] ON [dbo].[tbStuSubScore]
   INSTEAD OF INSERT
AS 
BEGIN
	--驗證學號是否存在
	IF(NOT EXISTS(SELECT * FROM tbStudent WHERE StuID=(SELECT StuID FROM inserted)))
	BEGIN
		PRINT('驗證學號不否存在')
		ROLLBACK TRANSACTION
	END
	ELSE
	BEGIN
		--驗證學科是否存在
		IF(NOT EXISTS(SELECT * FROM tbSubject WHERE SubID=(SELECT SubID FROM inserted)))
		BEGIN
			PRINT('驗證學科不否存在')
			ROLLBACK TRANSACTION
		END
		ELSE
		BEGIN
			--執行INSERT
			INSERT INTO tbStuSubScore SELECT * FROM inserted
		END
	END
END

GO
 

注意:

在觸發器語句中用兩個特殊的表一個是deleted表和inserted。它們是經過觸發器操做自動建立駐留在內存中的臨時表。
Deleted表用於存儲 DELETE和 UPDATE語句所影響的行的複本。在執行DELETE或 UPDATE語句時,行從觸發器表中刪除,並傳輸到 deleted表中。Deleted表和觸發器表一般沒有相同的行。
Inserted 表用於存儲 INSERT 和 UPDATE 語句所影響的行的副本。在一個插入或更新事務處理中,新建行被同時添加到 inserted 表和觸發器表中。Inserted 表中的行是觸發器表中新行的副本

1.插入操做(Insert) Inserted表有數據,Deleted表無數據
2.刪除操做(Delete) Inserted表無數據,Deleted表有數據
3.更新操做(Update) Inserted表有數據(新數據),Deleted表有數據(舊數據)

測試:

1>.執行INSERT 添加一條學科不存不正常在的學生成績記錄,執行失敗

INSERT INTO [dbo].[tbStuSubScore]([StuID],[Score],[SubID],[CreateDT])VALUES('001',100,0,GETDATE())  

2.>執行INSERT 添加一條學號不存不正常在的學生成績記錄,執行失敗

INSERT INTO [dbo].[tbStuSubScore]([StuID],[Score],[SubID],[CreateDT])VALUES('004',100,1,GETDATE())

 

3.>執行一條正常的學生成績記錄,執行成功

INSERT INTO [dbo].[tbStuSubScore]([StuID],[Score],[SubID],[CreateDT])VALUES('001',100,1,GETDATE())

相關文章
相關標籤/搜索