主要内容参考:
https://blog.csdn.net/KingCruel/article/details/106292310
https://blog.csdn.net/qq_36330228/article/details/90582493
触发器:
触发器,可理解为一种特殊的存储过程。是一个特殊的事务(在执行过程中,可执行一些检查或设置条件,不满足时,可回滚操作)
存储过程,通过存储过程名称来调用执行;触发器,通过事件触发--自动调用执行;
触发器(trigger)是SQL server 提供给程序员和数据分析员来保证数据完整性的一种方法,它是与表事件相关的特殊的存储过程,
它的执行不是由程序调用,也不是手工启动,而是由事件来触发,比如当对一个表进行操作( insert,delete, update)时就会激活它执行。触发器经常用于加强数据的完整性约束和业务规则等。
触发器分类:
- DDL触发器:(数据定义语言,Data Definition Language) 例如,create\alter\drop
- DML触发器:(数据操作语言,Data Manipulation Language) 例如,insert\update\delete
- 操作完成后触发器:insert\update\delete
- insted of 触发器:只执行触发器本身,不执行其他定义的操作(insert\update\delete)
 
触发器语句中使用了两种特殊的表:deleted 表和 inserted 表
DML触发器执行时,系统内存会自动生成deleted表或inserted表,执行结束会自动消失。
SQL Server 有3类触发器【触发器是在对应表的下面】
Sql server中这三类触发器总是在执行操作语句后才被自动调用
- Insert触发器,使用到inserted表——Insert:向数据表插入数据时,调用insert触发器
- Update触发器,使用到deleted表和inserted表——Update:更新数据时调用update触发器
- Delete触发器,使用到deleted表——Delete:删除数据时执行Delete触发器
| inserted delated:插入表、删除表; 逻辑表也是虚表,系统在内存中创建,不会存储到数据库中,只读的,读取但不能修改数据; 结构和操作的表相同; 在触发器执行过程中存在,且可以访问,触发器工作完成之后,这两张表会自动删除; Deleted 表用于存储 DELETE 和 UPDATE 语句所影响的行的复本 | ||
| 对表的操作 | inserted表 | deleted表 | 
| insert | 存放插入的数据 | 无数据 | 
| update | 存放更新后的数据--新数据 | 存放更新前的数据--老数据 | 
| delete | 无数据 | 存放被删除的数据 | 
查询所有触发器:select * from sysobjects where xtype='TR'
执行已存在触发器:exec sp_helptext 'trrigername'
工作原理:
After(同for):先执行增、删、改、操作,再激活触发器操作。
Instead of:在执行增、删、改、操作之前,先激活触发器。

触发器优点:
  1.强化约束:强制复杂业务的规则和要求,能实现比check语句更为复杂的约束。
  2.跟踪变化:触发器可以侦测数据库内的操作,从而禁止数据库中未经许可的更新和变化。
  3.级联运行:侦测数据库内的操作时,可自动地级联影响整个数据库的各项内容。
  4.嵌套调用:触发器可以调用一个或多个存储过程。触发器最多可以嵌套32层。
触发器缺点:
    1. 可移植性差。
  2.占用服务器资源,给服务器造成压力。
  3.执行速度主要取决于数据库服务器的性能与触发器代码的复杂程度。
  4.嵌套调用一旦出现问题,排错困难,而且数据容易造成不一致,后期维护不方便。
触发器使用建议:
        1.尽量避免在触发器中执行耗时操作,因为触发器会与SQL语句认为在同一事务中,事务不结束,就无法释放锁。
        2.避免在触发器中做复杂操作,影响触发器性能的因素比较多(Eg:产品版本,所使用的架构等),要想编写高效的触发器考虑因素比较多,编写高性能触发器还是很难的。
        3.触发器编写时注意多行触发时的处理。(一般不建议使用游标)
脚本语法:
create trigger trigger_TableName_Insert on TableName for insert -- 也可以写成 after insert as --TSQL list 。。。。。。 go
1.Insert触发器示例: 修改时Create 修改为 alter
在向目标表中插入数据后,会触发该表的Insert 触发器,系统自动在内存中创建inserted表; 下面的demo中对Age加了判断,如果不满足判断数据会进行回滚,插入的数据操作会失败。
create database DBTEST
go
use DBTEST
go
--创建学生表
create table student(
    student_id int identity(1,1) primary key,
    student_name varchar(10),
    student_age int,
    student_sex varchar(2)
);
--插入学生数据
insert into student (student_name,student_age,student_sex)
values    ('张三',23,'男'),    ('李四',18,'女'),    ('王五',32,'男')
select * from student
create trigger trigger_student_Insert
on student
for insert -- 也可以写成 after insert
as
--TSQL list
declare @student_id int,@student_name varchar(50),@student_age varchar(50),@student_sex varchar(50)
select @student_id=student_id,@student_name=student_name,@student_age=student_age,@student_sex=student_sex from inserted
print convert(varchar,@student_id)+','+@student_name+','+@student_age+','+@student_sex +'新增数据成功!!!'
go
--insert 触发器 触发测试
insert into student (student_name,student_age,student_sex)values('坤坤',18,'男')

