触发器简介:

触发器是一种特殊的存储过程,它的执行不是由程序调用,也不是手动执行,而是由事件来触发。触发器是当对某一个表进行操作。例如:update、insert、delete这些操作的时候,系统会自动调用执行该表上对应的触发器。

触发器分类:

1、DML( 数据操纵语言 Data Manipulation Language)触发器:是指触发器在数据库中发生 DML 事件时将启用。DML事件是指在表或视图中对数据进行的 insert、update、delete 操作的语句。

2、DDL(数据定义语言 Data Definition Language)触发器:是指当服务器或数据库中发生 DDL 事件时将启用。DDL事件是指在表或索引中的 create、alter、drop 操作语句。

3、登陆触发器:是指当用户登录 SQL SERVER 实例建立会话时触发。如果身份验证失败,登录触发器不会触发。

其中 DML 触发器比较常用,根据 DML 触发器触发的方式不同又分为以下两种情况:

after 触发器(之后触发):其中 after 触发器要求只有执行 insert、update、delete 某一操作之后触发器才会被触发,且只能定义在表上。

instead of 触发器 (之前触发):instead of 触发器并不执行其定义的操作(insert、update、delete)而仅是执行触发器本身。可以在表或视图上定义 instead of 触发器。

DML 触发器有两个特殊的表:插入表(instered)和删除表(deleted),这两张表是逻辑表。这两个表是建立在数据库服务器的内存中,而且两张表的都是只读的。这两张表的结构和触发器所在的数据表的结构是一样的。当触发器完成工作后,这两张表就会被删除。Inserted 表的数据是插入或是修改后的数据,而 deleted 表的数据是更新前的或是已删除的数据。

AFTER 触发器语法:

 1 CREATE [ OR ALTER ] TRIGGER [ schema_name . ]trigger_name
2 ON { table }
3 [ WITH <dml_trigger_option> [ ,...n ] ]
4 { FOR | AFTER }
5 { [ INSERT ] [ , ] [ UPDATE ] [ , ] [ DELETE ] }
6 AS { sql_statement [ ; ] [ ,...n ] }
7
8 <dml_trigger_option> ::=
9 [ NATIVE_COMPILATION ]
10 [ SCHEMABINDING ]
11 [ EXECUTE AS Clause ]

INSTEAD OF 触发器语法:

 1 CREATE [ OR ALTER ] TRIGGER [ schema_name . ]trigger_name
2 ON { table | view }
3 [ WITH <dml_trigger_option> [ ,...n ] ]
4 { FOR | AFTER | INSTEAD OF }
5 { [ INSERT ] [ , ] [ UPDATE ] [ , ] [ DELETE ] }
6 [ WITH APPEND ]
7 [ NOT FOR REPLICATION ]
8 AS { sql_statement [ ; ] [ ,...n ] | EXTERNAL NAME <method specifier [ ; ] > }
9
10 <dml_trigger_option> ::=
11 [ ENCRYPTION ]
12 [ EXECUTE AS Clause ]
13
14 <method_specifier> ::=
15 assembly_name.class_name.method_name

DDL 触发器语法:

1 CREATE [ OR ALTER ] TRIGGER trigger_name
2 ON { ALL SERVER | DATABASE }
3 [ WITH <ddl_trigger_option> [ ,...n ] ]
4 { FOR | AFTER } { event_type | event_group } [ ,...n ]
5 AS { sql_statement [ ; ] [ ,...n ] | EXTERNAL NAME < method specifier > [ ; ] }
6
7 <ddl_trigger_option> ::=
8 [ ENCRYPTION ]
9 [ EXECUTE AS Clause ]

登陆触发器语法:

1 CREATE [ OR ALTER ] TRIGGER trigger_name
2 ON ALL SERVER
3 [ WITH <logon_trigger_option> [ ,...n ] ]
4 { FOR| AFTER } LOGON
5 AS { sql_statement [ ; ] [ ,...n ] | EXTERNAL NAME < method specifier > [ ; ] }
6
7 <logon_trigger_option> ::=
8 [ ENCRYPTION ]
9 [ EXECUTE AS Clause ]

