SQL Server 触发器

原文:SQL Server 触发器

触发器

概述

   触发器为特殊类型的存储过程,可在执行语言事件时自动生效。SQL Server 包括三种常规类型的触发器:DML 触发器、DDL 触发器和登录触发器。

当服务器或数据库中发生数据定义语言 (DDL) 事件时将调用 DDL 触发器。登录触发器将为响应 LOGON 事件而激发存储过程。与 SQL Server 实例建立用户会话时将引发此事件。

当数据库中发生数据操作语言 (DML) 事件时将调用 DML 触发器。DML 事件包括在指定表或视图中修改数据的 INSERT 语句、UPDATE 语句或 DELETE 语句。DML 触发器可以查询其他表,还可以包含复杂的 Transact-SQL 语句。将触发器和触发它的语句作为可在触发器内回滚的单个事务对待。如果检测到错误(例如,磁盘空间不足),则整个事务即自动回滚。

 

步骤

   本文主要讲述DML触发器,DML触发器有两种:AFTER,INSTEAD OF触发器,同时DML 触发器使用 deleted 和 inserted 逻辑(概念)表。 它们在结构上类似于定义了触发器的表,即对其尝试执行了用户操作的表。 在 deleted 和 inserted 表保存了可能会被用户更改的行的旧值或新值。

  • 对于INSERT 操作,inserted保留新增的记录,deleted无记录
  • 对于DELETE 操作,inserted无记录,deleted保留被删除的记录
  • 对于UPDATE操作,inserted保留修改后的记录,deleted保留修改前的记录

    一.语法

CREATE TRIGGER [ schema_name . ]trigger_name 
ON { table | view } [ WITH <dml_trigger_option> [ ,...n ] ] 
{ FOR | AFTER | INSTEAD OF } 
{ [ INSERT ] [ , ] [ UPDATE ] [ , ] [ DELETE ] } AS { sql_statement  [ ; ] [ ,...n ] [ ; ] > }

 

     二.创建表

CREATE TABLE Class
(Cno INT PRIMARY KEY,
Cname nvarchar(20) not null)
go
CREATE TABLE Student
(SNO INT PRIMARY KEY IDENTITY(1,1),
Sname CHAR(10) not null,
Age int not null,
Sex char(2) not null,
Cno int NOT NULL
)
ALTER TABLE Student ADD CONSTRAINT FK_SNO_Cno FOREIGN KEY (Cno) REFERENCES Class(Cno)
go

AFTER触发器

AFTER 指定 DML 触发器仅在触发 SQL 语句中指定的所有操作都已成功执行时才被触发。 所有的引用级联操作和约束检查也必须在激发此触发器之前成功完成。

如果仅指定 FOR 关键字,则 AFTER 为默认值。

不能对视图定义 AFTER 触发器

  • insert触发

当向Class表中插入一条数据时,获取插入的cno,同时向Student表中插入一条数据

 
IF OBJECT_ID('TR_Class_insert','TR') IS NOT NULL
DROP TRIGGER TR_Class_insert
G0
CREATE
TRIGGER TR_Class_insert on Class AFTER INSERT AS BEGINDECLARE @Cno INTSELECT @Cno=Cno FROM inserted----获取插入的数据CNOINSERT INTO Student(Sname,Age,Sex,Cno)VALUES('李明',20,'',@Cno) END go INSERT INTO Class SELECT 101,'一班'SELECT * FROM Class SELECT * FROM Student
  • UPDATE触发

获取修改的Age值,如果Age为负数则执行回滚操作,否则输出修改前后的Age值

IF OBJECT_ID('TR_Student_update','TR') IS NOT NULL
DROP TRIGGER TR_Student_update
GO
CREATE TRIGGER TR_Student_update on Student
AFTER UPDATE
AS
BEGINDECLARE @Age_old int,@Age_new intSELECT @Age_old=Age from deleted ----获取修改前的SELECT @Age_new=Age FROM inserted----获取更改后的数据if @Age_new<0beginprint '年龄不能为负数'rollback;endelse BEGINprint @Age_oldprint @Age_newEND
ENDgo
update Student
set Age=-20
where SNO=1SELECT * FROM Class
SELECT * FROM Studentupdate Student
set Age=25
where SNO=1SELECT * FROM Class
SELECT * FROM Student
  •  delete触发

获取被删除的数据,返回错误提示,该步骤正好验证了“所有的引用级联操作和约束检查也必须在激发此触发器之前成功完成”,该步骤不会返回制定的错误提示,因为被删除的数据作用于外键约束,所以先于触发器操作执行外键约束,返回约束错误提示,并执行回滚.