Insert 触发器示例: 修改时Create 修改为 alter
--Insert 触发器
Create TRIGGER [dbo].[Trigger_Insert]
   ON  [dbo].[Person]
   AFTER INSERT
AS 
BEGIN	
	SET NOCOUNT ON;
	Declare @age int;
	Select @age=Age  From inserted
	--如果年龄小于150正常插入,否则数据回滚
	IF(@age<150)
		Begin
			Insert into PersonLog(PersonID, Name, Age, AddDate)
			Select ID, Name, Age, AddDate From inserted
		End
	ELSE
		Begin
		    print('年龄应小于150')
			rollback transaction     --数据回滚
		END    
END
2.Update 触发器:deleted更改前——老数据;inserted修改后——新数据(Update 触发器,即 删除老数据,新增新数据)
在向目标表中更新数据后,会触发该表的Update 触发器,系统自动在内存中创建deleted表和inserted表,deleted表存放的是更新前的数据,inserted表存放的是更新的数据。
update 触发器——是删除 + 新增的操作
--Update 触发器
Create TRIGGER [dbo].[Trigger_Update]
   ON  [dbo].[Person]
   AFTER UPDATE
AS 
BEGIN	
	SET NOCOUNT ON;
	--这里是先删除后插入,存在一张临时表deleted
    Insert Into PersonLog(PersonID, Name, Age, AddDate, UpdateDate)
	Select ID, Name, Age, AddDate, UpdateDate From inserted
END
示例二:
--update 触发器
create trigger trigger_student_Update
on student
for Update -- 也可以写成 after Update
as
--TSQL list , 打印修改前、修改后的数据
declare @student_id int,@student_name varchar(50),@student_age varchar(50),@student_sex varchar(50)
--deleted表用于存放,修改前数据
select @student_id=student_id,@student_name=student_name,@student_age=student_age,@student_sex=student_sex from deleted
print '修改前数据:'+ convert(varchar,@student_id)+','+@student_name+','+@student_age+','+@student_sex
--inserted表用于存放,修改后数据
select @student_id=student_id,@student_name=student_name,@student_age=student_age,@student_sex=student_sex from inserted
print '修改后数据:'+ convert(varchar,@student_id)+','+@student_name+','+@student_age+','+@student_sex 
--其他操作
insert into student (student_name,student_age,student_sex)values('kunkun',18,'男')
go
--update 触发器,触发测试
update student set student_name='王麻子' where student_name='王五'

 
注:在实际工作中,在使用触发器时,在更改数据时,可将原始数据和新数据备份至不同的表,以备不时之需
inserted和deleted表中的数据是只读,不可操作
3.delete触发器
在向目标表中删除数据后,会触发该表的Delete 触发器,系统自动在内存中创建deleted表,deleted表存放的是删除的数据。
--Delete 触发器
Create TRIGGER [dbo].[Trigger_Delete]
   ON  [dbo].[Person]
   AFTER DELETE
AS 
BEGIN
	SET NOCOUNT ON;
    Insert Into PersonLog(PersonID, Name, Age, AddDate, UpdateDate, DeleteDate)
	Select ID, Name, Age, AddDate, UpdateDate, GETDATE() From deleted
END
示例二:
--创建学生表数据备份表
if(OBJECT_ID('studentbak','U')is null) --is not null
create table studentbak
(
		student_id int identity(1,1) primary key,
		student_name varchar(10),
		student_age int,
		student_sex varchar(2)
);
----------------------------------003delete 触发器 start----------------------------------
create trigger trigger_student_Delete
on student
for delete -- 也可以写成 after delete
as
--TSQL list , 打印修改前、修改后的数据
declare @student_id int,@student_name varchar(50),@student_age varchar(50),@student_sex varchar(50)
--deleted表存放修改前的老数据
select @student_id=student_id,@student_name=student_name,@student_age=student_age,@student_sex=student_sex from deleted
print '删除的数据为:'+ convert(varchar,@student_id)+','+@student_name+','+@student_age+','+@student_sex
--其他操作
insert into student (student_name,student_age,student_sex)values('yangyang',18,'女')
--可备份至其他备份表中(目标表存在)
insert into studentbak(student_name,student_age,student_sex)values(@student_name,@student_age,@student_sex)
--目标表不存在
--select * from into studentbak from deleted
go
--delete 触发器,触发测试
delete from student where student_name='王麻子'
go