参数:

CREATE OR ALTER:

创建或者有条件的修改触发器(即要修改的触发器必须已经存在)。

schema_name:
DML触发器所属的模式的名称(即所有者,例如:dbo)。

trigger_name:
是触发器的名称。

table | view:

是执行 DML 触发器的表或视图,有时称为触发器表或触发器视图。指定表格或视图的完全限定名称是可选的。视图只能由 INSTEAD OF 触发器引用。

DATABASE:
将 DDL 触发器的范围应用于当前数据库。如果指定,触发器会在当前数据库中发生 event_type 或 event_group 时触发。

ALL SERVER:

将 DDL 或登录触发器的作用域应用于当前服务器。如果指定,触发器会在当前服务器的任何地方发生 event_type 或 event_group 时触发。

WITH ENCRYPTION:

加密 CREATE TRIGGER 语句的文本。使用 WITH ENCRYPTION 可以防止触发器作为 SQL Server 复制的一部分进行发布。无法为 CLR 触发器指定 WITH ENCRYPTION。

EXECUTE AS:
指定执行触发器的安全上下文。以便能够控制 SQL Server 实例用于验证触发器引用的任何数据库对象的权限的用户帐户。

NATIVE_COMPILATION:
表示触发器是本地编译的。

SCHEMABINDING:
指定触发器引用的表不能被删除或更改。

FOR | AFTER:
AFTER 指定仅在触发 SQL 语句中指定的所有操作成功执行时触发 DML 触发器。所有引用级联操作和约束检查在此触发器触发之前也必须成功。当 FOR 是指定的唯一关键字时,AFTER 是默认值。视图无法定义AFTER触发器。

INSTEAD OF:
指定执行 DML 触发器而不是触发 SQL 语句,因此覆盖触发语句的操作。无法为 DDL 或登录触发器指定 INSTEAD OF。

对于 INSTEAD OF 触发器,在具有指定级联动作 ON DELETE 的引用关系的表上不允许使用 DELETE 选项。类似地,在具有指定级联动作 ON UPDATE 的引用关系的表上,不允许 UPDATE 选项。

{[DELETE] [,] [INSERT] [,] [UPDATE]} :
指定在针对此表或视图进行尝试时激活 DML 触发器的数据修改语句。必须至少指定一个选项。在触发器定义中允许以任何顺序对这些选项进行任意组合。

event_type:
是执行后导致 DDL 触发器触发的 Transact-SQL 语言事件的名称。

event_group:
是 Transact-SQL 语言事件的预定义分组的名称。属于任何 Transact-SQL 语言事件执行后的 DDL 触发器触发 event_group。

sql_statement:
是触发条件和动作。触发条件指定附加条件,以确定尝试的 DML,DDL 或登录事件是否导致执行触发器操作。

<method_specifier>:

对于 CLR 触发器,指定要与触发器绑定的程序集的方法。该方法不得不引用任何参数并返回 void。class_name 必须是有效的 SQL Server 标识符,并且必须作为具有程序集可见性的程序集中的类存在。

 

以下是DML触发器的使用,先看看示例数据:

 

insert 触发器:

 1 if(OBJECT_ID('trigger_Stu_Insert') is not null)        -- 判断名为 trigger_Stu_Insert 的触发器是否存在
2 drop trigger trigger_Stu_Insert -- 删除触发器
3 go
4 create trigger trigger_Stu_Insert
5 on Student -- 指定创建触发器的表
6 for insert -- insert 触发器,也可以写为 after insert
7 as
8
9 declare @C_Id int
10 declare @S_Id int
11
12 select @C_Id=C_Id from Course where C_Name='SQL' -- 获取课程为 SQL 的ID
13 select @S_Id=S_Id from inserted --插入一条学生的数据,那么这条数据就存在 inserted 这个表中
14
15 select @C_Id
16 select @S_Id
17
18 select * from inserted
19
20 update Student set C_S_Id=@C_Id where S_Id=@S_Id
21 go
22
23 insert into Student(S_StuNo,S_Name,S_Sex,S_Height,S_BirthDate)
24 values('016','大熊','男','210','2017-01-01')
25
26 select * from Student
27 select * from Course

