数据库触发器:插入时

Posted

技术标签:

【中文标题】数据库触发器:插入时【英文标题】:Database Triggers: On Insert 【发布时间】:2011-11-23 12:14:57 【问题描述】:

这是一个简单的例子。

我想在Table1 (Name, Age, Sex) 中插入数据。该表在插入数据时会自动增加serial#(int)。

我想在Table1 insert 上放置一个触发器,以便在插入数据后,它会从Table1 中提取serial#(int) 并将Serial#Name 放入Table2 和@987654329 @ 和 some other data 中的 Table3

可以通过触发器实现吗?

或者,我应该从table1 中选择(最后一个)Serial 并通过手动增加它来调用其他表上的插入,在我曾经插入Table1 的同一SP 中?

哪种方法更好?

编辑 1: 假设表:

Serial | UID | Name | Age | Sex | DateTimeStamp
(int | uniqueidentifier | nvarchar | smallint | nchar | DateTime ) 

默认NewID() 和默认GetDate() 作为UIDDateTimeStampINSERTED 表会在 DatetimeStamp 字段中具有 Datetime-Of-Insertion 吗?意思是,我最初没有输入任何 Serial、GUID 或 DatetimeStamp,它们会出现在 INSERTED 表中吗? 编辑2: 你能给我指点关于触发器的好书/文章吗?我读了mastering SQL server 2005,并没有从中得到太多。谢谢!

【问题讨论】:

YES - 您的INSERTED将具有这些值! 【参考方案1】:

当然,您可以使用触发器来执行此操作 - 类似于:

CREATE TRIGGER trg_Table1_INSERT
ON dbo.Table1 AFTER INSERT 
AS BEGIN
   INSERT INTO dbo.Table2(SerialNo, Name)
      SELECT SerialNo, Name
      FROM Inserted

   INSERT INTO dbo.Table3(SomeOtherCol)
      SELECT SomeOtherCol
      FROM Inserted
END

或者你需要在这里做的任何事情......

重要的是要了解触发器将被调用每个语句一次 - 而不是每插入行一次。因此,如果您有一个插入 10 行的语句,您的触发器将被调用一次,伪表 Inserted 将包含已插入语句中的这 10 行。

【讨论】:

所以,T1 将有 10 行,INSERTED 将有 10 行,但 T2 和 T3 不会?你说的是这个吗? @AnubhavSaini:是的,是的,不是的。是的,Table1 将有 10 行,因此,Inserted 将有 10 行。您需要考虑到这一点,例如您需要知道并相应地进行编程(许多开发人员总是假设Inserted 中只有一行)。不 - 使用我上面的代码,Table2Table3获得 10 个新行! @marc_s 只是为了清楚起见,每个语句调用一次触发器,而不是每个批处理一次(除非可能是这种情况,批处理只是一个语句) @RalphShillington:抱歉 - 是的,你是对的 - 每个语句一次。最重要的是:不是每行一次!对于许多总是认为Inserted 只是单行并执行SELECT FROM Inserted..... 并因多行而失败的人来说,这就是“杀手” @marc_s,每次在Table1中插入都会将所有行从Inserted into Table2插入(INSERT INTO dbo.Table2(SerialNo, Name) SELECT SerialNo, Name FROM Inserted),这个不能接受! 【参考方案2】:

是的,这可以通过触发器实现。

当您使用INSERT 触发器时,您可以访问表示要插入的行的INSERTED 逻辑表,其中包含新ID 的值。

【讨论】:

【参考方案3】:

是的,可以通过触发器来实现,但请记住,TRIGGER 不接受任何输入,也不提供任何输出,因此您只能通过在触发器中查询来收集所需的数据,但要满足插入到你的 Table2 和 Table3

CREATE TRIGGER tr_YourDesiredTriggerName ON Table1
 FOR INSERT
 AS
 BEGIN
    -- Inserting data to Table2
INSERT INTO Table2( Serial, Name) 
   SELECT i.Serial, i.Name 
       FROM Table1 AS t1 INNER JOIN Inserted AS i ON t1.Serial = i.Serial
       AND i.Serial NOT IN  ( SELECT t2.Serial FROM Table2 AS t2 )

    -- Inserting data to Table3     
INSERT INTO Table3( Serial, OtherData)  -- select from other table
   SELECT i.Serial, OtherData
       FROM OtherTable AS ot INNER JOIN Inserted AS i ON ot.Serial = i.Serial
       AND i.Serial NOT IN ( SELECT t3.Serial FROM Table3 AS t3 )
END

【讨论】:

【参考方案4】:

如果您无法控制插入源,请使用触发器。如果您确实可以控制插入源,则可以修改插入过程以添加辅助表行。

您还可以控制未来的插入吗?如果为这个表创建了另一个插入怎么办?如果您使用触发器,那么辅助插入也将自动处理。如果不是,那么第二次插入过程可能会省略第二次插入。根据您的应用程序,这可能是好是坏。

【讨论】:

以上是关于数据库触发器:插入时的主要内容,如果未能解决你的问题,请参考以下文章

是否可以创建一个触发器,该触发器在将记录插入一个数据库但最终插入另一个数据库时执行?

插入时多个数据库触发器

触发器-当一个表更新时,将数据插入另一张表中

触发器 当往一个表中插入数据时,更新另一个表,报语法错误...

Oracle触发器修改数据时同步执行插入该条数据

触发错误:ORA-01403 插入时找不到数据