SQL Server -- 觸發器總結(練習&約束)

http://www.cnblogs.com/yank/p/4193820.html html

概念sql

觸發器是一種特殊類型的存儲過程,不禁用戶直接調用。建立觸發器時會對其進行定義,以便在對特定表或列做特定類型的數據修改時執行。數據庫

觸發器能夠查詢其餘表,並且能夠包含複雜的 SQL 語句。 它們主要用於強制服從複雜的業務規則或要求。 例如,您能夠根據客戶當前的賬戶狀態,控制是否容許插入新訂單。
觸發器也可用於強制引用完整性,以便在多個表中添加、更新或刪除行時,保留在這些表之間所定義的關係。緩存

做用架構

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

2)觸發器能夠強制比用 CHECK 約束定義的約束更爲複雜的約束。與 CHECK 約束不一樣,觸發器能夠引用其它表中的列。例如,觸發器可使用另外一個表中的 SELECT 比較插入或更新的數據,以及執行其它操做,如修改數據或顯示用戶定義錯誤信息。測試

3)觸發器還能夠強制執行業務規則日誌

4)觸發器也能夠評估數據修改先後的表狀態,並根據其差別採起對策。code

實際應用htm

儘管觸發器有不少優勢,可是在實際的項目開發中,特別是OOP思想的深刻,觸發器的弊端也逐漸突顯,主要:

一、過多的觸發器使得數據邏輯變得複雜

二、數據操做比較隱含,不易進行調整修改

三、觸發器的功能逐漸在代碼邏輯或事務中替代實現,更符合OO思想。

建議:

使用觸發器需慎重。

語法

CREATE TRIGGER trigger_name
ON {table_name | view_name}
{FOR | After | Instead of } [ insert, update,delete ]
AS
sql_statement

觸發器類型

SQL Server 包括兩種常規類型的觸發器:數據操做語言 (DML) 觸發器和數據定義語言 (DDL) 觸發器。 當INSERT、UPDATE 或 DELETE 語句修改指定表或視圖中的數據時,可使用 DML 觸發器。 DDL 觸發器激發存儲過程以響應各類 DDL 語句,這些語句主要以CREATE、ALTER 和 DROP 開頭。 DDL 觸發器可用於管理任務,例如審覈和控制數據庫操做。

一般說的觸發器就是DML觸發器。

DML 觸發器在 INSERT、UPDATE 和 DELETE 語句上操做,而且有助於在表或視圖中修改數據時強制業務規則,擴展數據完整性。

在SQL Server2005後又增長了DDL觸發器。

DDL 觸發器將激發存儲過程以響應事件。但與 DML 觸發器不一樣的是,它們不會爲響應針對表或視圖的 UPDATE、INSERT 或 DELETE 語句而激發。相反,它們將爲了響應各類數據定義語言 (DDL) 事件而激發。這些事件主要與以關鍵字 CREATE、ALTER 和 DROP 開頭的 Transact-SQL 語句對應。執行 DDL 式操做的系統存儲過程也能夠激發 DDL 觸發器。

DDL 觸發器使用場合:
•要防止對數據庫架構進行某些更改。
•但願數據庫中發生某種狀況以響應數據庫架構中的更改。
•要記錄數據庫架構中的更改或事件。

在這裏咱們只講述DML觸發器。DML觸發器又分如下分類:

一、 After觸發器

After觸發器要求只有執行某一操做insert、update、delete以後觸發器才被觸發,且只能定義在表上。

1)insert觸發器

 2)update觸發器

 3)delete觸發器

二、Instead of 觸發器

Instead of 觸發器表示並不執行其定義的操做(insert、update、delete)而僅是執行觸發器自己。既能夠在表上定義instead of觸發器,也能夠在視圖上定義。

inserted與deleted對比