这个例子是:当 Student 表新增一条数据时,修改这条数据的课程ID。

delete 触发器:

 1 if(OBJECT_ID('trigger_Stu_Delete') is not null)        -- 判断名为 trigger_Stu_Delete 的触发器是否存在
2 drop trigger trigger_Stu_Delete -- 删除触发器
3 go
4 create trigger trigger_Stu_Delete
5 on Student -- 指定创建触发器的表
6 for delete -- delete 触发器,也可以写为 after delete
7 as
8
9 declare @C_S_Id int
10
11 select @C_S_Id=C_S_Id from deleted --删除的学生的数据就存在 deleted 这个表中
12
13 select @C_S_Id
14
15 select * from deleted
16
17 delete from Course where C_Id=@C_S_Id -- 删除具有删除的学生的课程ID的课程
18 go
19
20 delete from Student where C_S_Id='1'
21
22 select * from Student
23 select * from Course

这个例子是:删除指定课程ID的学生时,并删除指定课程ID的课程。

update 触发器:

 1 if(OBJECT_ID('trigger_Cou_Update') is not null)        -- 判断名为 trigger_Cou_Update 的触发器是否存在
2 drop trigger trigger_Cou_Update -- 删除触发器
3 go
4 create trigger trigger_Cou_Update
5 on Course -- 指定创建触发器的表
6 for update -- update 触发器,也可以写为 after update
7 as
8
9 declare @C_Id int
10
11 select @C_Id=C_Id from deleted
12
13 select * from deleted -- 修改前的数据就存在 deleted 这个表中
14
15 select * from inserted -- 修改后的数据就存在 inserted 这个表中
16
17 update Student set C_S_Id=@C_Id where C_S_Id is null
18 go
19
20 update Course set C_Name='C#' where C_Id='4'
21
22 select * from Student
23 select * from Course

这个例子是:修改课程名称时,把课程ID为空(null)的学生的课程ID默认为修改的课程ID。

禁止修改学生学号触发器,触发器进行数据回滚:

 1 if(OBJECT_ID('trigger_Stu_Update') is not null)        -- 判断名为 trigger_Stu_Update 的触发器是否存在
2 drop trigger trigger_Stu_Update -- 删除触发器
3 go
4 create trigger trigger_Stu_Update
5 on Student -- 指定创建触发器的表
6 for update -- update 触发器,也可以写为 after update
7 as
8 begin try
9 if(UPDATE(S_StuNo)) -- 列级触发器:判断是否更新了学生学号(学号不允许更改)
10 begin
11 raiserror(66666,16,1)
12 end
13 end try
14 begin catch
15 select * from deleted -- 修改前的数据就存在 deleted 这个表中
16 select * from inserted -- 修改后的数据就存在 inserted 这个表中
17 rollback tran;
18 end catch
19 go
20
21 update Student set S_StuNo='006' where S_Id='20'
22
23 select * from Student

after 触发器可以指定多个操作都可以触发该触发器。只需要在 for/after 后面添加逗号和触发器的类型,例如:

1 for update,insert,delete
2
3 after update,insert,delete

instead of 触发器:

这个触发器就好玩了,下面先看看数据。

 1 if(OBJECT_ID('trigger_Stu_InsteadOf') is not null)        -- 判断名为 trigger_Stu_InsteadOf 的触发器是否存在
2 drop trigger trigger_Stu_InsteadOf -- 删除触发器
3 go
4 create trigger trigger_Stu_InsteadOf
5 on Student -- 指定创建触发器的表
6 instead of update,insert,delete -- instead of 触发器
7 as
8 select * from deleted -- 修改前的数据就存在 deleted 这个表中
9 select * from inserted -- 修改后的数据就存在 inserted 这个表中
10 go
11
12 update Student set S_StuNo='006' where S_Id='20'
13
14 insert into Student([S_StuNo],[S_Name],[S_Sex],[S_Height],[S_BirthDate])
15 values('017','清红','女','180','2017-01-01')
16
17 delete from Student where C_S_Id='5'
18
19 select * from Student

