]vp_nPbJ]
NOTFORREPLICATIONzGnO__&_NX
___EF_a__t
表示当复制进程更改触发器所涉及的表时,不应执行该触发器。
_V_nj_`w"_
_7tSbsC"_
AS#_S!
r_zb
xfo#`1(6_
是触发器要执行的操作。
Cj@(#t`Fs_
E;;t_+\nfq
sql_statementp@|z_-__b
/UU_heZb{
是触发器的条件和操作。
触发器条件指定其它准则,以确定Delete、Insert或Update语句是否导致执行触发器操作。
V_p/x_Kt
gO9Rm]SH3
当尝试Delete、Insert或Update操作时,Transact-SQL语句中指定的触发器操作将生效。
__>wz7qlx
vhF%.co*_
触发器可以包含任意数量和种类的Transact-SQL语句。
触发器旨在根据数据修改语句检查或更改数据;它不应将数据返回给用户。
触发器中的Transact-SQL语句常常包含控制流语言。
CreateTRIGGER语句中使用几个特殊的表:
___>2&e'_
+_x[-iO_{_
deleted和inserted是逻辑(概念)表。
这些表在结构上类似于定义触发器的表(也就是在其中尝试用户操作的表);这些表用于保存用户操作可能更改的行的旧值或新值。
例如,若要检索deleted表中的所有值,请使用:
6%s_KP__
Select*N'G6_
{DF
FROMdeleted^2}&_bDul
_i_$<
_t
如果兼容级别等于70,那么在Delete、Insert或Update触发器中,SQLServer将不允许引用inserted和deleted表中的text、ntext或image列。
不能访问inserted和deleted表中的text、ntext和image值。
若要在Insert或Update触发器中检索新值,请将inserted表与原始更新表联接。
当兼容级别是65或更低时,对inserted或deleted表中允许空值的text、ntext或image列,将返回空值;如果这些列不可为空,则返回零长度字符串。
QCx_g%IZ
当兼容级别是80或更高时,SQLServer允许在表或视图上通过INSTEADOF触发器更新text、ntext或image列。
}3_p__6j=_
m<<3/(G_b
nQn~JyGRx,
f6K+P%_Z
是表示触发器中可以包含多条Transact-SQL语句的占位符。
对于IFUpdate(column)语句,可以通过重复Update(column)子句包含多列。
>__QH"i<.e
kN_m/2_c
IFUpdate(column)_2_5{O4~O_
___/y0W8)H
测试在指定的列上进行的Insert或Update操作,不能用于Delete操作。
可以指定多列。
因为在ON子句中指定了表名,所以在IFUpdate子句中的列名前不要包含表名。
若要测试在多个列上进行的Insert或Update操作,请在第一个操作后指定单独的Update(column)子句。
在Insert操作中IFUpdate将返回TRUE值,因为这些列插入了显式值或隐性(NULL)值。
7^___IsK
[I';ZBqY
_Jf?
5___
说明 IFUpdate(column)子句的功能等同于IF、IF...ELSE或WHILE语句,并且可以使用BEGIN...END语句块。
有关更多信息,请参见控制流语言。
tEv=Eot!
H2
B&,_bd_A~P
g_dW9;__8{
可以在触发器主体中的任意位置使用Update(column)。
*V|Hx|\lm^
no_=J6_FAR
column#MI_+#_-?
10$3?
B7]{
是要测试Insert或Update操作的列名。
该列可以是SQLServer支持的任何数据类型。
但是,计算列不能用于该环境中。
有关更多信息,请参见数据类型。
(OWop"rPy
[b_M_va_
IF(COLUMNS_UpdateD())0A[v_EJq_EG]5{Nt
测试是否插入或更新了提及的列,仅用于Insert或Update触发器中。
COLUMNS_UpdateD返回varbinary位模式,表示插入或更新了表中的哪些列。
{_Fk_r_3'0
Yr4_DcA8
COLUMNS_UpdateD函数以从左到右的顺序返回位,最左边的为最不重要的位。
最左边的位表示表中的第一列;向右的下一位表示第二列,依此类推。
如果在表上创建的触发器包含8列以上,则COLUMNS_UpdateD返回多个字节,最左边的为最不重要的字节。
在Insert操作中COLUMNS_UpdateD将对所有列返回TRUE值,因为这些列插入了显式值或隐性(NULL)值。
g$cm_6}2
<
_3T_B3`t"7
可以在触发器主体中的任意位置使用COLUMNS_UpdateD。
TG~x
2!
(
_{@T_V_Td}
bitwise_operatorkDO()~__W
r_([_6E}%K
是用于比较运算的位运算符。
\Lg_7o=%(.
p_AZ_vF[$_
updated_bitmaskq_0dCA(fE
*$_+'_?
eS_
是整型位掩码,表示实际更新或插入的列。
例如,表t1包含列C1、C2、C3、C4和C5。
假定表t1上有Update触发器,若要检查列C2、C3和C4是否都有更新,指定值14;若要检查是否只有列C2有更新,指定值2。
\
=Z*pH__T
hU{lk_*$__
comparison_operator_J*h=d'LK_
R_z3^2_'4_
是比较运算符。
使用等号(=)检查updated_bitmask中指定的所有列是否都实际进行了更新。
使用大于号(>)检查updated_bitmask中指定的任一列或某些列是否已更新。
_|f:
#!
_9B
_l_L_)na
column_bitmask_VN__hi&Ss
>_N?
1}[;&g
是要检查的列的整型位掩码,用来检查是否已更新或插入了这些列。
k#Ia___{_}
}_X__L_\
注释F<__&js_y=
触发器常常用于强制业务规则和数据完整性。
SQLServer通过表创建语句(AlterTABLE和CreateTABLE)提供声明引用完整性(DRI);但是DRI不提供数据库间的引用完整性。
若要强制引用完整性(有关表的主键和外键之间关系的规则),请使用主键和外键约束(AlterTABLE和CreateTABLE的PRIMARYKEY和FOREIGNKEY关键字)。
如果触发器表存在约束,则在INSTEADOF触发器执行之后和AFTER触发器执行之前检查这些约束。
如果违反了约束,则回滚INSTEADOF触发器操作且不执行(激发)AFTER触发器。
?
J]X_fG;6
5.K7G5#_t
可用sp_settriggerorder指定表上第一个和最后一个执行的AFTER触发器。
在表上只能为每个Insert、Update和Delete操作指定一个第一个执行和一个最后一个执行的AFTER触发器。
如果同一表上还有其它AFTER触发器,则这些触发器将以随机顺序执行。
xO5Mws[_!
r
$__1e8C_u
如果AlterTRIGGER语句更改了第一个或最后一个触发器,则将除去已修改触发器上设置的第一个或最后一个特性,而且必须用sp_settriggerorder重置排序值。
+d9Rz_Yw%
2p_n6_?
u=
只有当触发SQL语句(包括所有与更新或删除的对象关联的引用级联操作和约束检查)成功执行后,AFTER触发器才会执行。
AFTER触发器检查触发语句的运行效果,以及所有由触发语句引起的Update和Delete引用级联操作的效果。
_/fF#In
_h_i!
v6w
触发器限制D`_|Xe_d98
CreateTRIGGER必须是批处理中的第一条语句,并且只能应用到一个表中。
_f_S6__R2*_6
触发器只能在当前的数据库中创建,不过触发器可以引用当前数据库的外部对象。
?
x_XFPnC
B
3_x{T_toA
如果指定触发器所有者名称以限定触发器,请以相同的方式限定表名。
__hRW9_X#
V>/=v6.`_[
在同一条CreateTRIGGER语句中,可以为多种用户操作(如Insert和Update)定义相同的触发器操作。
cVb6a3_fm
;\CVq_q__~
如果一个表的外键在Delete/Update操作上定义了级联,则不能在该表上定义INSTEADOFDelete/Update触发器。
*`&+x_r6
O_MZ在触发器内可以指定任意的SET语句。
所选择的SET选项在触发器执行期间有效,并在触发器执行完后恢复到以前的设置。
A^_>V[7v(n
ah_XO""_c%
与使用存储过程一样,当触发器激发时,将向调用应用程序返回结果。
若要避免由于触发器激发而向应用程序返回结果,请不要包含返回结果的Select语句,也不要包含在触发器中进行变量赋值的语句。
包含向用户返回结果的Select语句或进行变量赋值的语句的触发器需要特殊处理;这些返回的结果必须写入允许修改触发器表的每个应用程序中。
如果必须在触发器中进行变量赋值,则应该在触发器的开头使用SETNOCOUNT语句以避免返回任何结果集。
J8.d32*_
#__4_fw'md
Delete触发器不能捕获TRUNCATETABLE语句。
尽管TRUNCATETABLE语句实际上是没有Where子句的Delete(它删除所有行),但它是无日志记录的,因而不能执行触发器。
因为TRUNCATETABLE语句的权限默认授予表所有者且不可转让,所以只有表所有者才需要考虑无意中用TRUNCATETABLE语句规避Delete触发器的问题。
_8Imk"@c/-
co6R?
_-3~t
无论有日志记录还是无日志记录,WRITETEXT语句都不激活触发器。
MJL_q_'~:
<
_x_s^^_'U
触发器中不允许以下Transact-SQL语句:
mrm
_l$pq<
!
(:
F8RAYB_
AlterDATABASECreateDATABASEDISKINITf_pVYd__
DISKRESIZEDropDATABASELOADDATABASEg9v-Mx6b!
LOADLOGRECONFIGURERESTOREDATABASEc$___j]7
W
RESTORELOG UQBC'e1(A
_C_!
+#/#_p
-\<=zIW!
KJ
WgzH@U](/
说明 由于SQLServer不支持系统表中的用户定义触发器,因此建议不要在系统表中创建用户定义触发器。
U__[M_i4e_
NilGLanb^
44T_fe]
多个触发器*Ol;4Q'y
SQLServer允许为每个数据修改事件(Delete、Insert或Update)创建多个触发器。
例如,如果对已有Update触发器的表执行CreateTRIGGERFORUpdate,则将创建另一个更新触发器。
在早期版本中,在每个表上,每个数据修改事件(Insert、Update或Delete)只允许有一个触发器。
[bs_6)>_
5mGL`_$A
dzAK=4_8_
说明 如果触发器名称不同,则CreateTRIGGER(兼容级别为70)的默认行为是在现有的触发器中添加其它触发器。
如果触发器名称相同,则SQLServer返回一条错误信息。
但是,如果兼容级别等于或小于65,则使用CreateTRIGGER语句创建的新触发器将替换同一类型的任何现有触发器,即使触发器名称不同。
有关更多信息,请参见sp_dbcmptlevel。
l__?
r?
ZE>
_^o___w)d
"F_]]_C__
递归触发器Os4!
_7__&b
当在sp_dboption中启用recursivetriggers设置时,SQLServer还允许触发器的递归调用。
w%_WG>n_`
Zgo_m_B_O3
递归触发器允许发生两种类型的递归:
uV40:
K,_R
*UkW$2?
nhG
间接递归
tc_u_e__D_^_
_xQgWclYF
直接递归E)on$:
_K2
使用间接递归时,应用程序更新表T1,从而激发触发器TR1,该触发器更新表T2。
在这种情况下,触发器T2将激发并更新T1。
?
>C-L}q8/
T8_rvy_U#!
使用直接递归时,应用程序更新表T1,从而激发触发器TR1,该触发器更新表T1。
由于表T1被更新,触发器TR1再次激发,依此类推。
__E_o2j55m
X2_DqP||_n
下例既使用了间接触发器递归,又使用了直接触发器递归。
假定在表T1中定义了两个更新触发器TR1和TR2。
触发器TR1递归地更新表T1。
Update语句使TR1和TR2各执行一次。
而TR1的执行将触发TR1(递归)和TR2的执行。
给定触发器的inserted和deleted表只包含与唤醒调用触发器的Update语句相对应的行。
>yrL5]iC_W
>\eNZ__o(
_:
yB(_d5
说明 只有启用sp_dboption的recursivetriggers设置,才会发生上述行为。
对于为给定事件定义的多个触发器,并没有确定的执行顺序。
每个触发器都应是自包含的。
x_ZQhXJ_
PS7iK*v__
_UW:
khp8
禁用recursivetriggers设置只能禁止直接递归。
若要也禁用间接递归,请使用sp_configure将nestedtriggers服务器选项设置为0。
_c_kUFG_a
|^>_3_,_{}
如果任一触发器执行了ROLLBACKTRANSACTION语句,则无论嵌套级是多少,都不会进一步执行其它触发器。
t'Ta/_v9
?
e__""_]o
嵌套触发器lU-5oqo?
_
触发器最多可以嵌套32层。
如果一个触发器更改了包含另一个触发器的表,则第二个触发器将激活,然后该触发器可以再调用第三个触发器,依此类推。
如果链中任意一个触发器引发了无限循环,则会超出嵌套级限制,从而导致取消触发器。
若要禁用嵌套触发器,请用sp_configure将nestedtriggers选项设置为0(关闭)。
默认配置允许嵌套触发器。
如果嵌套触发器是关闭的,则也将禁用递归触发器,与sp_dboption的recursivetriggers设置无关。
_~i_c8SQz_
whF7D__F{
延迟名称解析f_;(HCJ_Tb
SQLServer允许Transact-SQL存储过程、触发器和批处理引用编译时不存在的表。
这种能力称为延迟名称解析。
但是,如果Transact-SQL存储过程、触发器或批处理引用在存储过程或触发器中定义的表,则只有当兼容级别设置(通过执行sp_dbcmptlevel设置)等于65时,才会在创建时发出警告。
如果使用批处理,则在编译时发出警告。
如果引用的表不存在,将在运行时返回错误信息。
有关更多信息,请参见延迟名称解析和编译。
82ONJv_
8&X9UY)UN
权限c$8~-_MHY
CreateTRIGGER权限默认授予定义触发器的表所有者、sysadmin固定服务器角色成员以及db_owner和db_ddladmin固定数据库角色成员,并且不可转让。
_Ml1
3_CF?
s{/_;3w*6*
若要检索表或视图中的数据,用户必须在表或视图中拥有Select语句权限。
若要更新表或视图的内容,用户必须在表或视图中拥有Insert、Delete和Update语句权限。
2s_5
G]__
__hrTab_2<
如果视图中存在INSTEADOF触发器,用户必须在该视图中有Insert、Delete和Update特权,以对该视图发出Insert、Delete和Update语句,而不管实际上是否在视图上执行了这样的操作。
ulZb_sR_bh
_)18__PB4
示例6