SQL Server编程(06)触发器


SQL Server 通过触发器用来保证业务逻辑和数据的完整性。在SQL Server中,触发器是一种特殊类型的存储过程,可在执行语言事件时自动触发。SQL Server中触发器包括三种:DML触发器、DDL触发器和登录触发器。

  • DML触发器:执行DML语句触发执行,例如操作数据表或视图的insert、update、delete语句,不包含select。
  • DDL触发器:执行DDL语句时触发执行,例如create table等语句。
  • 登录触发器:在用户登录SQL Server实例创建会话时触发。

SQL Server将触发器和触发它的语句放在一个可回滚事务中,如果触发器发生异常,则与该触发器相关的语句自动回滚。

DML的功能(优点):

  • 实现表的级联更改,实现与外键约束相似的功能(如果外键可以约束,则不推荐使用触发器)
  • 防止恶意或错误的insert、update、delete操作。触发器比check约束更加强大,触发器可以引用其它数据表,执行更加复杂的限制,而check约束不能引用其它表。
  • 可以获取到更改前和修改后的数据,根据差异采取措施,决定是commit,还是rollback
  • 一个表支持创建多个同类型的DML触发器

注意:有日志操作的行为才会激活触发器。例如truncate table删除表中所有数据,并没有执行日志操作,所以不会激活delete触发器。

创建触发器

DML触发器分为:

  • after触发器(之后触发)
    1. insert触发器
    2. update触发器
    3. delete触发器
  • instead of 触发器 (之前触发)

其中after触发器要求只有执行某一操作insert、update、delete之后触发器才被触发,且只能定义在表上。而instead of触发器表示并不执行其定义的操作(insert、update、delete)而仅是执行触发器本身。既可以在表上定义instead of触发器,也可以在视图上定义。

触发器有两个特殊的表:插入表(instered表)和删除表(deleted表)。这两张是逻辑表也是虚表。有系统在内存中创建者两张表,不会存储在数据库中。而且两张表的都是只读的,只能读取数据而不能修改数据。这两张表的结果总是与被改触发器应用的表的结构相同。当触发器完成工作后,这两张表就会被删除。Inserted表的数据是插入或是修改后的数据,而deleted表的数据是更新前的或是删除的数据。

 Inserted逻辑表Deleted逻辑表
增加记录(insert)存放增加的记录
删除记录(delete)存放被删除的记录
修改记录(update)存放更新后的记录存放更新前的记录

Update数据的时候就是先删除表记录,然后增加一条记录。这样在inserted和deleted表就都有update后的数据记录了。注意的是:触发器本身就是一个事务,所以在触发器里面可以对修改数据进行一些特殊的检查。如果不满足可以利用事务回滚,撤销操作。

创建触发器的语法:

create trigger tgr_name
on table_name
with encrypion 加密触发器for update...
asTransact-SQL

 

创建insert类型触发器

insert触发器,会在inserted表中添加一条刚插入的记录。

--创建insert插入类型触发器
if (object_id('tgr_classes_insert', 'tr') is not null)drop trigger tgr_classes_insert
go
create trigger tgr_classes_insert
on classesfor insert --插入触发
as--定义变量declare @id int, @name varchar(20), @temp int;--在inserted表中查询已经插入记录信息select @id = id, @name = name from inserted;set @name = @name + convert(varchar, @id);set @temp = @id / 2;    insert into student values(@name, 18 + @id, @temp, @id);print '添加学生成功!';
go
--插入数据
insert into classes values('5班', getDate());
--查询数据
select * from classes;
select * from student order by id;

 

创建delete类型触发器

delete触发器会在删除数据的时候,将刚才删除的数据保存在deleted表中。

--delete删除类型触发器
if (object_id('tgr_classes_delete', 'TR') is not null)drop trigger tgr_classes_delete
go
create trigger tgr_classes_delete
on classesfor delete --删除触发
asprint '备份数据中……';    if (object_id('classesBackup', 'U') is not null)--存在classesBackup,直接插入数据insert into classesBackup select name, createDate from deleted;else--不存在classesBackup创建再插入select * into classesBackup from deleted;print '备份数据成功!';
go
--
--不显示影响行数
--set nocount on;
delete classes where name = '5班';
--查询数据
select * from classes;
select * from classesBackup;

 

