欢迎莅临 SUN WU GANG 的园子!!!

世上无难事,只畏有心人。有心之人,即立志之坚午也,志坚则不畏事之不成。

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

主要内容参考:

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 表用于存储 INSERT 和 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--------------------------------------

  

 

posted on 2023-06-08 11:29  sunwugang  阅读(18)  评论(0编辑  收藏  举报