触发器
触发器概念:
触发器是一种特殊类型的存储过程,不由用户直接调用。创建触发器时会对其进行定义,以便在对特定表或列作特定类型的数据修改时执行。
触发器总结:
- 触发器是与数据库和数据表相结合的特殊的存储过程,当数据表有Insert、Update、Delete操作或数据库有Create、Alter、Drop 操作的时候,可以激活触发器,并运行其中的T-SQL 语句。
- 在SQLServer 2008 中触发器分有DML 触发器和DDL 触发器两种。
其中DML触发器又分为After 触发器和Instead Of 触发器两种。
After 触发器是先修改记录后激活的触发器;
Instead Of 触发器是“取代”触发器。
DDL 触发器根据作用范围可以分为作用在数据库的触发器和作用在服务器的触发器两种。
After 触发器只能用于数据表中,而Instead Of触发器即可以用在数据表中,也可以用在视图中。
- 使用CREATETRIGGER语句可以创建触发器,使用ALTER TRIGGER语句可以修改触发器,使用Drop Trigger 语句可以删除触发器。
- 触发器允许嵌套和递归,嵌套最多可以是32 层。
其本质是:
- 它不能被显式地调用,而是在往表中插入记录、更改记录或者删除记录时,当事件发生时,才被自动地激活。
- CREATE PROCEDURE 或 CREATE TRIGGER 语句不能跨越批处理。即存储过程或触发器始终只能在一个批处理中创建并编译到一个执行计划中。
- 用触发器还可以强制执行业务规则MicrosoftSQL Server 提供了两种主要机制来强制业务规则和数据完整性:约束和触发器。
- 触发器是一种特殊类型的存储过程,它在指定的表中的数据发生变化时自动生效。唤醒调用触发器以响应INSERT、UPDATE 或 DELETE 语句。
- 触发器可以查询其它表,并可以包含复杂的Transact-SQL 语句。将触发器和触发它的语句作为可在触发器内回滚的单个事务对待。如果检测到严重错误(例如,磁盘空间不足),则整个事务即自动回滚。因此就具备了事务的所有特征。
注意: ‘事务具备什么特征?在触发器中的作用?‘
如果发现引起触发器执行的T-SQL 语句执行了一个非法操作,比如关于其它表的相关性操作,发现数据丢失或需调用的数据不存在,那么就回滚到该事件执行前的SQL SERVER数据库状态。
A、触发器的优点
1)触发器可通过数据库中的相关表实现级联更改;不过,通过级联引用完整性约束可以更有效地执行这些更改。
2)触发器可以强制比用CHECK 约束定义的约束更为复杂的约束。与 CHECK 约束不同,触发器可以引用其它表中的列。例如,触发器可以使用另一个表中的 SELECT 比较插入或更新的数据,以及执行其它操作,如修改数据或显示用户定
义错误信息。
3)触发器也可以评估数据修改前后的表状态,并根据其差异采取对策。一个表中的多个同类触发器(INSERT、UPDATE 或 DELETE)允许采取多个不同的对策以响应同一个修改语句。
B、触发器与约束的对比:
- 触发器的主要好处在于它们可以包含使用Transact-SQL代码的复杂处理逻辑。因此,触发器可以支持约束的所有功能;
- 在约束所支持的功能无法满足应用程序的功能要求时,触发器就极为有用。例如:除非 REFERENCES 子句定义了级联引用操作,否则FOREIGN KEY 约束只能以与另一列中的值完全匹配的值来验证列值。CHECK 约束只能根据逻辑表达式或同一表中的另一列来验证列值。如果应用程序要求根据另一个表中的列验证列值,则必须使用触发器。
- 约束只能通过标准的系统错误信息传递错误信息。如果应用程序要求使用(或能从中获益)自定义信息和较为复杂的错误处理,则必须使用触发器。
- 触发器可通过数据库中的相关表实现级联更改;不过,通过级联引用完整性约束可以更有效地执行这些更改。触发器可以禁止或回滚违反引用完整性的更改,从而取消所尝试的数据修改。当更改外键且新值与主键不匹配时, 此类触发器就可能发生作用。
例如, 可以在titleauthor.title_id上创建一个插入触发器,使它在新值与titles.title_id中的某个值不匹配时回滚一个插入。不过,通常使用FOREIGNKEY 来达到这个目的。如果触发器表上存在约束,则在INSTEADOF 触发器执行后但在AFTER 触发器执行前检查这些约束。如果约束破坏,则回滚INSTEAD OF 触发器操作并且不执行AFTER触发器。
C、触发器功能
完成比约束更复杂的数据约束:触发器可以实现比约束更为复杂的数据约束
检查所做的SQL 是否允许:触发器可以检查SQL 所做的操作是否被允许。
例如:在产品库存表里,如果要删除一条产品记录,在删除记录时,触发器可以
检查该产品库存数量是否为零,如果不为零则取消该删除操作。
修改其它数据表里的数据:当一个SQL 语句对数据表进行操作的时候,触发器可以根据该SQL 语句的操作情况来对另一个数据表进行操作。
例如:一个订单取消的时候,那么触发器可以自动修改产品库存表,在订购量的字段上减去被取消订单的订购数量。
调用更多的存储过程:约束的本身是不能调用存储过程的,但是触发器本身就
是一种存储过程,而存储过程是可以嵌套使用的,所以触发器也可以调用一个
或多过存储过程。
发送SQL Mail:在SQL 语句执行完之后,触发器可以判断更改过的记录是否
达到一定条件,如果达到这个条件的话,触发器可以自动调用SQL Mail 来发
送邮件。
例如:当一个订单交费之后,可以物流人员发送Email,通知他尽快发货。
返回自定义的错误信息:约束是不能返回信息的,而触发器可以。例如插入一
条重复记录时,可以返回一个具体的友好的错误信息给前台应用程序。
更改原本要操作的SQL 语句:触发器可以修改原本要操作的SQL 语句,例如
原本的SQL 语句是要删除数据表里的记录,但该数据表里的记录是最要记录,
不允许删除的,那么触发器可以不执行该语句。
防止数据表结构更改或数据表被删除:为了保护已经建好的数据表,触发器可
以在接收到Drop 和Alter 开头的SQL 语句里,不进行对数据表的操作。
触发器分类
在SQLServer 中,触发器可以分为两大类:DML 触发器和DDL 触发器
DML 触发器:
DML触发器是当数据库服务器中发生数据操作语言(Data Manipulation
Language)事件时执行的存储过程。
DML 触发器又分为两类:After 触发器和Instead Of 触发器
○1 、After 触发器:这类触发器是在记录已经改变完之后(after),才会被激活执行,它主要是用于记录变更后的处理或检查,一旦发现错误,也可以用RollbackTransaction 语句来回滚本次的操作。即AFTER 触发器在执行INSERT、UPDATE或DELETE 语句的操作之后执行
○2 、InsteadOf 触发器:这类触发器一般是用来取代原本的操作,在记录变更之前发生的,它并不去执行原来SQL 语句里的操作(Insert、Update、Delete),
而去执行触发器本身所定义的操作。INSTEADOF 触发器代替INSERT,UPDATE 或DELETE语句执行
DDL 触发器:
DDL触发器是在响应数据定义语言(Data Definition Language)事件时执行的存
储过程。DDL 触发器一般用于执行数据库中管理任务。如审核和规范数据库操作、防止数据库表结构被修改等。
3)、触发器工作方式:
○1 、INSERT触发器的工作方式
1 执行INSERT语句
3 执行AFTER INSERT触发器语句
2 记录INSERT语句
CREATETRIGGER [insrtWorkOrder] ON [Production].[WorkOrder]
AFTERINSERT AS
BEGIN
SETNOCOUNT ON
INSERTINTO [Production].[TransactionHistory]
([ProductID],
[ReferenceOrderID],
[TransactionType],
[TransactionDate],
[Quantity],
[ActualCost])
SELECT
inserted.[ProductID],inserted.[WorkOrderID],‘W‘,GETDATE(),inserted.[OrderQty],0
FROM inserted
○2 、DELETE触发器的工作方式
临时表Inserted 和Deleted:
q 触发器触发时:
q 系统自动在内存中创建deleted 表或inserted 表
q 只读,不允许修改;触发器执行完成后,自动删除
l 删除的表(Deleted)用于存储DELETE 和 UPDATE语句所影响的行的副本。在执行DELETE 或 UPDATE 语句的过程中,行从触发器表中删除,并传输到删除的表中。删除的表和触发器表通常没有相同的行。可以从deleted 表中检查被删除的数据是否满足业务需求,如果不满足,则向用户报告错误消息,并回滚插入操作,因为触发器本身就是一个特殊的事务单元。
l 插入的表(Inserted)用于存储INSERT 和 UPDATE语句所影响的行的副本。在插入
1执行DELETE语句
2执行AFTER DELETE 触发器语句
3记录DELETE 语句
CREATETRIGGER [updtProductReview] ON [Production].[ProductReview]
AFTERUPDATE NOT FORREPLICATION AS
BEGIN
UPDATE[Production].[ProductReview]
SET [Production].[ProductReview].[ModifiedDate] = GETDATE()
FROM inserted
WHEREinserted.[ProductReviewID] =
[Production].[ProductReview].[ProductReviewID]
END
或更新事务期间,新行将同时被添加到插入的表和触发器表。插入的表中的行是触
发器表中的新行的副本。可以从inserted 表中检查插入的数据是否满足业务需求,
如果不满足,则向用户报告错误消息,并回滚插入操作
l 更新事务类似于在删除操作之后执行插入操作;
首先,旧行被复制到删除的表中,然后,新行被复制到触发器表和插入的表中。
修改操作 inserted 表 deleted表增加(INSERT)记录 存放新增的记录------
删除(DELETE)记录----- 存放被删除的记录
修改(UPDATE)记录 存放更新后的记录 存放更新前的记录
○3 、INSTEADOF 触发器的工作方式
○4 、嵌套触发器的工作方式
CREATETRIGGER [delEmployee] ON [HumanResources].[Employee]
INSTEADOF DELETE NOT FORREPLICATION AS
BEGIN
SETNOCOUNT ON
DECLARE@DeleteCount int
SELECT@DeleteCount = COUNT(*)
FROM deleted
IF @DeleteCount > 0
BEGIN
…
END
END