首頁 > php教程 > PHP开发 > SQL總結觸發器

SQL總結觸發器

高洛峰
發布: 2016-12-14 16:24:53
原創
2586 人瀏覽過

概念

觸發器是一種特殊類型的預存過程,不由使用者直接呼叫。建立觸發器時會對其進行定義,以便在對特定表或列作特定類型的資料修改時執行。

觸發器可以查詢其他資料表,而且可以包含複雜的 SQL 語句。 它們主要用於強制服從複雜的業務規則或要求。 例如,您可以根據客戶目前的帳戶狀態,控制是否允許插入新訂單。
觸發器也可用於強制引用完整性,以便在多個表中新增、更新或刪除資料列時,保留在這些表之間所定義的關係。

作用

1)觸發器可透過資料庫中的相關表實現級聯變更;透過級聯參考完整性限制可以更有效地執行這些變更。

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

3)觸發器還可以強制執行業務規則

4)觸發器也可以評估資料修改前後的表狀態,並根據其差異採取對策。

實際應用

儘管觸發器有很多優點,但是在實際的專案開發中,特別是OOP思想的深入,觸發器的弊端也逐漸突顯,主要:

1、過多的觸發器使得資料邏輯變得複雜

2、資料操作比較隱含,不易進行調整修改

3、觸發器的功能逐漸在程式碼邏輯或事務中替代實現,更符合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觸發器又分以下分類:

1、 After觸發器

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

     1)insert觸發器

     2)update觸發器

     3)delete ete

2、Instead of 觸發動作的觸發、執行器)而僅是執行觸發器本身。既可以在表上定義instead of觸發器,也可以在視圖上定義。

inserted與deleted對比

触发器有两个特殊的表:插入表(instered表)和删除表(deleted表)。这两张是逻辑表也是虚表。有系统在内存中创建者两张表,不会存储在数据库中。而且两张表的都是只读的,只能读取数据而不能修改数据。这两张表的结果总是与被改触发器应用的表的结构相同。当触发器完成工作后,这两张表就会被删除。Inserted表的数据是插入或是修改后的数据,而deleted表的数据是更新前的或是删除的数据。

SQL總結觸發器

具体应用

在触发器实际应用中,主要还是建立约束以及级联更新。在这里主要通过简单实例予以说明。

1、触发器新增

原理:

当触发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=COUNT(Students.ID) FROM Students INNER JOIN inserted ON Students.ID =inserted.ID    
    PRINT @age
    if(@age<18)
    begin
        raiserror(&#39;学生年龄必须要大于18哦&#39;,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 行
事务在触发器中结束。批处理已中止。
登入後複製

2、触发器更新

原理:

可将UPDATE语句看成两步操作:即捕获数据前像(before image)的DELETE语句,和捕获数据后像(after image)的INSERT语句。当在定义有触发器的表上执行UPDATE语句时,原始行(前像)被移入到deleted表,更新行(后像)被移入到inserted表。

触发器检查deleted表和inserted表以及被更新的表,来确定是否更新了多行以及如何执行触发器动作。

可以使用IF UPDATE语句定义一个监视指定列的数据更新的触发器。这样,就可以让触发器容易的隔离出特定列的活动。当它检测到指定列已经更新时,触发器就会进一步执行适当的动作,例如发出错误信息指出该列不能更新,或者根据新的更新的列值执行一系列的动作语句。

场景:

专业信息ID修改,对应的学生信息中专业ID也相应进行修改

实例实现:

--更新触发器:更新专业ID时,同时更新学生的专业信息
IF OBJECT_ID (N&#39;TRIGER_Majors_Update&#39;, N&#39;tr&#39;) 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總結觸發器

执行更新操作:

UPDATE Majors SET ID=12 WHERE ID=11

执行结果:

SQL總結觸發器

3、触发器删除

原理:

当触发DELETE触发器后,从受影响的表中删除的行将被放置到一个特殊的deleted表中。deleted表是一个逻辑表,它保留已被删除数据行的一个副本。deleted表还允许引用由初始化DELETE语句产生的日志数据。

使用DELETE触发器时,需要考虑以下的事项和原则:

当某行被添加到deleted表中时,它就不再存在于数据库表中;因此,deleted表和数据库表没有相同的行。

创建deleted表时,空间是从内存中分配的。deleted表总是被存储在高速缓存中。

为DELETE动作定义的触发器并不执行TRUNCATE TABLE语句,原因在于日志不记录TRUNCATE TABLE语句。

场景:学校某选修课取消。

处理逻辑:在删除课程的同时,需要删除该课程的选课信息。

触发器:

--删除触发器:删除课程时,同时删除该课程的选课信息
IF OBJECT_ID (N&#39;TRIGER_Courses_Delete&#39;, N&#39;tr&#39;) 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總結觸發器

执行课程删除操作:

DELETE FROM Courses WHERE ID=10

执行结果:

可以看到,删除课程的同时,选修课程10的选课记录也被删除。

SQL總結觸發器

4、Instead Of 触发器

用Instead Of触发器实现与实例3相同的功能,具体实现代码如下:

--Instead Of触发器:删除课程时,同时删除该课程的选课信息
IF OBJECT_ID (N&#39;TRIGER_Courses_Instead_Delete&#39;, N&#39;tr&#39;) 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&#39;TRIGER_Students_Insert&#39;, N&#39;tr&#39;) 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 @age
    if(@age<18)
    begin
        raiserror(&#39;学生年龄必须要大于18哦&#39;,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&#39;TRIGER_Majors_Update&#39;, N&#39;tr&#39;) 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&#39;TRIGER_Courses_Delete&#39;, N&#39;tr&#39;) 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&#39;TRIGER_Courses_Instead_Delete&#39;, N&#39;tr&#39;) 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
登入後複製


相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
最新問題
熱門推薦
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板