回答

收藏

防止相互递归执行触发器?

技术问答 技术问答 308 人阅读 | 0 人回复 | 2023-09-14

假设您有表格Presentations和Events。保存演示文稿并包含基本事件信息(如位置和日期)后,将使用触发器自动创建事件。(由于技术原因,恐怕不可能仅将数据保存在一个位置并使用视图。)此外,在稍后的演示中更改此信息时,触发器也会将更新复制到事件中,像这样:5 X4 I' ~, \/ E
CREATE TRIGGER update_presentations1 t& o- N+ |( |% I; P
ON Presentations
/ `) H9 _5 f) [- }# H" gAFTER UPDATE
; G* w" N7 Q: N4 x9 z& pAS
+ o3 _- @" j& L0 {4 ABEGIN
0 i' {% K* g& G    UPDATE Events
6 ?2 j2 U" ]/ {' n: z' M2 j    SET Events.Date = Presentations.Date,
& I0 \( H  Y9 r; R5 n" C        Events.Location = Presentations.Location7 L8 R0 X& p9 N6 X5 B
    FROM Presentations INNER JOIN Events ON Presentations.EventID = Events.ID
; g: x' z$ k: e    WHERE Presentations.ID IN (SELECT ID FROM inserted). h; ~- C. s, ?, d0 r! n
END
2 h# X8 u' J2 A. U) f现在,客户需要它,这样,如果用户更改了 事件中 的信息,它也应该返回到演示。出于明显的原因,我不能相反:& a3 L% h, \. E+ _- D
CREATE TRIGGER update_events3 E7 v- o9 R- T1 H, x+ r6 b& ~
ON Events
$ z# I8 q& t3 m$ I) k: ~, tAFTER UPDATE
; @" f: k0 W5 V" j3 d  ^AS
# Y/ _! ~$ ^. JBEGIN
6 W( q0 U& [! |5 U    UPDATE Presentations
# r; Q& I: c+ K/ `    SET Presentations.Date = Events.Date,% }& `, e# A+ K- N" D
        Presentations.Location = Events.Location
+ C+ j& t' q+ F6 P    FROM Events INNER JOIN Presentations ON Events.PresentationID = Presentations.ID
$ e  N, a% d1 |0 M8 f    WHERE Events.ID IN (SELECT ID FROM inserted)
( \/ ^) U* C3 L2 B) O: SEND
  d  S+ I# m8 i' Z( Y毕竟,这将导致每个触发器彼此触发。我可以做的是last_edit_by在两个表中添加一列,其中包含一个用户ID。如果触发器用特殊的无效ID填充(例如,通过使实际人员的所有用户ID为正,而使脚本的用户ID为负),则可以将其用作退出条件:
' t1 {4 f$ I/ A& ~) G    AND last_edit_by >= 00 E9 a, k. }! Y# B
这可能有效,但是我想做的是向SQL Server指示,在事务中,触发器应该只触发一次。有办法检查吗?还是要检查表是否已被触发器影响?. e9 d2 e$ U3 X

' M$ }3 d+ B7 E6 r 感谢史蒂夫罗宾斯:7 u+ B6 t" D$ Z1 w
只需将可能嵌套的UPDATE语句包装在IF条件中检查即可trigger_nestlevel()。例如:5 f3 r& H# B7 A% h5 R  u, M
CREATE TRIGGER update_presentations
! J2 t" V; O2 b7 O2 ~8 |- ^2 HON Presentations
6 g6 B0 }! W: I3 tAFTER UPDATE
% L. `$ S; y! n, v7 A4 {9 uAS8 j& G4 g- Z  ^5 G! ~1 L
BEGIN0 Q0 H& V4 P' I3 V& x
    IF trigger_nestlevel() 请注意,这trigger_nestlevel()似乎是从1开始的,而不是从0开始的。如果您希望两个触发器中的每个触发器执行一次,但不更频繁地执行,则只需检查trigger_nestlevel()
! @  v# e" L+ Z8 j$ i5 d
9 n  \6 m7 t& D               
# ^9 V( X; \% [9 M: v解决方案:
0 J( e+ Z* j- z6 v& _! x. G                & C, L+ ?' s. _; R2 }7 {8 ^" {# f/ ~# s
6 ]1 C& b! q# z/ ^% `" S! C

0 a% Z- @: ^1 c" C, r                我不确定是否要在每个事务中执行此操作,但是是否需要为其他部分打开嵌套触发器?如果您在服务器上关闭它们,则不会从另一个更新表的触发器中触发一个触发器。
+ y% |+ I/ |* `6 p8 R5 }8 Y2 |( N编辑(评论的答案): 您将需要更改触发器A才能使用 TRIGGER_NESTLEVEL
分享到:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则