【问题标题】:How to test for multiple row actions in a SQL Server trigger?如何测试 SQL Server 触发器中的多行操作?
【发布时间】:2009-01-02 20:25:13
【问题描述】:

我幼儿园的 SQL Server 告诉我,在插入和删除的伪表中可能会触发多行触发器。我在编写触发代码时大多考虑到这一点,通常会导致一些基于光标的混乱。现在我真的只能测试它们一次发射一行。如何生成多行触发器,SQL Server 是否真的会发送多行触发器?我可以设置一个标志,让 SQL Server 只触发单行触发器吗?

【问题讨论】:

    标签: sql-server database


    【解决方案1】:

    触发器定义应始终处理多行。

    取自SQLTeam

    -- BAD Trigger code following:
    
    CREATE TRIGGER trg_Table1 
    ON Table1 
    For UPDATE
    AS
    DECLARE @var1 int, @var2 varchar(50)
    
    SELECT @var1 = Table1_ID, @var2 = Column2
    FROM inserted
    
    UPDATE Table2
    SET SomeColumn = @var2
    WHERE Table1_ID = @var1
    

    上述触发器只对插入表的最后一行起作用。

    这就是你应该如何实现它:

    CREATE TRIGGER trg_Table1 
    ON Table1 
    FOR UPDATE
    AS
    
    UPDATE t2
    SET SomeColumn = i.SomeColumn
    FROM Table2 t2
    INNER JOIN inserted i
    ON t2.Table1_ID = i.Table1_ID
    

    【讨论】:

    • SET SomeColumn = t1.SomeColumn 好像写错了,别名t1 定义在哪里?尽管如此 +1,因为现在我明白为什么我的触发器只针对最后插入的行触发。
    • @Tim:抱歉,打错了。已更新。
    【解决方案2】:

    是的,如果一条语句影响多行,它应该由单个触发器调用处理,因为您可能希望恢复整个事务。不可能在逻辑上将其拆分为单独的触发器调用,我认为 SQL Server 不提供这样的标志。您可以通过发出影响多行的 UPDATE 或 DELETE 语句来使 SQL Server 调用具有多行的触发器。

    【讨论】:

    • 我会进一步说,您的触发器应该始终考虑多行,无论您是否希望以这种方式调用它们。
    • 戴夫,绝对的。我只是想澄清为什么这样的事情在逻辑上不应该是可能的。触发器应该知道“一次”发生的整个事件,如果它对每一行都运行,这是不可能的。如果触发器很昂贵,DELETE MyTable 语句也将永远占用
    • @Dave Markle:完全同意。如果可以的话,我会投票赞成你的评论!
    【解决方案3】:

    首先让我担心的是,您正在使用游标使触发器处理多行。不要那样做!使用基于集合的语句来代替插入或删除的伪表。在我来这里工作之前,有人将其中一个基于光标的触发器放在我们的数据库中。处理 400,00 条记录插入需要 40 多分钟(而且我经常需要为一个客户在此表中插入超过 100,000 条记录)。将其更改为基于集合的解决方案将时间更改为不到一分钟。虽然所有触发器都必须能够处理多行,但您绝不能通过制造性能噩梦来做到这一点。

    如果您可以为 cusor 编写 select 语句,则可以基于相同的基于 set 的 select 语句编写插入、更新或删除。

    【讨论】:

    • 我需要在触发器触发后在 3 个不同的地方(触发器)执行相同的更新集。出于可维护性的原因,我将所有更新都放入一个 SP 中,并让触发器调用该过程。所以我需要一个游标,以防多行更新......:|
    • 您可以编写一个使用表变量作为输入变量并执行基于集合的工作的存储过程。在任何情况下都不要在触发器中使用光标。
    • 此外,性能远比可维护性更重要。可维护性永远不应该胜过性能。
    【解决方案4】:

    我一直编写触发器来处理多行,我的理解是,如果一个查询插入/更新/删除多行,那么只有一个触发器会触发,因此您必须使用游标来移动一个一个的记录。

    【讨论】:

    • 不要在触发器中使用游标,而是使用基于集合的语句,
    【解决方案5】:

    一个 SQL 语句总是调用一个触发器执行 - 这是触发器定义的一部分。 (这也是一种情况,似乎每个编写触发器的人都至少有一次绊倒。)我相信您可以通过检查 @@ROWCOUNT 发现有多少记录受到影响。

    【讨论】:

      猜你喜欢
      • 2013-04-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多