1、什么时触发器?
1)触发器是一个在修改指定表中的数据时执行的存储过程。经常通过创建触发器来强制实现不同表中的逻辑相关数据的引用完整性或一致性。由于用户不能绕过触发器,所以可以用它来强制实施复杂的业务规则,以此确保数据的完整性。
2)触发器不同于存储过程。触发器主要是通过事件进行触发而被执行的,而存储过程可以通过存储过程名字而被直接调用。当对某一表进行诸如:UDPATE、INSERT、DELETE这些操作时,SQL Server就会自动执行触发器所定义的SQL语句,从而确保对数据的处理必须符合由这些SQL语句所定义的规则。
为什么要使用触发器?
1)触发器自动执行,它们在表的数据作了任何修改(比如手工输入或者使用程序采集的操作)之后立即激活。
2)触发器可以通过数据库中的相关表进行层叠更改。这比直接把代码写在前台的做法更完全合理。
3)触发器可以强制限制,这些限制比用CHECK约束所定义的更复杂。与CHECK约束不同的是,触发器可以引用其他表中的列。
触发器的种类
1)DDL触发器
DDL触发器当服务器或者数据库中发生数据定义语言(DDL)事件时被调用。如果要执行以下操作,可以使用DDL触发器:
a)要防止对数据库架构进行某些更改
b)希望数据库中发生某种情总以响应数据库架构中的更改
c)要记录数据库架构中的更改或者事件
2)DML触发器
DML触发器是当数据库服务器发生数据操作语言(DML)事件时要执行的操作。通常所说的DML触发器主要包括三种:INSERT触发器、UPDATE触发器、DELETE触发器。DML触发器可以查询其他表,还可以包含复杂的T-SQL语句。将触发器和触发它的语句做为可在触发器内回滚的单个事务对待。如果检测到错误,则整个事务自动回滚。
2、创建INSERT触发器
语法格式
CREATE TRIGGER trigger_name
ON {table|view}
{
{{FOR | AFTER | INSTEAD OF}
{[DELETE][,][INSERT][,][UPDATE]}
AS
sql _statement
}
}
CREATE TRIGGER t_AddOrder
on [ORDER]
for insert
as
declare @pid int, @sale int
select @pid=pid,@sale=[count] from inserted
update product set proCount=proCount-@sale where PID = @pid
3、创建DELETE触发器
ALTER TRIGGER t_RemoveOrder
on [ORDER]
for delete
as
DECLARE cur_deleted scroll CURSOR
FOR select pid,[count] from deleted
FOR read only
OPEN cur_deleted
declare @pid int, @sale int
FETCH NEXT FROM cur_deleted into @pid,@sale
while @@fetch_status=0
BEGIN
update product set proCount=proCount+@sale where PID = @pid
FETCH NEXT FROM cur_deleted into @pid,@sale
End
CLOSE cur_deleted
DEALLOCATE cur_deleted
insert into [Order] (pid,[count]) values (1,2)
insert into [Order] (pid,[count]) values (2,3)
delete [Order]
select * from [Order]
select * from [Product]
4、创建UPDATE触发器
注:可以把UPDATE动作看作DELETE + INSERT 动作的组合,既先删除旧的这些记录,再插入一条新的记录,此时在数据库中存在了两个临时表,既是DELETED和INSERTD。
CREATE TRIGGER t_EditProduct
ON [Product] For Update
as
if update(proName)
BEGIN
print '产品名称为基础数据,不能被修改!'
--回滚事务
ROLLBACK Transaction
END
else
BEGIN
print '修改成功!';
END
--执行失败
UPDATE Product set proName='IPhone 4' where pid = 1
--执行成功
UPDATE Product set proCount=10 where pid = 1
5、创建DDL触发器
语法格式
CREATE TRIGGER trigger_name
ON {ALL SERVER|DATABASE}
WITH ENCRYPTIION
FOR|AFTER|{event_type}
AS
sql_statement
CREATE trigger t_DontDeleteTables
ON Database
For Drop_table,Alter_table
AS
Begin
print '系统禁止删除或修改表!';
Rollback Transaction
End
DROP table [Order]
6、管理触发器
drop trigger trigger_name
--禁用触发器
disable trigger trigger_name
--启用触发器
enable trigger trigger_name
--示例
ALTER table [Order] add status int not null default 0
--禁用指定触发器
disable trigger t_DontDeleteTables
7、嵌套触发器(最多32层)
CREATE TABLE Department(
departmentId int not null identity(1,1) primary key,
departmentName nvarchar(20) not null,
departmentCount int not null default 0
)
CREATE TABLE Personnel(
personnelId int not null identity(1,1) primary key,
departmentId int not null,
personnelName nvarchar(10) not null
)
CREATE TABLE NewPersonnel
(
personnelId int not null identity(1,1) primary key,
departmentId int not null,
personnelName nvarchar(10) not null
)
insert into Department (departmentName) values ('总经办'),('财务部'),('行政人事部'),('信息技术部'),('市场研发部'),('售后客服部')
CREATE TRIGGER t_Delete
ON NewPersonnel
FOR DELETE
as
BEGIN
insert into Personnel select departmentId,personnelName from deleted
END
CREATE TRIGGER t_Insert
ON Personnel
FOR INSERT
as
BEGIN
declare @departmentId int
select @departmentId = departmentId from insertd
update department set departmentCount=(select count(1) from Personnel where departmentId=@departmentId) where departmentId=@departmentId
END
select * from department
insert into NewPersonnel(departmentId,personnelName) values (1,'王**'),(1,'毛*'),(1,'张**')
insert into NewPersonnel(departmentId,personnelName) values (2,'宋**'),(2,'高**'),(2,'殷**')
insert into NewPersonnel(departmentId,personnelName) values (3,'庄**'),(3,'施**'),(3,'胡*'),(3,'刘**')
insert into NewPersonnel(departmentId,personnelName) values (4,'张*'),(4,'宋**'),(4,'陈**')
DELETE [NewPersonnel] where departmentId = 4
8、递归触发器
任何触发器都可以包含影响同一个表或另一个表的UPDATE/INSERT或DELETE语句。如果启用递归触发器选项,那么改变表中数据的触发器,通过递归执行就可以再次触发自己。在数据库创建时,默认情况下递归触发器选项是禁用的,但可以使用ALTER DATABASE语句来启用它。
递归触发器具有复杂特性,可以用它来解决诸如自引用关系这样的复杂关系。使用递归触发器时,需要考虑以下的事项和原则:
1)递归触发器很复杂,必须经过有条理的设计和全面的测试。
2)在任意点的数据修改会触发一系列触发器。尽管提供处理复杂关系的能力,但是如果表要求以特定的顺序更新用户的表时,使用递归触发器就会产生问题
3)所有触发器一起构成一个大事务。任何触发器中的任何位置上的ROLLBACK命令都将取消所有数据输入。所有数据均为擦除,并且无任何数据被放到表中
4)触发器最多只能递归16层。换句话说,如果递归链中的第16个触发器激活了第17个触发器,则结果与发布ROLLBACK命令一样,所有数据将被擦除。