IF OBJECT_ID('TR_Class_delete','TR') IS NOT NULL
DROP TRIGGER TR_Class_delete
GO
CREATE TRIGGER TR_Class_delete on Class
AFTER DELETE
AS
BEGINDECLARE @Cno intSELECT @Cno=Cno from DELETED---获取被删除的记录IF @Cno>0beginRAISERROR ('数据不能被删除,被用于外键约束', 16, 10);rollback----执行回滚操作endENDSELECT * FROM Class
SELECT * FROM StudentDELETE FROM Class
where CNO=101SELECT * FROM Class
SELECT * FROM Student

对Student表建立外键约束,用于级联操作 ON DELETE,对于表的级联删除更新操作这里就不讲述了
删除之前创建的外键约束,并创建具有级联更新删除操作的外键约束
alter table student
drop constraint FK_SNO_CnoALTER TABLE Student
ADD CONSTRAINT FK_SNO_Cno FOREIGN KEY (Cno) REFERENCES Class (Cno)
ON DELETE CASCADE ON UPDATE CASCADE

再执行删除语句,返回制定错误提示“数据不能被删除,被用于外键约束”并执行回滚操作

DELETE FROM Class
where CNO=101SELECT * FROM Class
SELECT * FROM Student

 

INSTEAD OF触发器

指定执行 DML 触发器而不是触发 SQL 语句,因此,其优先级高于触发语句的操作。 不能为 DDL 或登录触发器指定 INSTEAD OF。

对于表或视图,每个 INSERT、UPDATE 或 DELETE 语句最多可定义一个 INSTEAD OF 触发器。 但是,可以为具有自己的 INSTEAD OF 触发器的多个视图定义视图。

INSTEAD OF 触发器不可以用于使用 WITH CHECK OPTION 的可更新视图。 如果将 INSTEAD OF 触发器添加到指定了 WITH CHECK OPTION 的可更新视图中,则 SQL Server 将引发错误。 用户须用 ALTER VIEW 删除该选项后才能定义 INSTEAD OF 触发器

对于 INSTEAD OF 触发器,不允许对具有指定级联操作 ON DELETE 的引用关系的表使用 DELETE 选项。 同样,也不允许对具有指定级联操作 ON UPDATE 的引用关系的表使用 UPDATE 选项

  •  Insert 触发
-------insert 触发
----删除已有的instead of触发器
declare @name nvarchar(100)
select @name=name from sys.triggers where  object_name(parent_id)='student' and is_instead_of_trigger=1
set @name='drop trigger '+@name
exec (@name)IF OBJECT_ID('TR_Student_instead_insert','TR') IS NOT NULL
DROP TRIGGER TR_Student_instead_insert
GO
CREATE TRIGGER TR_Student_instead_insert on Student
INSTEAD OF insert
AS
BEGINSELECT * into T_back from inserted ----获取即将插入的数据ENDselect * from Student
select * from ClassINSERT INTO Student(Sname,Age,Sex,Cno)
values('张三',23,'',102)select * from T_back

 

  •  delete触发

创建触发器失败,因为之前创建外键约束时添加了on delete cascade

IF OBJECT_ID('TR_Student_instead_delete','TR') IS NOT NULL
DROP TRIGGER TR_Student_instead_delete
GO
CREATE TRIGGER TR_Student_instead_delete on Student
INSTEAD OF DELETE
AS
BEGINDECLARE @Cno intSELECT @Cno=Cno from DELETED---获取被删除的记录IF EXISTS (SELECT * FROM Class where Cno=@cno) beginrollback----执行回滚操作RAISERROR ('数据不能被删除,被用于外键约束1', 16, 10);endEND消息 2113,级别 16,状态 1,过程 TR_Student_instead_delete,第 10 行
因为表 'Student'FOREIGN KEY 使用级联 DELETEUPDATE,所以无法对该表 创建 INSTEAD OF DELETE 或 INSTEAD OF UPDATE TRIGGER 'TR_Student_instead_delete'

重建外键约束,删除级联
alter table student
drop constraint FK_SNO_CnoALTER TABLE Student
ADD CONSTRAINT FK_SNO_Cno FOREIGN KEY (Cno) REFERENCES Class (Cno)

 

  •  UPDATE触发
-----同一张表中只能定义一个instead of 触发器,删除表之前创建的instead of 触发declare @name nvarchar(100)
select @name=name from sys.triggers where  object_name(parent_id)='student' and is_instead_of_trigger=1
set @name='drop trigger '+@name
exec (@name)IF OBJECT_ID('TR_Student_instead_update','TR') IS NOT NULL
DROP TRIGGER TR_Student_instead_update
GO
CREATE TRIGGER TR_Student_instead_update on Student
INSTEAD OF update
AS
BEGINDECLARE @Age_del int ,@Age_up intSELECT @Age_del=Age from DELETED---获取被更改的记录SELECT @Age_up=Age from Insertedbeginprint @Age_delprint @Age_upselect * from Student ----查询数据是否被更改endEND----查询更新前的表数据
select * from student SNO    Sname    Age    Sex    Cno
13    李明          22101update Student
set age=-2
where CNO=101