创建update类型触发器

update触发器会在更新数据后,将更新前的数据保存在deleted表中,更新后的数据保存在inserted表中。

--update更新类型触发器
if (object_id('tgr_classes_update', 'TR') is not null)drop trigger tgr_classes_update
go
create trigger tgr_classes_update
on classesfor update
asdeclare @oldName varchar(20), @newName varchar(20);--更新前的数据select @oldName = name from deleted;if (exists (select * from student where name like '%'+ @oldName + '%'))begin--更新后的数据select @newName = name from inserted;update student set name = replace(name, @oldName, @newName) where name like '%'+ @oldName + '%';print '级联修改数据成功!';endelseprint '无需修改student表!';
go
--查询数据
select * from student order by id;
select * from classes;
update classes set name = '五班' where name = '5班';

 

update更新列级触发器

更新列级触发器可以用update是否判断更新列记录;

if (object_id('tgr_classes_update_column', 'TR') is not null)drop trigger tgr_classes_update_column
go
create trigger tgr_classes_update_column
on classesfor update
as--列级触发器:是否更新了班级创建时间if (update(createDate))beginraisError('系统提示:班级创建时间不能修改!', 16, 11);rollback tran;end
go
--测试
select * from student order by id;
select * from classes;
update classes set createDate = getDate() where id = 3;
update classes set name = '四班' where id = 7;

instead of 类型触发器

instead of 触发器表示并不执行其定义的操作(insert、update、delete)而仅是执行触发器本身的内容。

语法:

create trigger tgr_name
on table_name
with encryptioninstead of update...
asT-SQL

创建instead of触发器

if (object_id('tgr_classes_inteadOf', 'TR') is not null)drop trigger tgr_classes_inteadOf
go
create trigger tgr_classes_inteadOf
on classesinstead of delete/*, update, insert*/
asdeclare @id int, @name varchar(20);--查询被删除的信息,病赋值select @id = id, @name = name from deleted;print 'id: ' + convert(varchar, @id) + ', name: ' + @name;--先删除student的信息delete student where cid = @id;--再删除classes的信息delete classes where id = @id;print '删除[ id: ' + convert(varchar, @id) + ', name: ' + @name + ' ] 的信息成功!';
go
--test
select * from student order by id;
select * from classes;
delete classes where id = 7;

显示错误信息(raiserror)

if (object_id('tgr_message', 'TR') is not null)drop trigger tgr_message
go
create trigger tgr_message
on studentafter insert, update
as raisError('tgr_message触发器被触发', 16, 10);
go
--test
insert into student values('lily', 22, 1, 7);
update student set sex = 0 where name = 'lucy';
select * from student order by id;

修改触发器

alter trigger tgr_message
on student
after delete
as raisError('tgr_message触发器被触发', 16, 10);
go
--test
delete from student where name = 'lucy';

 

启用、禁用触发器

--禁用触发器
disable trigger tgr_message on student;
--启用触发器
enable trigger tgr_message on student;

 

查询创建的触发器信息

--查询已存在的触发器
select * from sys.triggers;
select * from sys.objects where type = 'TR';--查看触发器触发事件
select te.* from sys.trigger_events te join sys.triggers t
on t.object_id = te.object_id
where t.parent_class = 0 and t.name = 'tgr_valid_data';--查看创建触发器语句
exec sp_helptext 'tgr_message';

 

示例,验证插入数据

if ((object_id('tgr_valid_data', 'TR') is not null))drop trigger tgr_valid_data
go
create trigger tgr_valid_data
on student
after insert
asdeclare @age int,@name varchar(20);select @name = s.name, @age = s.age from inserted s;if (@age < 18)beginraisError('插入新数据的age有问题', 16, 1);rollback tran;end
go
--test
insert into student values('forest', 2, 0, 7);
insert into student values('forest', 22, 0, 7);
select * from student order by id;