觸發器有兩個特殊的表:插入表(instered表)和刪除表(deleted表)。這兩張是邏輯表也是虛表。有系統在內存中建立者兩張表,不會存儲在數據庫中。並且兩張表的都是隻讀的,只能讀取數據而不能修改數據。這兩張表的結果老是與被改觸發器應用的表的結構相同。當觸發器完成工做後,這兩張表就會被刪除。Inserted表的數據是插入或是修改後的數據,而deleted表的數據是更新前的或是刪除的數據。

對錶的操做 Inserted邏輯表 Deleted邏輯表
增長記錄(insert) 存放增長的記錄
刪除記錄(delete) 存放被刪除的記錄
修改記錄(update) 存放更新後的記錄 存放更新前的記錄

具體應用

在觸發器實際應用中,主要仍是創建約束以及級聯更新。在這裏主要經過簡單實例予以說明。

一、觸發器新增

原理:

當觸發INSERT觸發器時,新的數據行就會被插入到觸發器表和inserted表中。inserted表是一個邏輯表,它包含了已經插入的數據行的一個副本。inserted表包含了INSERT語句中已記錄的插入動做。inserted表還容許引用由初始化INSERT語句而產生的日誌數據。觸發器經過檢查inserted表來肯定是否執行觸發器動做或如何執行它。inserted表中的行老是觸發器表中一行或多行的副本。

場景:增長學生信息時,要校驗其年齡,暫定其年齡必須大於18,不然新增失敗

做用:校驗約束

具體實例:

複製代碼
--觸發器新增:只容許錄取18歲以上學生
IF OBJECT_ID (N'TRIGER_Students_Insert', N'tr') IS NOT NULL
DROP TRIGGER TRIGER_Students_Insert;
GO
CREATE TRIGGER TRIGER_Students_Insert
ON Students
FOR INSERT
AS
declare @age int
select @age= Students.age FROM Students INNER JOIN inserted ON Students.ID =inserted.ID
PRINT @agebr/>if(@age<18)
begin
raiserror('學生年齡必需要大於18哦',16,8)
rollback tran
end

執行insert:

INSERT INTO Students(ID,Name,Age,City,MajorID) VALUES(105,'李四',16,'BeiJing',11)

執行結果:

會直接異常,返回錯誤信息

消息 50000,級別 16,狀態 8,過程 TRIGER_Students_Insert,第 10 行
學生年齡必需要大於18哦
消息 3609,級別 16,狀態 1,第 1 行
事務在觸發器中結束。批處理已停止。

二、觸發器更新

原理:

可將UPDATE語句當作兩步操做:即捕獲數據前像(before image)的DELETE語句,和捕獲數據後像(after image)的INSERT語句。當在定義有觸發器的表上執行UPDATE語句時,原始行(前像)被移入到deleted表,更新行(後像)被移入到inserted表。

觸發器檢查deleted表和inserted表以及被更新的表,來肯定是否更新了多行以及如何執行觸發器動做。

可使用IF UPDATE語句定義一個監視指定列的數據更新的觸發器。這樣,就可讓觸發器容易的隔離出特定列的活動。當它檢測到指定列已經更新時,觸發器就會進一步執行適當的動做,例如發出錯誤信息指出該列不能更新,或者根據新的更新的列值執行一系列的動做語句。

場景:

專業信息ID修改,對應的學生信息中專業ID也相應進行修改

實例實現:

--更新觸發器:更新專業ID時,同時更新學生的專業信息
IF OBJECT_ID (N'TRIGER_Majors_Update', N'tr') IS NOT NULL
DROP TRIGGER TRIGER_Majors_Update;
GO
CREATE TRIGGER TRIGER_Majors_Update
ON Majors
FOR UPDATE
AS
IF UPDATE(ID)
UPDATE Students Set MajorID=inserted.ID
FROM Students,deleted,inserted
WHERE Students.MajorID = deleted.ID

原始數據:
SQL Server --  觸發器總結(練習&約束)

執行更新操做:

