触发器的概念
触发器是一类特殊的存储过程。
它作为一个对象存储在数据库中。
触发器为数据库管理人员和程序开发人员提供了一种保证数据完整性的方法。
触发器是定义在特定的表或视图上的。
当有操作影响到触发器保护的数据时,例如,数据表发生了INSERT、UPDATE或DELETE操作时,如果该表有对应的触发器,这个触发器就会自动激活执行。
触发器的功能
触发器是针对数据库和数据表的特殊存储过程,它在指定的表中的数据发生改变时自动生效,并可以包含复杂的T-SQL语句,表达复杂的表间完整性要求,处理各种复杂的操作。
(SQL Server 2008提供了两种方法来保证数据完整性:约束和触发器)
SQL Server将触发器和触发它的语句作为可在触发器内回滚的单个事务对待,如果检测到严重错误,则整个事务即自动回滚,恢复到原来的状态。
触发器的类型
在SQL Server 2008中,根据激活触发器执行的T-SQL语句类型,可以把触发器分为两类:
一类是DML触发器(数据操作触发器),
一类是DDL触发器(数据定义触发器)。
1. DML触发器(数据操作触发器)
DML触发器是当数据库服务器中发生数据操作语言DML事件时执行的特殊存储过程,如INSERT、UPDATE或DELETE等。
DML触发器根据其引发的时机不同又可以分为两种类型:
- AFTER触发器
- INSTEAD OF触发器
1.1 AFTER触发器
在执行了INSERT、UPDATE或DELETE语句操作之后执行AFTER触发器。
它主要用于记录变更后的处理。
一旦发现错误,也可使用ROLLBACK TRANSACTION语句来回滚本次的操作。
1.2 INSTEAD OF触发器
这类触发器一般是用来取代原本要进行的操作,是在记录变更之前发生的,它并不去执行原来的SQL语句里的操作,而是去执行触发器本身所定义的操作。
2. DDL触发器
DDL触发器是当数据库服务器中发生数据定义语言DDL事件时执行的特殊存储过程,如CREATE、ALTER等。
DDL触发器一般用于执行数据库中的管理任务,如审核和规范数据库操作,防止数据库表结构被修改等。
inserted表和deleted表
每个触发器有两个特殊的表:inserted表和deleted表。
这两个表建在数据库服务器的内存中,是由系统管理的逻辑表,而不是真正存储在数据库中的物理表。
对于这两个表,用户只有读取的权限,没有修改的权限。
这两个表的结构与触发器所在的表的结构是完全一致的。
当触发器的工作完成之后,这两个表也将从内存中删除。
inserted表
对于插入记录操作来说,inserted表里存储的是要插入的数据;
对于更新记录操作来说,inserted表里存放的是要更新的记录(要写入的数据)。
deleted表
对于删除记录操作来说,deleted表里存放的是被删除的旧记录;
对于更新记录操作来说,deleted表里存放的是更新前的记录(被删除的旧记录)。
故:
进行INSERT操作时,只影响inserted表;
进行DELETE操作时,只影响deleted表;
进行UPDATE操作时,既影响inserted表也影响到deleted表。
T-SQL语句创建触发器
触发器与表(视图)是紧密相关的。
在创建触发器时,需要指定触发器的名称、包含触发器的表、引发触发器的条件以及当触发器启动后要执行的语句等内容。
CREATE TRIGGER trigger_name
ON { table_name | view_name }
{[FOR | AFTER] | INSTEAD OF}
{[INSERT ] [,] [UPDATE] [,] [DELETE]}
[WITH ENCRYPTION]
AS
SQL_statement
(1)trigger_name:触发器名称。
(2)table|view:触发器表(或触发器视图)名称,指出被触发者。
(3)FOR|AFTER| INSTEAD OF:FOR与AFTER均指定为AFTER触发器,INSTEAD OF指定为INSTEAD OF触发器。该项指出了触发时机(即何时触发)。
(4)INSERT 指定了为INSERT触发器,UPDATE指定为UPDATE触发器, DELETE指定为DELETE触发器。该项指出了何种操作触发。
(5)WITH ENCRYPTION:对CREATE TRIGGER语句的文本进行加密。防止将触发器作为 SQL Server 复制的一部分进行发布。
(6)AS 引导触发器的主体。
(7)SQL_statement指出触发器完成的功能。
注意,创建触发器有下列限制:
(1)CREATE TRIGGER必须是批处理中的第一条语句,并且只能应用于一个表(视图)。
(2)触发器只能在当前数据库中创建。
(3)不能在视图上定义 AFTER 触发器。在表或视图上,每个 INSERT、UPDATE 或 DELETE 语句最多可以定义一个 INSTEAD OF 触发器。
(4)创建DML触发器的权限默认分配给表的所有者,且不能将该权限转给其他用户。
(5)在触发器内可以指定任意的 SET 语句。选择的 SET 选项在触发器执行期间保持有效,然后恢复为原来的设置。
创建INSERT触发器
- 创建触发器tr1_student ,为student新增学生后,统计新增的人数并输出。
CREATE TRIGGER tr1_student ON student
AFTER INSERT
AS
DECLARE @Scount int;
SELECT @Scount=COUNT(*) FROM INSERTED;
PRINT @Scount;
触发该触发器的语句 :
INSERT INTO student
VALUES ( …… ) /*可多行*/
( …… )
… ;
创建INSERT触发器
设c001、c002是每个学生的必修课,创建触发器tr2_student ,新增一个学生后,增加其选课信息。
CREATE TRIGGER tr2_student ON student
AFTER INSERT
AS
DECLARE @Snum CHAR(8);
SELECT @Snum=Sno FROM INSERTED;
INSERT INTO sc
VALUES ( @Snum,’c001’,null ), ( @Snum,’c002’,null );
触发该触发器的语句 :
INSERT INTO student VALUES( …… ); /*只能一行*/
创建DELETED触发器
- 创建触发器tr1_sc ,删除c001的选课信息,统计其记录数并输出。(即删除了的记录个数)
CREATE TRIGGER tr1_sc ON sc
AFTER DELETE
AS
DECLARE @Scount int;
SELECT @Scount=COUNT(*) FROM DELETED;
PRINT ‘从SC中删除了’+cast(@Scount as char(4))+’行。’;
触发该触发器的语句 :
DELETE FROM SC WHERE Cno=‘c001’;
创建UPDATE触发器
UPDATE触发器在用户发出UPDATE语句后触发执行。
该触发器合并了DELETE触发器和INSERT触发器的作用。
在用户执行了UPDATE语句后,原来的数据行从基本表中删除,但保存在DELETED表中,同时基本表更新后的新数据行也在INSERTED表中保存了一个副本。
可利用DELETED表和INSERTED表,获取更新前后的数据行,完成比较操作。
设有表SC1(Sno,Cno,Grade,Note),当Grade>=60时Note为’通过’,否则为’不通过’。创建一触发器,当修改某学生某门课的成绩Grade时,相应的备注列Note也随之修改。
CREATE TRIGGER tr1_sc1 ON sc1
AFTER UPDATE
AS
DECLARE @Sn CHAR(8) , @Cn CHAR(4), @G int, @Gnote CHAR(8);
SELECT @Sn=Sno, @Cn=Cno, @G=Grade, @Gnote=note
FROM INSERTED;
IF @G>=60
UPDATE SC1 SET Note=‘通过’ where Sno= @Sn and Cno= @Cn
ELSE
UPDATE SC1 SET Note=‘不通过’ where Sno= @Sn and Cno=@Cn
设修改的是课程Cno=‘c001’ 、学生 Sno=‘20160001的成绩为89,则触发该触发器的语句 :
UPDATE SC1 SET Grade=89 WHERE Cno=‘c001’ and Sno=‘20160001’;
创建INSTEAD OF触发器
定义一触发器XSDA_UPDATE,一旦对XSDA表有任何更新操作,触发器显示“禁止更新!”,并取消所做修改。
CREATE TRIGGER XSDA_UPDATE ON xsda
INSTEAD OF UPDATE
AS
PRINT ‘禁止更新!’;
创建复合触发器
复合触发器:完成多种功能(INSERT、DELETE、UPDATE)的触发器。
创建一触发器tr5_sc ,不允许修改或删除SC表中2011级学生的成绩信息。
(如果是after触发器,则要撤销( ROLLBACK TRANSACTION )对数据库所做的更新操作!)
复合触发器:
CREATE TRIGGER tr5_sc ON sc
AFTER DELETE, UPDATE
AS
DECLARE @Snum CHAR(8)
SELECT @Snum=Sno FROM DELETED;
IF @Snum LIKE ‘2011_ _ _ _'
BEGIN
ROLLBACK TRANSACTION
PRINT ‘不允许修改或删除2011级学生成绩信息!'
END
假设要把学生‘20110001’的课程‘c001’ 成绩改为89,则触发该触发器的语句 :
UPDATE SC SET Grade=89 WHERE Cno=‘c001’ and Sno=‘20110001’;
或者进行删除操作
DELETE FROM SCWHERE Cno=‘c001’ and Sno=‘20110001’;
instead of触发器:
CREATE TRIGGER tr5_sc ON sc
instead of DELETE, UPDATE
AS
DECLARE @Snum CHAR(8)
SELECT @Snum=Sno FROM DELETED;
IF @Snum LIKE ‘2011_ _ _ _'
BEGIN
PRINT ‘不允许修改或删除2011级学生成绩信息!'
END
注:
同一个数据库中触发器名字不能相同,即使不在同一个表(视图)中。
删除触发器
语法格式:
DROP TRIGGER trigger_name[,…]
说明:trigger_name为需要删除的触发器名称,当一次删除多个触发器时,各个触发器名称之间用逗号隔开。
例如:
DROP TRIGGER tr5_sc
修改触发器
ALTER TRIGGER <触发器名>
ON <表名>
{AFTER|FOR} {[INSERT][,][UPDATE][,] [DELETE]}
AS
[ SQL 语句 ]
工作量相当于重新创建同名触发器。