示例,操作日志

if (object_id('log', 'U') is not null)drop table log
go
create table log(id int identity(1, 1) primary key,action varchar(20),createDate datetime default getDate()
)
go
if (exists (select * from sys.objects where name = 'tgr_student_log'))drop trigger tgr_student_log
go
create trigger tgr_student_log
on student
after insert, update, delete
asif ((exists (select 1 from inserted)) and (exists (select 1 from deleted)))begininsert into log(action) values('updated');endelse if (exists (select 1 from inserted) and not exists (select 1 from deleted))begininsert into log(action) values('inserted');endelse if (not exists (select 1 from inserted) and exists (select 1 from deleted))begininsert into log(action) values('deleted');end
go
--test
insert into student values('king', 22, 1, 7);
update student set sex = 0 where name = 'king';
delete student where name = 'king';
select * from log;
select * from student order by id;本文转自齐师傅博客园博客,原文链接:http://www.cnblogs.com/youring2/p/4929149.html,如需转载请自行联系原作者

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/279164.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

网站运行java_定制化Azure站点Java运行环境(5)

Java 8下PermGen及参数设置在上一章节中&#xff0c;我们定制化使用了Java 8环境&#xff0c;使用我们的测试页面打印出了JVM基本参数&#xff0c;但如果我们自己观察&#xff0c;会发现在MXBeans中&#xff0c;没有出现PermGen的使用数据&#xff0c;初始大小等信息&#xff0…

三阶魔方魔方公式_观看此魔方的自我解决

三阶魔方魔方公式Finally: a Rubik’s cube that can solve itself. A maker named Human Controller built it in Japan, and you can see it in action right now. 最后&#xff1a;一个可以解决自身问题的魔方。 一家名为Human Controller的制造商在日本制造了它&#xff0…

pc样式在ie8中的bug

