主要内容参考:
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.触发器编写时注意多行触发时的处理。(一般不建议使用游标)
脚本语法:
1 2 3 4 5 6 7 | create trigger trigger_TableName_Insert on TableName for insert -- 也可以写成 after insert as --TSQL list 。。。。。。 go |
1.Insert触发器示例: 修改时Create 修改为 alter
在向目标表中插入数据后,会触发该表的Insert 触发器,系统自动在内存中创建inserted表; 下面的demo中对Age加了判断,如果不满足判断数据会进行回滚,插入的数据操作会失败。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | --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 触发器——是删除 + 新增的操作
1 2 3 4 5 6 7 8 9 10 11 12 | --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 |
示例二:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | --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表存放的是删除的数据。
1 2 3 4 5 6 7 8 9 10 11 | --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 |
示例二:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | --创建学生表数据备份表 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:在触发器中,标识列没有生成,没有值,执行完成,插入的数据不能正常插入
应用场景:在执行操作之前,进行部分检查之类的操作,再执行插入或其他操作(需将对应操作写入触发器)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | ----------------------------------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-------------------------------------- |
完整脚本如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 | 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-------------------------------------- |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 记一次.NET内存居高不下排查解决与启示