2016-02-12 48 views
0

我的问题有点理论性,因为我没有任何具体的工作例子。但我认为值得回答。在SQL Server中编写插入触发器的正确​​方法是什么?

什么是在SQL Server中编写插入触发器的正确​​方法?

比方说,我创建像这样(或多或少伪代码)触发

CREATE TRIGGER MY_TRIGGER 
ON MY_TABLE 
FOR INSERT AS 
    DECLARE @myVariable;    
    DECLARE InsertedRows CURSOR FAST_FORWARD FOR SELECT A_COLUMN FROM INSERTED; 

    OPEN InsertedRows; 
    FETCH NEXT FROM InsertedRows INTO @NewOrderCode; 

    ... 

     INSERT INTO ANOTHER_TABLE (     
      CODE, 
      DATE_INSERTED 
     ) VALUES (      
      @myVariable, 
      GETDATE()  
     ); 

    ...etc 

现在,如果别人创建在同一个表的另一触发条件和触发会改变插入的行一些列?这样

CREATE TRIGGER ANOTHER_TRIGGER 
ON MY_TABLE 
FOR INSERT AS 
    UPDATE MY_TABLE 
    SET A_COLUMN = something 
    WHERE ID IN (SELECT ID FROM INSERTED); 

...etc 

然后我的触发(如果另一个触发后被解雇)上的东西不对数据进行操作,因为插入的数据是不一样的,其已经改变与其他触发右表中的实际插入的数据?

总结:

触发器A于表T更新新插入的行,触发器B,则对脏数据进行操作,因为从触发器A中的更新并不在其中触发B操作插入的伪代码表可见。但是如果触发器B直接在工作台上工作而不是在伪表INSERTED上,它会通过触发器A看到更新的数据。

这是真的吗?我是否应该始终使用表中的数据而不是从INSERTED表中处理数据?

回答

0

触发器是事务性的。如果您尝试按照您所描述的方式进行循环更新,则会导致死锁 - 第一次更新会阻止第二次更新完成。

尽管在查看这段代码,但您试图通过INSERTED伪表进行插入来执行插入操作 - 示例中没有任何内容需要该行为。如果你直接从完整的INSERTED表中插入,你会得到一个明显的改进,而且你的第二个触发器的触发次数也会减少。

+0

我不明白。谁被谁拦截?两个触发器都在插入之后。其中之一是更新两个触发器所属的表,第二个插入另一个表。 – Behnil

+0

是的。但第二次写入是由第一次写入触发的,第一次写入在执行时尚未完成其事务。它试图更新的行由原始事务更新,因此被锁定。试图在新的环境中更新它们只会给你一个僵局。 – eftpotrm

+0

但我在触发器中更新。这是否意味着在其表上发生更新时触发后插入触发器? – Behnil

4

我通常会建议不要有多个触发器。如果你愿意的话,你可以用define what order来运行。一旦你有更多的东西,你不能控制非第一个非最后一个触发器的运行顺序。

它也越来越难以推断插入过程中发生了什么。

相反,我建议每个表单执行一次触发器,以完成该操作应发生的所有任务。如果您担心产生的代码的大小,那通常意味着您应该将代码一起移出触发器 - 触发器应该快速且轻松。

相反,您应该开始考虑让触发器记录一个动作,然后使用服务代理或一个SQL Server作业,它可以提取这些记录并执行额外的处理。重要的是,它在自己的交易中做到这一点,而不是延迟原来的INSERT


我还会告诫您不要在示例1中显示的当前代码。考虑编写一个直接引用insertedINSERT ... SELECT语句,并将所有新行插入到另一个表中,而不是使用游标和逐行插入行。

+0

谢谢,我感谢你的回答。但我的问题是关于另一个触发器对其进行操作时由一个触发器更新的数据的脏状态。 – Behnil

+1

@Behnil - 我在说,*合并*这些触发器,以便您不必考虑它们如何独立运作。 –

3

你应该做的一件事绝对避免在触发器中使用的是一个CURSOR

一个触发器应该是非常灵活,小巧,快速 - 和一个游标是什么,但!毕竟,它在交易的上下文中被执行,导致它被触发。不要不必要地延迟完成该交易!

您还需要注意,Inserted包含多个行和编写相应的触发,但使用基于集合的技术 - 而不是光标和while循环 - 让你的触发迅速,快捷。

不要做繁重,耗时的工作在触发器 - 刚刚更新了数列,或者使进入另一个表 - 这很好 - NO繁重!,没有电子邮件发送等!

+0

绝对同意这一点。谢谢。但我的问题是关于另一个触发器对其进行操作时由一个触发器更新的数据的脏状态。 – Behnil

1

我的个人指南SQL触发幸福

  1. 触发要轻,速度快。昂贵的触发器为EVERYBODY缓慢的数据库(并不偶然地包括触发器作者在内的所有人都不满意)
  2. 请您使用一个触发操作表组合。 foo表上最多只有一个插入触发器。尽管在一张桌子上多次操作的触发器不一定是坏的。
  3. 不要忘记,inserteddeleted表可能包含多于一行,甚至根本不包含行。无论操作中涉及多少行,快乐的触发器(更重要的是令人愉快的数据库用户和管理员)将表现良好。
  4. 不是不不是曾经在触发器中使用游标。服务器端游标通常是滥用良好实践,尽管在极少数情况下使用它们是合理的。一个触发器是从来没有其中之一。而是将一系列面向集合的DML语句改为任何类似触发器的语句。
  5. 请记住有两类触发器 - 触发器AFTER和触发器INSTEAD OF。在编写触发器时考虑这一点。
  6. 永远不要忽视那些触发器(AFTERINSTEAD OF)开始执行的时候要比启动它们的语句运行的上下文大@@trancount
  7. 优先于触发器的声明性参照完整性(DRI)作为保持数据库中数据一致的手段。某些应用程序完整性规则需要触发器但是DRI多年来走过了很长的一段路,像row_number()这样的功能使得触发器变得不那么必要。
相关问题