插入同一个表时有两个触发器

时间:2010-07-16 20:40:00

标签: sql sql-server

这是一个非常有趣的问题。我正在使用SQL Server 2008。 我在一个公用表上有两个触发器说'CommonTable'。一个触发器正在更新,另一个触发器在插入/更新/删除。

  • 在第一个触发器“Trigger1”中,我会进行检查/回滚,有时根据业务逻辑更改新插入的值。 这是示例代码

-

CREATE TRIGGER [dbo].[Trigger1] ON [dbo].[CommonTable]
FOR UPDATE
UPDATE [CommonTable] 
SET 
    [StatusCode] = 'New Value'
WHERE 
[RecId] = 'rec id value'
  • 在第二个触发器“Trigger2”中,我将新的插入/删除/更新值从“CommonTable”表存储到另一个表“CommonTable_History”以进行历史记录跟踪。 这是示例代码

-

CREATE TRIGGER [dbo].[Trigger2] ON [dbo].[CommonTable]
FOR INSERT, UPDATE, DELETE

--based on logic read the value from DELETED or INSERTED table and store in other table.

SELECT @RowData = (SELECT * FROM DELETED AS [CommonTable] WHERE [RecId] = @RowRecId FOR XML AUTO,                       BINARY BASE64 , ELEMENTS)

--and then insert @RowData in 'CommonTable_History' table.

在'sp_settriggerorder'的帮助下,我已经设置了这些触发器的执行顺序,因此首先执行“Trigger1”,然后执行“Trigger2”。

第二个触发器“Trigger2”适用于插入/删除值。如果第一次触发“Trigger1”没有更改新的插入值,它对新的插入值工作正常。

但是,如果在某些情况下,插入的值已在“Trigger1”中更改。说[StatusCode] ='新值',旧值为'旧值',然后“Trigger2”仍然存储'旧值'而不是'新值'。 为什么因为“Trigger1”更改了值,但该值仍未存储在数据库中,并且在“Insert”上执行“Trigger2”之前。 现在我的要求是,在这里我要存储“新价值”。

所以我想,让“Trigger2”使用“AFTER”关键字。但“FOR”和“AFTER”表现相同并不能解决问题。

然后我想,让“Trigger2”使用“INSTEAD OF”关键字。但是“INSTEAD OF”会出现以下错误 “无法创建删除的INSTEAD或更新TRIGGER。这是因为该表有一个带有级联DELETE或UPDATE的FOREIGN KEY。”

对于表'CommonTable',我无法删除带有级联DELETE或UPDATE的FOREIGN KEY。

如果您的人有任何其他替代解决方案,请告诉我。 -Vikram Gehlot

3 个答案:

答案 0 :(得分:3)

我认为你的第二个触发器需要使用实际表中的值,而不是插入/删除的表来填充日志表 - 插入/删除的表将始终具有未更改的原始值,而您的更改值将出现在表。使第二个触发器成为“After”触发器,因此您不必使用sp_settriggerorder。像这样,例如:

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TRIGGER [dbo].[trg_Trig1] 
   ON  [dbo].[TestTable] 
   FOR INSERT
AS 
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;

    update TestTable
    set [value] = 10
    where [value] = 25

END

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TRIGGER [dbo].[trg_Trig2]
   ON  [dbo].[TestTable] 
   AFTER INSERT
AS 
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;

    -- Insert statements for trigger here
    insert into log_TestTable
    (id, description, [value])
    select tt.id, tt.description, tt.[value]
    from inserted i
        LEFT JOIN TestTable tt
            ON tt.id = i.id

END

答案 1 :(得分:2)

它可能不是最干净的解决方案,但您可以简单地将两个触发器组合成一个吗?这样,两段SQL都可以了解彼此的变化。

答案 2 :(得分:0)

你的第二个触发器在我看来好像它不能正常工作是多个记录被插入到基于集合的操作中,如果你使用一个在触发器中选择不好的循环。先解决这个问题!

不是select * from deleted,为什么不将已删除或插入的表连接到原始表并从那里获取值(除了从删除或插入中获得的id值,它应该为您提供最新值所有文件中的文件,如果你添加其他触发逻辑,以后不会破坏。