UPDATE和INSERT只应触发一次触发器

时间:2015-02-04 13:28:33

标签: sql sql-server tsql triggers

有没有办法以一种只触发一次触发器的方式组合更新和插入语句?

我有一个具有(当前需要)触发器AFTER INSERT, UPDATE, DELETE的特定表。现在我想更新一行并插入另一行,并且只触发一次触发器。

这一切都可能吗?

我已经尝试过MERGE-Statement但没有成功:触发器会在更新时触发一次,对插入部件触发一次。

2 个答案:

答案 0 :(得分:1)

嗯,问题解决了我。我没有找到将语句组合成触发器的一个fire-event的方法。但是触发器以一种有趣的方式运行,这对我来说已经足够了:对触发器的两次调用都已经可以访问完全更新的数据。

只需执行以下语句,您就会明白我的意思。

CREATE TABLE Foo (V INT)
GO
CREATE TRIGGER tFoo ON Foo AFTER INSERT, UPDATE, DELETE
AS
  SELECT 'inserted' AS Type, * FROM inserted
  UNION ALL
  SELECT 'deleted', * FROM deleted
  UNION ALL
  SELECT 'actual', * FROM Foo
GO
DELETE FROM Foo
INSERT Foo VALUES (1)
;MERGE INTO Foo
  USING (SELECT 2 AS V) AS Source ON 1 = 0
  WHEN NOT MATCHED BY SOURCE THEN DELETE
  WHEN NOT MATCHED BY TARGET THEN INSERT (V) VALUES (Source.V);

结果,MERGE将调用两次触发器。但这两次," SELECT * FROM Foo"已经提供了完全更新的数据:将有一行值为2.值1已被删除。

这让我感到很惊讶:在调用delete-trigger之前,先调用insert-trigger并删除已删除的行。

仅插入"的值"和"删除"对应于delete-或insert-statement。

答案 1 :(得分:0)

您可以尝试这样的事情:

触发器将检查是否存在#temp表。

如果它不存在,则使用虚拟数据创建它。然后,它检查最近的值是否包含现在正在运行的相同用户(SPID)以及上次触发的时间是否在20秒内。

如果这些都是真的那么它将PRINT 'Do Nothing'并删除表,否则它将执行你的触发器声明。 在触发器语句结束时,它会在表中插入SPID和当前日期时间。

此临时表应该与SPID连接一样长,如果您希望它持续更长时间使其成为## temp或真实表。

IF OBJECT_ID('tempdb..#temp') IS NULL
begin
Create table #temp(SPID int, dt datetime)
insert into #temp values (0, '2000-01-01')
end

If @@SPID = (select top 1 SPID from #temp order by dt desc) 
and Convert(datetime,Convert(varchar(19),GETDATE(),121)) between 
Convert(datetime,Convert(varchar(19),(Select top 1 dt from #temp order by dt desc),121)) and 
Convert(datetime,Convert(varchar(19),DateAdd(second, 20, (select top 1 dt from #temp order by dt desc)),121))
    begin
    PRINT 'Do Nothing'
    Drop table #temp
    end
    else
    begin
    --trigger statement

    Insert into #temp values (@@SPID, GETDATE())
    end