----对于前面定义的after触发器age不能为负数也不会执行,instead of 触发器高于执行语句,高于after 触发
SNO Sname Age Sex Cno
13 李明 22101select * from student SNO Sname Age Sex Cno 13 李明 22101(1 行受影响) 22 -2(1 行受影响)(1 行受影响)当表上面定义了instead of 触发器,指定执行 DML 触发器而不是触发 SQL 语句,因此,其优先级高于触发语句的操作,而且也不会执行表上面定义的after触发器

 

 创建带字段判断的触发器,根据对特定列的 UPDATE 或 INSERT 修改来执行某些操作

------创建字段更新判断的update触发器
ALTER TABLE Class
ADD Address nvarchar(50)IF OBJECT_ID('TR_Class_Update','TR') IS NOT NULL
DROP TRIGGER TR_Class_Update
GO
CREATE TRIGGER TR_Class_Update on Class
AFTER UPDATE
AS
BEGINIF UPDATE(Cname) or UPDATE(Address)BEGINRAISERROR ('数据不能被修改', 16, 10)ROLLBACKEND
ENDSELECT * FROM ClassUPDATE Class
set Address='5栋101'
where Cno=101SELECT * FROM Class

 

总结

   虽然触发器功能强大,轻松可靠地实现许多复杂的功能,同时过多触发器会造成数据库及应用程序的维护困难,同时对触发器过分的依赖,势必影响数据库的结构,同时增加了维护的复杂程序.

 

备注:

    作者:沉寂的石头

    博客:http://www.cnblogs.com/chenmh

欢迎大家转载,但转载时必须注明文章来源,且在文章开头明显处给明链接,否则保留追究责任的权利。

欢迎大家拍砖

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

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

相关文章

LeetCode之Detect Capital

1、题目 Given a word, you need to judge whether the usage of capitals in it is right or not. We define the usage of capitals in a word to be right when one of the following cases holds: All letters in this word are capitals, like "USA".All lett…

你一写长文章就焦虑拖延?

这是病&#xff0c;得治。 症状 每年春季学期&#xff0c;总会有一些人很烦躁。 别人晒朋友圈&#xff0c;他留言说不中听的话&#xff1b;你见他突然妄自菲薄&#xff0c;开导劝慰他&#xff0c;却被辩驳甚至骂一通&#xff1b;一点儿小事儿&#xff0c;都能激起他胸中的愤怒&…

mysql通过data目录恢复数据库

mysql通过data目录恢复数据库 阅读&#xff1a;1236次 时间&#xff1a;2010-03-24 06:53:30 字体&#xff1a;[大 中 小]重装系统后&#xff0c;MySQL服务没有了&#xff0c;但是数据库的文件还在&#xff0c;这个时候我想恢复以前的数据库&#xff0c; 起码要把数据导出来…

5.7.21mysql数据库_【数据库】mysql5.7.21 winx64安装配置图文分享

本文主要为大家详细介绍了mysql 5.7.21 winx64安装配置方法图文教程&#xff0c;具有一定的参考价值&#xff0c;感兴趣的小伙伴们可以参考一下&#xff0c;希望能帮助到大家。1、将下载好的mysql压缩包解压到安装目录下2、新建文件my.ini&#xff0c;放置到mysql安装目录下&am…

.NET7的七项重大改进!

.NET 7 Preview1发布了&#xff0c;没时间实操&#xff1f;先快来看看.NET7的七项重大改进&#xff01;1、不再支持.NET 7应用程序、运行时和SDK的多级查找&#xff08;MLL&#xff09;2、PATH停止向.NET 7运行时和SDK添加32位.NET3、默认情况下&#xff0c; dotnet build/publ…

LeetCode之Sum of Two Integers

1、题目 Calculate the sum of two integers a and b, but you are not allowed to use the operator and -. Example: Given a 1 and b 2, return 3. Credits: Special thanks to fujiaozhu for adding this problem and creating all test cases. Subscribe to see wh…

关于新加坡IT薪酬

很多朋友发邮件或留言问我关于新加坡IT薪酬的问题&#xff0c;由于前段时间比较忙&#xff0c;所以没有及时一一回复&#xff0c;在此表示抱歉。 新加坡IT薪酬范围大概如下&#xff08;月薪,新加坡币对人民币为1:5&#xff09;: Junior Developer/Programmer/Engineer/Consulta…

