如果一个触发器在执行操作时引发了另一个触发器,而这个触发器又接着引发下一个触发器……这些触发器就是嵌套触发器。触发器可嵌套至 32 层,并且可以控制是否可以通过"嵌套触发器"服务器配置选项进行触发器嵌套。
如果允许使用嵌套触发器,且链中的一个触发器开始一个无限循环,则超出嵌套级,而且触发器将终止。
可使用嵌套触发器执行一些有用的日常工作,如保存前一触发器所影响行的一个备份。例如,可以在 titleauthor 上创建一个触发器,以保存由 delcascadetrig 触发器所删除的 titleauthor 行的备份。在使用 delcascadetrig 时,从 titles 中删除title_id PS2091 将删除 titleauthor 中相应的一行或多行。要保存数据,可在 titleauthor 上创建 DELETE 触发器,该触发器的作用是将被删除的数据保存到另一个单独创建的名为 del_save
不推荐按依赖于顺序的序列使用嵌套触发器。应使用单独的触发器层叠数据修改。
说明
递归触发器
触发器不会以递归方式自行调用,除非设置了 RECURSIVE_TRIGGERS 数据库选项。有两种不同的递归方式:
- 直接递归即触发器激发并执行一个操作,而该操作又使同一个触发器再次激发。例如,一应用程序更新了表T3,从而引发触发器 Trig3。Trig3 再次更新表 T3,使触发器 Trig3
- 间接递归即触发器激发并执行一个操作,而该操作又使另一个表中的某个触发器激发。第二个触发器使原始表得到更新,从而再次引发第一个触发器。例如,一应用程序更新了表T1,并引发触发器 Trig1。Trig1 更新表 T2,从而使触发器 Trig2 被引发。Trig2 转而更新表 T1,从而使 Trig1
当将 RECURSIVE_TRIGGERS 数据库选项设置为 OFF 时,仅防止直接递归。若要也禁用间接递归,请将 nested triggers
示例
A. 使用递归触发器解决自引用关系
递归触发器的一种用法是用于带有自引用关系的表(亦称为传递闭包)。例如,表 emp_mgr
- 一个公司的雇员 (emp)。
- 每个雇员的经理 (mgr)。
- 组织树中向每个经理汇报的雇员总数 (NoOfReports)。
递归 UPDATE 触发器在插入新雇员记录的情况下可以使 NoOfReports 列保持最新。INSERT 触发器更新经理记录的 NoOfReports 列,而该操作递归更新管理层向上其它记录的 NoOfReports 列。
1
USE
pubs
2
GO
3
--
Turn recursive triggers ON in the database.
4
ALTER
DATABASE
pubs
5
SET
RECURSIVE_TRIGGERS
ON
6
GO
7
CREATE
TABLE
emp_mgr (
8
emp
char
(
30
)
PRIMARY
KEY
,
9
mgr
char
(
30
)
NULL
FOREIGN
KEY
REFERENCES
emp_mgr(emp),
10
NoOfReports
int
DEFAULT
0
11
)
12
GO
13
CREATE
TRIGGER
emp_mgrins
ON
emp_mgr
14
FOR
INSERT
15
AS
16
DECLARE
@e
char
(
30
),
@m
char
(
30
)
17
DECLARE
c1
CURSOR
FOR
18
SELECT
emp_mgr.emp
19
FROM
emp_mgr, inserted
20
WHERE
emp_mgr.emp
=
inserted.mgr
21
22
OPEN
c1
23
FETCH
NEXT
FROM
c1
INTO
@e
24
WHILE
@@fetch_status
=
0
25
BEGIN
26
UPDATE
emp_mgr
27
SET
emp_mgr.NoOfReports
=
emp_mgr.NoOfReports
+
1
--
Add 1 for newly
28
WHERE
emp_mgr.emp
=
@e
--
added employee.
29
30
FETCH
NEXT
FROM
c1
INTO
@e
31
END
32
CLOSE
c1
33
DEALLOCATE
c1
34
GO
35
--
This recursive UPDATE trigger works assuming:
36
--
1. Only singleton updates on emp_mgr.
37
--
2. No inserts in the middle of the org tree.
38
CREATE
TRIGGER
emp_mgrupd
ON
emp_mgr
FOR
UPDATE
39
AS
40
IF
UPDATE
(mgr)
41
BEGIN
42
UPDATE
emp_mgr
43
SET
emp_mgr.NoOfReports
=
emp_mgr.NoOfReports
+
1
--
Increment mgr's
44
FROM
inserted
--
(no. of reports) by
45
WHERE
emp_mgr.emp
=
inserted.mgr
--
1 for the new report.
46
47
UPDATE
emp_mgr
48
SET
emp_mgr.NoOfReports
=
emp_mgr.NoOfReports
-
1
--
Decrement mgr's
49
FROM
deleted
--
(no. of reports) by 1
50
WHERE
emp_mgr.emp
=
deleted.mgr
--
for the new report.
51
END
52
GO
53
--
Insert some test data rows.
54
INSERT
emp_mgr(emp, mgr)
VALUES
(
'
Harry
'
,
NULL
)
55
INSERT
emp_mgr(emp, mgr)
VALUES
(
'
Alice
'
,
'
Harry
'
)
56
INSERT
emp_mgr(emp, mgr)
VALUES
(
'
Paul
'
,
'
Alice
'
)
57
INSERT
emp_mgr(emp, mgr)
VALUES
(
'
Joe
'
,
'
Alice
'
)
58
INSERT
emp_mgr(emp, mgr)
VALUES
(
'
Dave
'
,
'
Joe
'
)
59
GO
60
SELECT
*
FROM
emp_mgr
61
GO
62
--
Change Dave's manager from Joe to Harry
63
UPDATE
emp_mgr
SET
mgr
=
'
Harry
'
64
WHERE
emp
=
'
Dave
'
65
GO
66
SELECT
*
FROM
emp_mgr
67
GO
68
69
以下是更新前的结果:
70
71
emp mgr NoOfReports
72
--
---------------------------- ----------------------------- -----------
73
Alice Harry
2
74
Dave Joe
0
75
Harry
NULL
1
76
Joe Alice
1
77
Paul Alice
0
78
79
以下为更新后的结果:
80
81
emp mgr NoOfReports
82
--
---------------------------- ----------------------------- -----------
83
Alice Harry
2
84
Dave Harry
0
85
Harry
NULL
2
86
Joe Alice
0
87
Paul Alice
0