4.instead of insert
- 不执行定义操作,执行的是触发器本身的操作
- 发生在插入操作之前
--after insert:在触发器中,标识列已经自动生成,有值
--instead of insert:在触发器中,标识列没有生成,没有值,执行完成,插入的数据不能正常插入
应用场景:在执行操作之前,进行部分检查之类的操作,再执行插入或其他操作(需将对应操作写入触发器)
----------------------------------004 instead of insert触发器 start------------------------------------
create trigger trigger_student_InsteadOfInsert
on student
instead of insert
as
declare @student_id int,@student_name varchar(50),@student_age varchar(50),@student_sex varchar(50)
select @student_id=student_id,@student_name=student_name,@student_age=student_age,@student_sex=student_sex from inserted
print '要添加的数据:'+ convert(varchar,@student_id)+','+@student_name+','+@student_age+','+@student_sex
go
--instead of insert 触发触发器,发生在插入操作之前
insert into student (student_name,student_age,student_sex)values('坤坤2',18,'男')
select * from student
--after insert:在触发器中,标识列已经自动生成,有值
--instead of insert:在触发器中,标识列没有生成,没有值,执行完成,插入的数据不能正常插入
----------------------------------004 instead of insert触发器 end--------------------------------------
完整脚本如下所示:
create database DBTEST
go
use DBTEST
go
--创建学生表
create table student(
    student_id int identity(1,1) primary key,
    student_name varchar(10),
    student_age int,
    student_sex varchar(2)
);
--插入学生数据
insert into student (student_name,student_age,student_sex)
values    ('张三',23,'男'),    ('李四',18,'女'),    ('王五',32,'男')
select * from student
----------------------------------001insert 触发器 start----------------------------------
create trigger trigger_student_Insert
on student
for insert -- 也可以写成 after insert
as
--TSQL list
declare @student_id int,@student_name varchar(50),@student_age varchar(50),@student_sex varchar(50)
select @student_id=student_id,@student_name=student_name,@student_age=student_age,@student_sex=student_sex from inserted
print convert(varchar,@student_id)+','+@student_name+','+@student_age+','+@student_sex +'新增数据成功!!!'
go
--insert 触发触发器
insert into student (student_name,student_age,student_sex)values('坤坤',18,'男')
select * from student
----------------------------------001insert 触发器 end------------------------------------
----------------------------------002update 触发器 start----------------------------------
--update 触发器 (deleted\inserted)
--deleted表存放修改前的老数据 + inserted表存放修改后的新数据
create trigger trigger_student_Update
on student
for Update -- 也可以写成 after Update
as
--TSQL list , 打印修改前、修改后的数据
declare @student_id int,@student_name varchar(50),@student_age varchar(50),@student_sex varchar(50)
--deleted表存放修改前的老数据
select @student_id=student_id,@student_name=student_name,@student_age=student_age,@student_sex=student_sex from deleted
print '修改前数据:'+ convert(varchar,@student_id)+','+@student_name+','+@student_age+','+@student_sex
--inserted表存放修改后的新数据
select @student_id=student_id,@student_name=student_name,@student_age=student_age,@student_sex=student_sex from inserted
print '修改后数据:'+ convert(varchar,@student_id)+','+@student_name+','+@student_age+','+@student_sex 
--其他操作
insert into student (student_name,student_age,student_sex)values('kunkun',18,'男')
go
--update 触发器,触发测试
update student set student_name='王麻子' where student_name='王五'
select * from student
----------------------------------002update 触发器 end------------------------------------
go
--创建学生表数据备份表
if(OBJECT_ID('studentbak','U')is null) --is not null
create table studentbak
(
		student_id int identity(1,1) primary key,
		student_name varchar(10),
		student_age int,
		student_sex varchar(2)
);
----------------------------------003delete 触发器 start----------------------------------
create trigger trigger_student_Delete
on student
for delete -- 也可以写成 after delete
as
--TSQL list , 打印修改前、修改后的数据
declare @student_id int,@student_name varchar(50),@student_age varchar(50),@student_sex varchar(50)
--deleted表存放修改前的老数据
select @student_id=student_id,@student_name=student_name,@student_age=student_age,@student_sex=student_sex from deleted
print '删除的数据为:'+ convert(varchar,@student_id)+','+@student_name+','+@student_age+','+@student_sex
--其他操作
insert into student (student_name,student_age,student_sex)values('yangyang',18,'女')
--可备份至其他备份表中(目标表存在)
insert into studentbak(student_name,student_age,student_sex)values(@student_name,@student_age,@student_sex)
--目标表不存在
--select * from into studentbak from deleted  存在标识列,不可使用 * 
--select student_name,student_age,student_sex from deleted
go
--delete 触发器,触发测试
delete from student where student_name='王麻子'
go
select * from student
select * from studentbak
----------------------------------003delete 触发器 end------------------------------------
----------------------------------004 instead of insert触发器 start------------------------------------
create trigger trigger_student_InsteadOfInsert
on student
instead of insert
as
declare @student_id int,@student_name varchar(50),@student_age varchar(50),@student_sex varchar(50)
select @student_id=student_id,@student_name=student_name,@student_age=student_age,@student_sex=student_sex from inserted
print '要添加的数据:'+ convert(varchar,@student_id)+','+@student_name+','+@student_age+','+@student_sex
go
--instead of insert 触发触发器,发生在插入操作之前
insert into student (student_name,student_age,student_sex)values('坤坤2',18,'男')
select * from student
--after insert:在触发器中,标识列已经自动生成,有值
--instead of insert:在触发器中,标识列没有生成,没有值,执行完成,插入的数据不能正常插入
----------------------------------004 instead of insert触发器 end--------------------------------------
 
                    
                     
                    
                 
                    
                 

 
         
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号