Spring Boot 入门小目标 3 --- 先来试着热部署

2019独角兽企业重金招聘Python工程师标准>>> Spring Boot 入门小目标---先来试着热部署 这次写的主要就是 使用 springloaded 来实现 热部署。 很多时候&#xff0c;我们在修改和添加了新的方法或代码&#xff0c;都需要重启服务器。这样很麻烦&#xff0c;而且 不合…

三:Java之Applet

首先我要说的是Applet是一种应用程序&#xff0c;它是一种由JAVA编写的小应用程序&#xff0c;通常这样的应用程序都像他的名字一样&#xff0c;是一个非常小的程序&#xff0c;或许有些朋友就会问了&#xff0c;那么它是用来干什么的呢&#xff1f;JAVA程序就是JAVA程序啊&…

基于事件驱动架构构建微服务第19部分:使用 SignalR 和 Azure Active Directory 构建和保护实时通信...

原文链接&#xff1a;https://logcorner.com/building-micro-services-through-event-driven-architecture-part19-building-and-securing-real-time-communications-using-signalr-and-azure-active-directory/命令 HTTP API 将事件存储到事件存储&#xff0c;但不直接将它们发…

LeetCode之Maximum Depth of Binary Tree

1、题目 Given a binary tree, find its maximum depth. The maximum depth is the number of nodes along the longest path from the root node down to the farthest leaf node. Subscribe to see which companies asked this question. 2、代码实现 /*** Definition for a…

java 多线程之间通信_JAVA多线程之线程间的通信方式解析

JAVA多线程之线程间的通信方式解析一&#xff0c;介绍本总结我对于JAVA多线程中线程之间的通信方式的理解&#xff0c;主要以代码结合文字的方式来讨论线程间的通信&#xff0c;故摘抄了书中的一些示例代码。二&#xff0c;线程间的.通信方式①同步这里讲的同步是指多个线程通过…

Orchard之生成新模板

一&#xff1a;启用 Code Generation 进入后台&#xff0c; Modules –> Developer Enable 之。 二&#xff1a;生成模版 首先&#xff0c;进入 Orchard 命令行 在 CMD 下到达解决方案的 Web 的 Bin 目录下&#xff0c;打开 Orchard 命令&#xff0c;输入&#xff1a; code…

Java设计模式-状态模式(State)

核心思想就是&#xff1a;当对象的状态改变时&#xff0c;同时改变其行为&#xff0c;很好理解&#xff01;就拿QQ来说&#xff0c;有几种状态&#xff0c;在线、隐身、忙碌等&#xff0c;每个状态对应不同的操作&#xff0c;而且你的好友也能看到你的状态&#xff0c;所以&…

cookies,sessionStorage 和 localStorage 的区别?

cookie是网站为了标示用户身份而储存在用户本地终端&#xff08;Client Side&#xff09;上的数据&#xff08;通常经过加密&#xff09;。cookie数据始终在同源的http请求中携带&#xff08;即使不需要&#xff09;&#xff0c;记会在浏览器和服务器间来回传递。sessionStorag…

基于Prometheus的.NET 4.x应用服务监控

【.NET监控】| 总结/Edison Zhou0Why 监控&#xff1f;Edison所在团队95%以上的应用都是基于.NET 4.5开发的&#xff0c;只能跑在Windows Server服务器上的IIS中&#xff0c;公司运维也没有意愿对Windows Server进行有效的管理和提供监控支持&#xff0c;整得我们无法及时查看有…

php+对象+toarray_PHP 对象、数组间的转换

PHP 对象、数组间的转换/*** PHP 对象、数组间的转换** author flyer0126* since 2012/05/03**/// 1. 利用(array)和(object)&#xff0c;简单处理$objTemp (object)array();$objTemp->a 1;$objTemp->b 2;$objTemp->c 3;$arrTemp (array)$objTemp;print_r($objTe…

LeetCode之Happy Number

1、题目 Write an algorithm to determine if a number is "happy". A happy number is a number defined by the following process: Starting with any positive integer, replace the number by the sum of the squares of its digits, and repeat the process u…

高效沟通的7C原则

2019独角兽企业重金招聘Python工程师标准>>> 怎样确保沟通的顺畅和高效性呢&#xff1f;成功人士已经总结了很多方法&#xff0c;七项基本原则是一种基本的方法&#xff0c;起到了检查列表的作用&#xff0c;在你发送信息之前&#xff0c;对照检查可以帮助你确认信息…

ps切片导出时将切片选项选择为“所有用户切片”

ps切片导出时将切片选项选择为“所有用户切片”&#xff0c;可导出所有切中的区域。转载于:https://www.cnblogs.com/npk19195global/p/4513707.html