UPDATE Majors SET ID=12 WHERE ID=11

執行結果:
SQL Server --  觸發器總結(練習&約束)

三、觸發器刪除

原理:

當觸發DELETE觸發器後,從受影響的表中刪除的行將被放置到一個特殊的deleted表中。deleted表是一個邏輯表,它保留已被刪除數據行的一個副本。deleted表還容許引用由初始化DELETE語句產生的日誌數據。

使用DELETE觸發器時,須要考慮如下的事項和原則:
•當某行被添加到deleted表中時,它就再也不存在於數據庫表中;所以,deleted表和數據庫表沒有相同的行。
•建立deleted表時,空間是從內存中分配的。deleted表老是被存儲在高速緩存中。
•爲DELETE動做定義的觸發器並不執行TRUNCATE TABLE語句,緣由在於日誌不記錄TRUNCATE TABLE語句。

場景:學校某選修課取消。

處理邏輯:在刪除課程的同時,須要刪除該課程的選課信息。

觸發器:

--刪除觸發器:刪除課程時,同時刪除該課程的選課信息
IF OBJECT_ID (N'TRIGER_Courses_Delete', N'tr') IS NOT NULL
DROP TRIGGER TRIGER_Courses_Delete;
GO
CREATE TRIGGER TRIGER_Courses_Delete
ON Courses
FOR DELETE
AS
DELETE SC
FROM SC,deleted
WHERE SC.CourseID = deleted.ID

原始數據:
SQL Server --  觸發器總結(練習&約束)

執行課程刪除操做:

DELETE FROM Courses WHERE ID=10

執行結果:

能夠看到,刪除課程的同時,選修課程10的選課記錄也被刪除。

SQL Server --  觸發器總結(練習&約束)

四、Instead Of 觸發器

用Instead Of觸發器實現與實例3相同的功能,具體實現代碼以下:

複製代碼
--Instead Of觸發器:刪除課程時,同時刪除該課程的選課信息
IF OBJECT_ID (N'TRIGER_Courses_Instead_Delete', N'tr') IS NOT NULL
DROP TRIGGER TRIGER_Courses_Instead_Delete;
GO
CREATE TRIGGER TRIGER_Courses_Instead_Delete
ON Courses
Instead Of DELETE
AS
declare @courseId int
--獲取要刪除的課程ID
SELECT @courseId=ID FROM deleted
--刪除選課信息
DELETE FROM SC WHERE CourseID = @courseId
--刪除課程信息
DELETE FROM Courses WHERE ID=@courseId

執行刪除:

--測試用例
DELETE FROM Courses WHERE ID=10

測試結果:

其測試結果與實例3相同。

本文測試用例腳本:

--數據準備
--學生信息表
IF OBJECT_ID (N'Students', N'U') IS NOT NULL
DROP TABLE Students;
GO
CREATE TABLE Students(
ID int primary key not null,
Name nvarchar(50),
Age int,
City nvarchar(50),
MajorID int
)

--專業信息表
IF OBJECT_ID (N'Majors', N'U') IS NOT NULL
DROP TABLE Majors;
GO
CREATE TABLE Majors(
ID int primary key not null,
Name nvarchar(50)
)

--課程表
IF OBJECT_ID (N'Courses', N'U') IS NOT NULL
DROP TABLE Courses;
GO
CREATE TABLE Courses(
ID int primary key not null,
Name nvarchar(50) not null
)

IF OBJECT_ID (N'SC', N'U') IS NOT NULL
DROP TABLE SC;
GO
--選課表
CREATE TABLE SC(
StudentID int not null,
CourseID int not null,
Score int
)

/
基礎數據
/

--專業信息
DELETE FROM Majors
INSERT INTO Majors(ID,Name) VALUES(10,'法律')
INSERT INTO Majors(ID,Name) VALUES(11,'美學')