执行上面的语句之后,咦,数据怎么一点变化都没有?看看上面的介绍。instead of 触发器是之前触发。

instead of 触发器并不执行其定义的操作(insert、update、delete)而仅是执行触发器本身,并且会覆盖触发语句的操作,即 after 触发器 T-SQL 语句的操作,很明显我们上面定义的表 Student 的 after 触发器也没有效果了,现在理解了这句话了吧。

修改触发器:

 1 alter trigger trigger_Stu_InsteadOf        -- 修改触发器
2 on Student -- 指定创建触发器的表
3 instead of update,insert,delete -- instead of 触发器
4 as
5 declare @Count1 int
6 declare @Count2 int
7
8 select @Count1=COUNT(1) from deleted
9 select @Count2=COUNT(1) from inserted
10
11 if(@Count1>0 and @Count2>0)
12 begin
13 select 'update操作'
14 end
15 else if(@Count1>0)
16 begin
17 select 'delete操作'
18 end
19 else if(@Count2>0)
20 begin
21 select 'insert操作'
22 end
23 go
24
25 update Student set S_StuNo='006' where S_Id='20'
26
27 insert into Student([S_StuNo],[S_Name],[S_Sex],[S_Height],[S_BirthDate])
28 values('017','清红','女','180','2017-01-01')
29
30 delete from Student where C_S_Id='5'
31
32 select * from Student

启用/禁用触发器:

1 --禁用触发器
2 disable trigger trigger_Stu_InsteadOf on Student; -- trigger_Stu_InsteadOf 触发器名称
3 --启用触发器
4 enable trigger trigger_Stu_InsteadOf on Student; -- trigger_Stu_InsteadOf 触发器名称

查询已存在的触发器:

1 -- 查询已存在的触发器
2 select * from sys.triggers;
3 select * from sys.objects where type = 'TR';
4 select * from sysobjects where xtype='TR'
 1 -- sys.trigger_events 触发器事件对象视图
2 select * from sys.trigger_events
3
4 -- 查看触发器触发事件对象
5 select a.type_desc,b.* from sys.trigger_events a
6 inner join sys.triggers b on a.object_id = b.object_id
7 where b.name = 'trigger_Stu_Insert';
8
9 -- 查询创建触发器的 T-SQL 文本
10 exec sp_helptext 'trigger_Stu_Insert'

 

参考:

http://www.cnblogs.com/hoojo/archive/2011/07/20/2111316.html

https://docs.microsoft.com/en-us/sql/t-sql/statements/create-trigger-transact-sql#remarks-dml-triggers

