AFTER INSERT触发器导致查询执行挂起

时间:2017-12-11 17:57:52

标签: tsql sql-server-2012 triggers

在ms sql数据库中,我有一个名为 combo 的表,其中可能发生多次插入,更新和删除(当然还有单个)。在另一个名为 migrimi_temp 的表中,我以查询的形式跟踪这些更改(查询必须在mysql中执行才能获得相同的结果)。

例如,如果对id> gt的所有行执行删除查询50,触发器应激活以将以下查询存储到日志表中:

  

DELETE FROM combo,其中id> 50;

因此,组合表中的这一个删除查询将导致日志表中的一行。

但是,如果我有插入2行的插入查询,则应激活触发器以将每个插入存储到日志表中。因此,组合表中的这一个插入查询将导致日志表中的2个新行。

我打算在单独的触发器中处理插入,更新和删除操作。我曾设法为单行插入/更新/删除编写触发器。然后我发现可能还会执行多个操作。

这是我尝试在一个查询中处理多个插入的情况。在没有光标的情况下无法调整初始触发器后,我使用了游标。触发器成功执行,但是当我执行插入(单行或多行)时,执行会无限期挂起,或者至少比合理时间长。

USE [migrimi_test]
GO
/****** Object:  Trigger [dbo].[c_combo]    Script Date: 12/11/2017 5:33:46 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
create TRIGGER [dbo].[u_combo]
ON [migrimi_test].[dbo].[combo]
AFTER INSERT
AS
BEGIN

    SET NOCOUNT ON
    DECLARE @c_id INT;
    DECLARE @c_name nvarchar(100);
    DECLARE @c_duration int;
    DECLARE @c_isavailable INT;

    DECLARE c CURSOR FOR
      SELECT id, name, duration, isvisible FROM inserted
    OPEN c
    FETCH NEXT FROM c INTO @c_id, @c_name, @c_duration, @c_isavailable
    WHILE @@FETCH_STATUS = 0

    INSERT INTO [migrimi_temp].[dbo].[sql_query] (query)
    VALUES ('INSERT INTO combo (id, name, duration, value, isavailable, createdAt, updatedAt) values ('+CAST(@c_id as nvarchar(50))+', '+'"'+@c_name+'"'+', 
    '+CAST(@c_duration as nvarchar(50))+', 1, '+CAST(@c_isavailable as nvarchar(50))+', Now(), Now());' )

    FETCH NEXT FROM c INTO @c_id, @c_name, @c_duration, @c_isavailable
    CLOSE c
    END
    DEALLOCATE c

GO

SQL服务器版本是2012.操作系统是Windows Server 2008(尽管我怀疑这是相关的)。我主要基于这两个资源:https://social.msdn.microsoft.com/Forums/sqlserver/en-US/40f5635c-9034-4e9b-8fd5-c02cec44ce86/how-to-let-trigger-act-for-each-row?forum=sqlgetstarted

How can I get a trigger to fire on each inserted row during an INSERT INTO Table (etc) SELECT * FROM Table2?

这是我想要完成的更大想法的一部分,直到2天前我对触发器完全不熟悉。我正在努力平衡学习与在合理的时间内完成,但没有做得那么好

1 个答案:

答案 0 :(得分:0)

在SQL Server中,游标的速度非常慢。 您可以使用insert...select这是一种基于集合的方法,而不是使用游标在已插入的表上循环。它更快,是推荐的SQL工作方式:

CREATE TRIGGER [dbo].[u_combo]
ON [migrimi_test].[dbo].[combo]
AFTER INSERT
AS
BEGIN

    INSERT INTO [migrimi_temp].[dbo].[sql_query] (query)
    SELECT 'INSERT INTO combo (id, name, duration, value, isavailable, createdAt, updatedAt) values ('+CAST(id as nvarchar(50))+', "'+ name +'", 
        '+ CAST(duration as nvarchar(50)) +', 1, '+ CAST(isvisible as nvarchar(50))+ ', Now(), Now());'
    FROM inserted    

END

GO