--課程信息
DELETE FROM Courses
INSERT INTO Courses(ID,Name) VALUES (10,'太極拳')
INSERT INTO Courses(ID,Name) VALUES (11,'攝影入門')
INSERT INTO Courses(ID,Name) VALUES (12,'生命科學導論')

--學生信息
DELETE FROM Students
INSERT INTO Students(ID,Name,Age,City,MajorID) VALUES(101,'Tom',20,'BeiJing',10)
INSERT INTO Students(ID,Name,Age,City,MajorID) VALUES(103,'李明',20,'BeiJing',11)
INSERT INTO Students(ID,Name,Age,City,MajorID) VALUES(104,'王濤',18,'ShangHai',11)

--選課信息
DELETE FROM SC
INSERT INTO SC(StudentID,CourseID) VALUES(101,10)
INSERT INTO SC(StudentID,CourseID) VALUES(101,11)
INSERT INTO SC(StudentID,CourseID) VALUES(102,12)

--觸發器新增:只容許錄取18歲以上學生
IF OBJECT_ID (N'TRIGER_Students_Insert', N'tr') IS NOT NULL
DROP TRIGGER TRIGER_Students_Insert;
GO
CREATE TRIGGER TRIGER_Students_Insert
ON Students
FOR INSERT
AS
declare @age int
select @age=COUNT(Students.ID) FROM Students INNER JOIN inserted ON Students.ID =inserted.ID
PRINT @agebr/>if(@age<18)
begin
raiserror('學生年齡必需要大於18哦',16,8)
rollback tran
end

--測試用例
INSERT INTO Students(ID,Name,Age,City,MajorID) VALUES(105,'李四',16,'BeiJing',11)
SELECT * FROM Students

--更新觸發器:更新專業ID時,同時更新學生的專業信息
IF OBJECT_ID (N'TRIGER_Majors_Update', N'tr') IS NOT NULL
DROP TRIGGER TRIGER_Majors_Update;
GO
CREATE TRIGGER TRIGER_Majors_Update
ON Majors
FOR UPDATE
AS
IF UPDATE(ID)
UPDATE Students Set MajorID=inserted.ID
FROM Students,deleted,inserted
WHERE Students.MajorID = deleted.ID

--測試用例
UPDATE Majors SET ID=12 WHERE ID=11

SELECT FROM Students
SELECT
FROM Majors

--刪除觸發器:刪除課程時,同時刪除該課程的選課信息
IF OBJECT_ID (N'TRIGER_Courses_Delete', N'tr') IS NOT NULL
DROP TRIGGER TRIGER_Courses_Delete;
GO
CREATE TRIGGER TRIGER_Courses_Delete
ON Courses
FOR DELETE
AS
DELETE SC
FROM SC,deleted
WHERE SC.CourseID = deleted.ID

--測試用例
DELETE FROM Courses WHERE ID=10

--執行結果
SELECT FROM Students
SELECT
FROM Courses
SELECT * FROM SC

--Instead Of觸發器:刪除課程時,同時刪除該課程的選課信息
IF OBJECT_ID (N'TRIGER_Courses_Instead_Delete', N'tr') IS NOT NULL
DROP TRIGGER TRIGER_Courses_Instead_Delete;
GO
CREATE TRIGGER TRIGER_Courses_Instead_Delete
ON Courses
Instead Of DELETE
AS
declare @courseId int
--獲取要刪除的課程ID
SELECT @courseId=ID FROM deleted
--刪除選課信息
DELETE FROM SC WHERE CourseID = @courseId
--刪除課程信息
DELETE FROM Courses WHERE ID=@courseId

--測試用例
DELETE FROM Courses WHERE ID=10

--執行結果
SELECT FROM Students
SELECT
FROM Courses
SELECT * FROM SC

其餘

關於raiserror可見:

https://msdn.microsoft.com/zh-cn/library/ms178592.aspx

相關文章
相關標籤/搜索