一.触发器概述
触发器是一种特殊类型的存储过程,当指定表中的数据发生变化时触发器自动生效。它与表紧密相连,可以看做是表定义的一部分。触发器不能通过名称被直接调用,更不允许设置参数。
在SQL Server中一张表可以有多个触发器。用户可以使用INSERT、UPDATE或DELETE语句对触发器进行设置,也可以对一张表上的特定操作设置多个触发器。触发器可以包含复杂的Transact-SQL语句。不论触发器所进行的操作有多复杂,触发器都只作为一个独立的单元被执行,被看作是一个事务。如果在执行触发器的过程中发生了错误,则整个事务将会自动回滚。
二.触发器优点
触发器的优点表现在以下几个方面:
(1)触发器自动执行,对表中的数据进行修改后,触发器立即被激活。
(2)为了实现复杂的数据库更新操作,触发器可以调用一个或多个存储过程,甚至可以通过调用外部过程(不是数据库管理系统本身)完成相应的操作。
(3)触发器能够实现比CHECK约束更为复杂的数据完整性约束。在数据库中,为了实现数据完整性约束,可以使用CHECK约束或触发器。CHECK约束不允许引用其他表中的列来完成检查工作,而触发器可以引用其他表中的列。它更适合在大型数据库管理系统中用来约束数据的完整性。
(4)触发器可以检测数据库内的操作,从而取消了数据库未经许可的更新操作,使数据库修改、更新操作更安全,数据库的运行也更稳定。
(5)触发器能够对数据库中的相关表实现级联更改。触发器是基于一个表创建的,但是可以针对多个表进行操作,实现数据库中相关表的级联更改。
(6)一个表中可以同时存在3个不同操作的触发器(INSERT、UPDATE和DELETE)。
三.触发器分类
SQL SERVER 包括三种常规类型的触发器:DML 触发器、DDL 触发器和登录触发器。
当数据库中发生数据操作语言 (DML) 事件时将调用 DML 触发器。DML 事件包括在指定表或视图中修改数据的 INSERT 语句、UPDATE 语句或 DELETE 语句。DML 触发器可以查询其他表,还可以包含复杂的 TRANSACT-SQL 语句。
您可以设计以下类型的 DML 触发器:
(1) AFTER 触发器:在执行了 INSERT、UPDATE 或 DELETE 语句操作之后执行 AFTER 触发器。
(2)INSTEAD OF 触发器:执行 INSTEAD OF 触发器代替通常的触发动作。还可为带有一个或多个基表的视图定义 INSTEAD OF 触发器,而这些触发器能够扩展视图可支持的更新类型。
(3) CLR 触发器:CLR 触发器将执行在托管代码(在 .NET FRAMEWORK 中创建并在 SQL SERVER 中上载的程序集的成员)中编写的方法,而不用执行 TRANSACT-SQL 存储过程。CLR 触发器可以是 AFTER 触发器或 INSTEAD OF 触发器,还可以是 DDL 触发器。
(4)DDL 触发器:DDL 触发器是一种特殊的触发器,它在响应数据定义语言 (DDL) 语句时触发,可以用于在数据库中执行管理任务,审核以及规范数据库操作。
四.创建DML触发器
如果用户要通过数据操作语言 (DML) 事件编辑数据,则执行 DML 触发器。DML 事件是针对表或视图的 INSERT、UPDATE 或 DELETE 语句。
创建DML触发器的语法如下:
CREATE TRIGGER [ schema_name . ]trigger_name
ON { table | view }
[ WITH <dml_trigger_option> [ ,…n ] ]
{ FOR | AFTER | INSTEAD OF }
{ [ INSERT ] [ , ] [ UPDATE ] [ , ] [ DELETE ] }
[ WITH APPEND ]
[ NOT FOR REPLICATION ]
AS { sql_statement [ ; ] [ ,…n ] | EXTERNAL NAME <method specifier [ ; ] > }
<dml_trigger_option> ::=
[ ENCRYPTION ]
[ EXECUTE AS Clause ]
<method_specifier> ::=
assembly_name.class_name.method_name
创建DML触发器的参数说明。
(1)SCHEMA_NAME:DML触发器所属架构的名称。DML触发器的作用域是为其创建该触发器的表或视图的架构。
(2)TRIGGER_NAME:触发器的名称。TRIGGER_NAME 必须遵循标识符规则,但 TRIGGER_NAME 不能以 # 或 ## 开头。
(3)TABLE | VIEW:对其执行 DML 触发器的表或视图,有时称为触发器表或触发器视图。可以根据需要指定表或视图的完全限定名称。视图只能被 INSTEAD OF 触发器引用。不能对局部或全局临时表定义 DML 触发器。
(4)FOR | AFTER:AFTER指定DML触发器仅在触发SQL语句中指定的所有操作都已成功执行时才被触发。
(5)INSTEAD OF:指定执行 DML 触发器而不是触发 SQL 语句,因此,其优先级高于触发语句的操作。
(6){ [ INSERT ] [ , ] [ UPDATE ] [ , ] [ DELETE ] }:指定数据修改语句,这些语句可在 DML 触发器对此表或视图进行尝试时激活该触发器。必须至少指定一个选项。
(7)WITH APPEND:指定应该再添加一个现有类型的触发器。
(8)NOT FOR REPLICATION:指示当复制代理修改涉及到触发器的表时,不应执行触发器。
(9)SQL_STATEMENT:触发条件和操作。触发器条件指定其他标准,用于确定尝试的 DML、DDL 或 LOGON 事件是否导致执行触发器操作。
(10)EXECUTE AS CLAUSE:指定用于执行该触发器的安全上下文。
(11)< METHOD_SPECIFIER>:对于CLR触发器,指定程序集与触发器绑定的方法。该方法不能带有任何参数,并且必须返回空值。
五.建立DDL触发器
DDL 触发器用于响应各种数据定义语言 (DDL) 事件。这些事件主要对应于 TRANSACT-SQL CREATE、ALTER 和 DROP 语句,以及执行类似 DDL 操作的某些系统存储过程。
创建DDL触发器的语法如下:
CREATE TRIGGER TRIGGER_NAME
ON { ALL SERVER | DATABASE }
[ WITH <DDL_TRIGGER_OPTION> [ ,…N ] ]
{ FOR | AFTER } { EVENT_TYPE | EVENT_GROUP } [ ,…N ]
AS { SQL_STATEMENT [ ; ] [ ,…N ] | EXTERNAL NAME < METHOD SPECIFIER > [ ; ] }
<DDL_TRIGGER_OPTION> ::=
[ ENCRYPTION ]
[ EXECUTE AS CLAUSE ]
<METHOD_SPECIFIER> ::=
ASSEMBLY_NAME.CLASS_NAME.METHOD_NAME
创建DDL触发器的参数说明。
(1)TRIGGER_NAME:触发器的名称。TRIGGER_NAME必须遵循标识符规则,但TRIGGER_NAME不能以#或##开头
(2)ALL SERVER:将DDL或登录触发器的作用域应用于当前服务器。
(3)DATABASE:将DDL触发器的作用域应用于当前数据库。
(4)FOR | AFTER:AFTER指定DML触发器仅在触发SQL语句中指定的所有操作都已成功执行时才被触发。
(5)EVENT_TYPE:执行之后将导致激发DDL触发器的TRANSACT-SQL语言事件的名称。DDL事件中列出了DDL触发器的有效事件。
(6)EVENT_GROUP:预定义的TRANSACT-SQL语言事件分组的名称。
(7)SQL_STATEMENT:触发条件和操作。触发器条件指定其他标准,用于确定尝试的DML、DDL或LOGON事件是否导致执行触发器操作。
(8)< METHOD_SPECIFIER>:对于CLR触发器,指定程序集与触发器绑定的方法。
例:为数据库db_2012创建DDL触发器,防止用户对表进行删除或修改等操作。
设计步骤如下:
(1)打开SQL Server Management Studio,并连接到SQL Server2012中的数据库。
(2)单击工具栏中“ ”按钮,新建查询编辑器,输入如下SQL语句代码。
CREATE TRIGGER T_DDL_DATABASE --创建DDL触发器
ON DATABASE --将该触发器应用于当前数据库
FOR DROP_TABLE, ALTER_TABLE --对表修改时,提示信息
AS
PRINT ‘只有“T_DDL_DATABASE”触发器无效时,才可以删除或修改表。’
ROLLBACK --回滚操作
(3)单击“ ”按钮,就可以执行上述SQL语句代码。创建名称为T_DDL_DATABASE的DDL触发器。
创建完该触发器后,当对数据库中的表进行修改与删除等操作时,都会提示“只有‘T_DDL_DATABASE’触发器无效时,才可以删除或修改表”信息,并将删除后修改操作进行回滚。显示信息。
六.创建登录触发器
登录触发器在遇到 LOGON 事件时触发。LOGON 事件是在建立用户会话时引发的。触发器可以由 TRANSACT-SQL 语句直接创建,也可以由程序集方法创建,这些方法是在 MICROSOFT .NET FRAMEWORK 公共语言运行时 (CLR) 中创建并下载到 SQL SERVER 实例的。SQL SERVER 允许为任何特定语句创建多个触发器。
创建登录触发器的语法如下:
CREATE TRIGGER TRIGGER_NAME
ON ALL SERVER
[ WITH <LOGON_TRIGGER_OPTION> [ ,…N ] ]
{ FOR | AFTER } LOGON
AS { SQL_STATEMENT [ ; ] [ ,…N ] | EXTERNAL NAME < METHOD SPECIFIER > [ ; ] }
<LOGON_TRIGGER_OPTION> ::=
[ ENCRYPTION ]
[ EXECUTE AS CLAUSE ]
<METHOD_SPECIFIER> ::=
ASSEMBLY_NAME.CLASS_NAME.METHOD_NAME
创建登录触发器的参数说明。
(1)TRIGGER_NAME:触发器的名称。TRIGGER_NAME必须遵循标识符规则,但TRIGGER_NAME不能以#或##开头。
(2)ALL SERVER:将DDL或登录触发器的作用域应用于当前服务器。
(3)FOR | AFTER:AFTER指定DML触发器仅在触发SQL语句中指定的所有操作都已成功执行时才被触发。
(4)SQL_STATEMENT:触发条件和操作。触发器条件指定其他标准,用于确定尝试的DML、DDL或LOGON事件是否导致执行触发器操作。
(5)< METHOD_SPECIFIER>:对于CLR触发器,指定程序集与触发器绑定的方法。
例:创建一个名为connection_limit_trigger的登录触发器,功能为拒绝登录名为mr的成员登录 SQL Server,SQL语句如下。
USE master;
GO
CREATE LOGIN mr WITH PASSWORD = ‘mrsoft’ MUST_CHANGE,
CHECK_EXPIRATION = ON;
GO
GRANT VIEW SERVER STATE TO mr;
GO
CREATE TRIGGER connection_limit_trigger
ON ALL SERVER WITH EXECUTE AS ‘mr’
FOR LOGON
AS
BEGIN
IF ORIGINAL_LOGIN()= ‘mr’ AND
(SELECT COUNT(*) FROM sys.dm_exec_sessions
WHERE is_user_process = 1 AND
original_login_name = ‘mr’) > 1
ROLLBACK;
END;
登录触发器与DML触发器、DDL触发器所存储的位置不同,其存储位置为对象资源管理器中“服务器对象”/“触发器”。登录触发器connection_limit_trigger中的mr为登录到SQL Server中的登录名。触发器及mr所在的位置。
七.查看触发器
查看触发器与查看存储过程相同。同样可以使用sp_helptext存储过程与sys.sql_modules视图查看触发器。
使用sp_helptext存储过程查看触发器
sp_helptext存储过程可以查看架构范围内的触发器,非架构范围内的触发器是不能用此存储过程查看的,如DDL触发器、登录触发器。
获取数据库中触发器的信息
每个类型为 TR 或 TA 的触发器对象对应一行,TA代表程序集 (CLR) 触发器,TR代表 SQL 触发器。DML 触发器名称在架构范围内,因此,可在 sys.objects 中显示。DDL 触发器名称的作用域取决于父实体,只能在对象目录视图中显示。
八.修改触发器
修改触发器可以通过ALTER TRIGGER语句实现,下面分别对修改DML触发器、修改DDL触发器修改登录触发器进行介绍。
A.修改DML触发器
修改DML触发器的语法如下:
ALTER TRIGGER schema_name.trigger_name
ON ( table | view )
[ WITH <dml_trigger_option> [ ,…n ] ]
( FOR | AFTER | INSTEAD OF )
{ [ DELETE ] [ , ] [ INSERT ] [ , ] [ UPDATE ] }
[ NOT FOR REPLICATION ]
AS { sql_statement [ ; ] [ …n ] | EXTERNAL NAME [ ; ] }
<dml_trigger_option> ::=
[ ENCRYPTION ]
[ ]
<method_specifier> ::=
assembly_name.class_name.method_name
修改DML触发器的参数说明。
(1)SCHEMA_NAME:DML触发器所属架构的名称。DML触发器的作用域是为其创建该触发器的表或视图的架构。
(2)TRIGGER_NAME:要修改的现有触发器。
(3)TABLE | VIEW:对其执行DML触发器的表或视图,有时称为触发器表或触发器视图。可以根据需要指定表或视图的完全限定名称。
(4)AFTER:指定只有在触发SQL语句成功执行后,才会激发触发器。
(5)INSTEAD OF:指定执行DML触发器而不是触发SQL语句,因此,其优先级高于触发语句的操作。
(6){ [ DELETE ] [ , ] [ INSERT ] [ , ] [ UPDATE ] }:指定数据修改语句在试图修改表或视图时,激活DML触发器。必须至少指定一个选项。
(7)NOT FOR REPLICATION:指示当复制代理修改涉及到触发器的表时,不应执行触发器。
(8)SQL_STATEMENT:触发条件和操作。
(9)EXECUTE AS CLAUSE:指定用于执行该触发器的安全上下文。
(10)< METHOD_SPECIFIER>:对于CLR触发器,指定程序集与触发器绑定的方法。该方法不能带有任何参数,并且必须返回空值。
B.修改DDL触发器
修改DDL触发器的语法如下:
ALTER TRIGGER TRIGGER_NAME
ON { DATABASE | ALL SERVER }
[ WITH <DDL_TRIGGER_OPTION> [ ,…N ] ]
{ FOR | AFTER } { EVENT_TYPE [ ,…N ] | EVENT_GROUP }
AS { SQL_STATEMENT [ ; ] | EXTERNAL NAME
[ ; ] }
}
<DDL_TRIGGER_OPTION> ::=
[ ENCRYPTION ]
[ ]
<METHOD_SPECIFIER> ::=
ASSEMBLY_NAME.CLASS_NAME.METHOD_NAME
修改DDL触发器的参数说明。
(1)TRIGGER_NAME:要修改的现有触发器。
(2)DATABASE:将DDL触发器的作用域应用于当前数据库。
(3)ALL SERVER:将DDL或登录触发器的作用域应用于当前服务器。
(4)AFTER:指定只有在触发SQL语句成功执行后,才会激发触发器。
(5)EVENT_TYPE:执行之后将导致激发DDL触发器的TRANSACT-SQL语言事件的名称。
(6)EVENT_GROUP:预定义的TRANSACT-SQL语言事件分组的名称。
(7)SQL_STATEMENT:触发条件和操作。
(8)EXECUTE AS CLAUSE:指定用于执行该触发器的安全上下文。
(9)< METHOD_SPECIFIER>:对于CLR触发器,指定程序集与触发器绑定的方法。该方法不能带有任何参数,并且必须返回空值。
修改登录触发器的参数说明。
(1)TRIGGER_NAME:要修改的现有触发器。
(2)ALL SERVER:将DDL或登录触发器的作用域应用于当前服务器。
(3)AFTER:指定只有在触发SQL语句成功执行后,才会激发触发器。
(4)SQL_STATEMENT:触发条件和操作。
(5)EXECUTE AS:指定用于执行该触发器的安全上下文。
(6)<METHOD_SPECIFIER>:指定要与触发器绑定的程序集的方法。
九.重命名触发器
重命名触发器可以使用sp_rename系统存储过程实现。使用sp_rename系统存储过程重命名触发器与重命名存储过程相同。但是使用该系统存储过程重命名触发器,不会更改sys.sql_modules类别视图的definition(用于定义此模块的SQL文本)列中相应对象名的名称,所以建议用户不要使用该系统存储过程重命名触发器,而是删除该触发器,然后使用新名称重新创建该触发器。
十.禁用和启用触发器
当不再需要某个触发器时,可将其禁用或删除。禁用触发器不会删除该触发器,该触发器仍然作为对象存在于当前数据库中。但是,当执行任意 INSERT、UPDATE 或 DELETE 语句(在其上对触发器进行编程)时,触发器将不会激发。已禁用的触发器可以被重新启用。启用触发器会以最初创建它时的方式将其激发。默认情况下,创建触发器后会启用触发器。
A.禁用触发器
使用DISABLE TRIGGER语句禁用触发器,其语法如下:
DISABLE TRIGGER { [ SCHEMA_NAME . ] TRIGGER_NAME [ ,…N ] | ALL }
ON { OBJECT_NAME | DATABASE | ALL SERVER } [ ; ]
参数说明:
(1)SCHEMA_NAME:触发器所属架构的名称。
(2)TRIGGER_NAME:要禁用的触发器的名称。
(3)ALL:指示禁用在 ON 子句作用域中定义的所有触发器。
注意:
SQL SERVER 在为合并复制发布的数据库中创建触发器。在已发布数据库中指定 ALL 可禁用这些触发器,这样会中断复制。在指定 ALL 之前,请验证没有为合并复制发布当前数据库。
(4)OBJECT_NAME:对创建要执行的 DML 触发器 TRIGGER_NAME 的表或视图的名称。
(5)DATABASE:对于 DDL 触发器,指示所创建或修改的 TRIGGER_NAME 将在数据库范围内执行。
(6)ALL SERVER:对于 DDL 触发器,指示所创建或修改的 TRIGGER_NAME 将在服务器范围内执行。ALL SERVER 也适用于登录触发器。
B.启用触发器
启用触发器并不是重新创建它。已禁用的DDL、DML或登录触发器可以通过执行ENABLE TRIGGER语句重新起用。
语法如下:
ENABLE TRIGGER { [ SCHEMA_NAME . ] TRIGGER_NAME [ ,…N ] | ALL }
ON { OBJECT_NAME | DATABASE | ALL SERVER } [ ; ]
启用触发器的参数说明。
(1)SCHEMA_NAME:触发器所属架构的名称。不能为DDL或登录触发器指定SCHEMA_NAME。
(2)TRIGGER_NAME:要启用的触发器的名称。
(3)ALL:指示启用在ON子句作用域中定义的所有触发器。
(4)OBJECT_NAME:要对其创建要执行的DML触发器TRIGGER_NAME的表或视图的名称。
(5)DATABASE:对于DDL触发器,指示所创建或修改的TRIGGER_NAME将在数据库范围内执行。
(6)ALL SERVER:对于DDL触发器,指示所创建或修改的TRIGGER_NAME将在服务器范围内执行。ALL SERVER也适用于登录触发器。
十一.删除触发器
删除触发器是将触发器对象从当前数据库中永久的删除。通过执行DROP TRIGGER语句可以将DML、DDL或登录触发器删除。也可以通过操作SQL SERVER MANAGEMENT STUDIO手动删除DML、DDL或登录触发器。
A.DROP TRIGGER语句删除触发器
DROP TRIGGER语句可以从当前数据库中删除一个或多个DML、DDL或登录触发器。
a.删除DML触发器
删除DML触发器的语法如下:
DROP TRIGGER SCHEMA_NAME.TRIGGER_NAME [ ,…N ] [ ; ]
参数说明:
(1)SCHEMA_NAME:DML 触发器所属架构的名称。
(2)TRIGGER_NAME:要删除的触发器的名称
b.删除DDL触发器
删除DDL触发器的语法如下:
DROP TRIGGER TRIGGER_NAME [ ,…N ]
ON { DATABASE | ALL SERVER }
[ ; ]
参数说明:
TRIGGER_NAME:要删除的触发器的名称。
DATABASE:指示 DDL 触发器的作用域应用于当前数据库。如果在创建或修改触发器时也指定了 DATABASE,则必须指定 DATABASE。
ALL SERVER:指示 DDL 触发器的作用域应用于当前服务器。如果在创建或修改触发器时也指定了 ALL SERVER,则必须指定 ALL SERVER。ALL SERVER 也适用于登录触发器。
c.删除登录触发器
删除登录触发器的语法如下:
DROP TRIGGER TRIGGER_NAME [ ,…N ]
ON ALL SERVER
参数说明:
(1)TRIGGER_NAME:要删除的触发器的名称。
(2)ALL SERVER:ALL SERVER 也适用于登录触发器。
B.SQL Server Management Studio手动删除触发器
手动删除触发器步骤如下:
(1)打开SQL Server Management Studio,并连接到SQL Server2012中的数据库。
(2)展开“对象资源管理器”中的触发器所在的位置。例如要删除创建在db_2012数据库的T_DDL_DATABASE触发器,则展开的树型结构。
十二.常见错误
修改数据表失败,提示未提交数据
修改或删除数据表的数据时提示:未提交数据,错误消息:已更新或删除的行值要么不能使该行成为唯一值,要么改变了多个行。
这是因为表中没有设置主键,存在重复的数据。解决:设置主键以唯一的标识一个记录。或者重新建表,插入不重复的记录。
触发器的递归调用方式
触发器不会以递归方式自行调用,有两种不同的递归方式。一种是直接递归,即触发器激发并执行一个操作,而该操作又使同一个触发器再次激发。另一种是间接递归,是指触发器激发并执行一个操作,而该操作又使另一个表中的某个触发器激发。第二个触发器使原始表得到更新,从而再次引发第一个触发器。
来源:https://blog.csdn.net/weixin_44870681/article/details/100664476