2019独角兽企业重金招聘Python工程师标准>>> pc样式在ie8中的bug 1,box-sizing:border-box: 在ie中,此属性的使用有限制: (在IE8中&#xff0c;min-width属性适用于content-box即使box-sizing设置为border-box。 Chrome select在使用时从元素中选择选项时遇到问…

下载: 虾米音乐_您所说的内容:如何组织凌乱的音乐收藏

下载: 虾米音乐Earlier this week we asked you to share your tips, tricks, and tools, for managing a messy music collection. Now we’re back to share so great reader tips; read on to find ways to tame your mountain of music. 本周早些时候&#xff0c;我们要求您…

Django form表单

Django form表单 目录 普通方式手写注册功能 views.pylogin.html使用form组件实现注册功能 views.pylogin2.html常用字段与插件 initialerror_messagespasswordradioSelect单选Select多选Select单选checkbox多选checkboxDjango Form所有内置字段校验补充进阶 应用Bootstrap样式…

java 多线程 优先级_java多线程之线程的优先级

在操作系统中&#xff0c;线程可以划分优先级&#xff0c;优先级较高的线程得到CPU资源较多&#xff0c;也就是CPU优先执行优先级较高的线程对象中的任务(其实并不是这样)。在java中&#xff0c;线程的优先级用setPriority()方法就行&#xff0c;线程的优先级分为1-10这10个等级…

PyQt5应用与实践

2015-01-16 19:00 by 吴秦, 69476 阅读, 5 评论, 收藏, 编辑 一个典型的GUI应用程序可以抽象为&#xff1a;主界面&#xff08;菜单栏、工具栏、状态栏、内容区域&#xff09;&#xff0c;二级界面&#xff08;模态、非模态&#xff09;&#xff0c;信息提示&#xff08;Toolti…

plex实现流媒体服务器_Plex继续远离服务器,提供网络节目

plex实现流媒体服务器() Plex now offers a “Web Shows” feature in certain versions of their interface, providing access to shows from brands like TWiT, GQ, and Popular Science. Plex现在在其界面的某些版本中提供了“网络节目”功能&#xff0c;可以访问TWiT&…

MIME协议(三) -- MIME邮件的组织结构

一封MIME邮件可以由多个不同类型的MIME消息组合而成&#xff0c;一个MIME消息表示邮件中的一个基本MIME资源或若干基本MIME消息的组合体。每个MIME消息的数据格式与RFC822数据格式相似&#xff0c;也包括头和体两部分&#xff0c;分别称为MIME消息头和MIME消息体&#xff0c;它…

discord linux_最好的Discord机器人来启动服务器

discord linuxDiscord has an extensive API and good support for bots on their platform. Because of this, there are tons of bots to go around. However, many of them just copy one another’s functionality. We’ve picked out the ones that do it right, and comp…

java获取前端json数据_java如何获取前端ajax传来的json对象

假设使用 jQuery 中的 ajax1. Json 对象前端代码示例$.ajax({url : http://localhost:8888/demo,type: post,data: {userName:15488779956}success: function(data) {// TODO}})后台代码示例RestControllerpublic class Demo {/*** 方法 1 使用 HttpServletRequest 接收* */Req…

版本控制介绍以及常用的版本控制工具

版本控制是指对软件开发过程中各种程序代码、配置文件及说明文档等文件变更的管理&#xff0c;是软件配置管理的核心思想之一。 编写一个成熟可用的程序是一个工作量很大的工程&#xff0c;并非我们一次性就可以搞定的工作&#xff0c;所以在开发过程当中需要&#xff1a; 1、 …

2019年4月第四周_2012年4月最佳怪胎文章

2019年4月第四周This past month we covered topics such as how to use a 64-bit web browser on Windows, the best tips and tweaks for getting the most out of Firefox, how to check out library books on your Kindle for free, and more. Join us as we look back at …

matlab循环遍历数组_Matlab - 访问for循环中最大值的索引,并使用它从数组中删除值...

我想递归地找到一系列矩阵中的最大值(第8列&#xff0c;具体)&#xff0c;然后使用该最大值的索引来设置数组中的所有值&#xff0c;索引最大为NaN的最大索引(对于列14:16) . 很容易找到最大值和索引&#xff0c;但是使用for循环为多个数组做这件事我很难过 .如果没有for循环&a…

【资料整理】编译安装nginx

【nginx】编译安装nginx 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311…

游荡的奶牛

沙雕题目 读错题了&#xff0c;不想多说 转载于:https://www.cnblogs.com/bullshit/p/9811058.html

物体成瘾性_科技成瘾使我们不那么快乐。 那是一个市场机会。

物体成瘾性Compulsively checking social networks makes us less happy. I think we all understand this intuitively, the same way we understand that working out more and eating better is a good idea. 强迫检查社交网络使我们不那么开心。 我认为我们所有人都可以凭直…

mysql 不要统计null_浅谈为什么Mysql数据库尽量避免NULL

在Mysql中很多表都包含可为NULL(空值)的列&#xff0c;即使应用程序并不需要保存NULL也是如此&#xff0c;这是因为可为NULL是列的默认属性。但我们常在一些Mysql性能优化的书或者一些博客中看到观点&#xff1a;在数据列中&#xff0c;尽量不要用NULL 值&#xff0c;使用0&…

Swing学习1——总体概述

以下来自于JDK1.6 一、Swing学习我划分为两个方面&#xff1a; 一方面Swing的界面设计部分&#xff0c;包括相关组件类的继承关系&#xff0c;组件的功能用途&#xff0c;布局管理&#xff1b; 1.首先继承关系上自上而下为 java.lang.Object java.awt.Component java.awt.Conta…

装饰设计模式和例题

文件复制程序&#xff1a; 将一个文件复制一份出来&#xff0c;实现方法很简单&#xff0c;使用FileInputStream读取文件内容&#xff0c;然后使用FileOutputStream写入另一个文件&#xff0c;利用read方法的返回值作为while循环的条件&#xff0c;进行一边读一边写。 代码示例…