sql sever 触发器的概念和使用的更多相关文章

  1. sql Sever的存储过程转换为mysql的

    总体来说,sql sever和Mysql的存储过程的思路都是一样的,但是在语法和结构上还是有很大的区别的.1. 在mysql中写存储过程所有的dbo都要去掉.2. 每一个sql语句后面都需要加上:否则 ...

  2. SQL Server 触发器2

    触发器可以做很多事情,但也会带来很多问题.使用它的技巧在于在适当的时候使用,而不要在不适当的时候使用它们. 触发器的一些常见用途如下: 弹性参照完整性:实现很多DRI不能实现的操作(例如,跨数据库或服 ...

  3. SQL Sever 学习系列之一

    SQL Sever 学习系列之一 本学习系列,从实际工作需要中积累,对于一个新手而言,写出几条漂亮的查询语句,应该是可以受启发的. 一.问题的需求是:员工薪酬发放,现有资金能发放多少人,哪些人应得? ...

  4. SQL SEVER 2008中的演示样例数据库

    SQL SEVER 2008数据库是什么我就不说了,我在这里分享一下怎样学习SQL SEVER 2008数据库,假设是对数据库或是SQL SEVER 数据库全然陌生或是不熟悉的人来说,建议看看一些视频 ...

  5. sql sever 2008基础知识

    下面是一些总结,如果执行时发现错误,可以查看错误消息进行解决,也可上网查资料 数据库的组成: 主数据文件:有且只有一个,扩展名为.mdf. 次数据文件:可以没有,也可以有任意个.扩展名为.ndf. 日 ...

  6. SQL Sever 博客文章目录(2016-07-06更新)

    SQL Server方面的博客文章也陆陆续续的写了不少了,顺便也将这些知识点整理.归纳一下下.方便自己和他人查看. MS SQL 数据类型 三大数据库对比研究系列--数据类型 MS SQL 表和视图 ...

  7. SQL Sever无法打开链接对话框,未将对象引用设置到对象的实例。(AppIDPackage)

    前几天刚做完系统,先装的是SQL Sever2008,装完后还试了一下,OK~没问题,然后就继续装VS2012等一些软件.搞到很晚没有继续试试就睡了,第二天运行SSMS出问题了..(如图 1.0 所示 ...

  8. 3-1创建Sql Sever数据库登录名

    登录名:连接Sql Sever 服务器 数据库用户名: Sql Sever 的使用者 每个用来登录Sql Sever 的账户都是一个用户. 同一个数据库可以拥有多个用户,每一个用户也同时可以访问多个数 ...

  9. 1-03 Sql Sever 的身份验证模式

    身份验证分为: 1:Windows身份验证. 1:Sql Sever身分验证. 每种验证的具体方式: 1Windows的验证方式 点击下拉框,有这两种验证方式,Windows验证只需要启动服务即可. ...

随机推荐

  1. thinkphp5.0数据导出excel表格

    第一步.创建Model类文件(名称自定) 第二步.在类中写入以下代码 <?php namespace Admin\admin\model; use think\Model; class Mark ...

  2. on duplicate key mysql插入更新

    insert into `test` (`job_id`, `user_name`, `total_time`) values ('12345', 'zhangsan', '10') on dupli ...

  3. go guid 和uuid生成

    1 安装 开始-运行 输入 cmd 回车 输入 go get -u github.com/typa01/go-utils 安装完毕后 2 使用 a 首先引入包 import (      goutil ...

  4. Scratch(三)剪刀石头布

    经过上一讲的突击训练,我们从门外汉开始走向编程的深坑,我们今天还要对上一讲的游戏进行加强. 上一个游戏还能演变成什么游戏呢? 我其实知道你们想到的是老hu机什么的,确实,上一个游戏改改可以变成老hu机 ...

  5. oracle-3-Linux-11g安装-静默安装

    oracle下载地址:https://www.oracle.com/database/technologies/112010-linx8664soft.html 系统是最小化安装的Centos7.2 ...

  6. hdu1171 灵活的运用背包问题咯。。。 还有!!!! 合理的计算数组的范围!! wa了好多次!

    Problem Description Nowadays, we all know that Computer College is the biggest department in HDU. Bu ...

  7. jquery.fileupload源码解读笔记

    基础编程风格 新建 test.html  和 test.js和 main.js和 无论哪种顺序 <body> <script src="/Sandeep/js/jquery ...

  8. C#委托,匿名方法,Lambda,泛型委托,表达式树代码示例

    第一分钟:委托 有些教材,博客说到委托都会提到事件,虽然事件是委托的一个实例,但是为了理解起来更简单,今天只谈委托不谈事件.先上一段代码: 下边的代码,完成了一个委托应用的演示.一个委托分三个步骤: ...

  9. .net mvc 迁移到 .netcore

    迁移的时候发现,ef6 不能添加 到  .NET Standard2  的类库,因为不兼容, 6 以上的版本只能用于  .net 4.5 以上 只能用别的

  10. phpcms企业站的一些知识

    头header.html 尾footer.html 主页用index.html 列表页用list.html 单网页用page.html 内容页用show.html {template "co ...