【问题标题】:Get ROWCOUNT from INSTEAD OF TRIGGER从 INSTEAD OF TRIGGER 获取 ROWCOUNT
【发布时间】:2011-05-16 09:44:18
【问题描述】:

旧版应用使用代替触发器对表执行 INSERT,然后使用行数进行进一步处理。

我们现在需要使用INSTEAD OF INSERT 触发器来选择退出某些 INSERT。

问题是@@ROWCOUNT 仍然返回尝试插入的数量。

例如,一个永远不会完成插入的虚构触发器可能是

ALTER TRIGGER [dbo].[trig_ACCOUNT_CREDITS_RunningTotalINSERT]
   ON  [dbo].[ACCOUNT_CREDITS] 
   INSTEAD OF INSERT
AS 
BEGIN
 --tried with NOCOUNT ON and OFF
 SET NOCOUNT OFF;

 --This is an example of the branching logic that might determine 
 --whether or not to do the INSERT
IF 1=2 --no insert will ever occur (example only)
BEGIN
    INSERT INTO dbo.ACCOUNT_CREDITS (COL1, COL2)
    SELECT COL1, COL2 from INSERTED
END
END

有些 INSERT 语句可能是

--No rows will be inserted because value of COL1 < 5
INSERT INTO dbo.ACCOUNT_CREDITS (COL1, COL2) VALUES ( 3, 3)

--We would assume row count to be 0, but returns 1
select @@ROWCOUNT

--No rows will be inserted because value of COL1 < 5       
INSERT INTO dbo.ACCOUNT_CREDITS (COL1, COL2) 
SELECT 1, 1
union all
SELECT 2, 2

--We would assume row count to be 0, but returns 2
select @@ROWCOUNT

我可以解决这个问题,但我无法信任 @@ROWCOUNT 让我很困扰。我在 SO 或那些 other 知识库中找不到有关此问题的参考。这仅仅是 TRIGGERS ARE EVIL 的一个例子吗?

我可以影响@@ROWCOUNT 吗?

【问题讨论】:

  • 我的意思是决定是否实际进行 INSERT。根据 INSERTED TABLE 的值,可能不会发生 INSERT。我会更新我的问题,以便更清楚。
  • 当你有一个 INSTEAD OF 触发器,你试图通过使用另一个 INSTEAD OF 触发器来覆盖它的动作时,我的直觉反应是你在触发器中有太多的逻辑,你可能已经被数据库的黑暗面吸引。那就是疯狂。回头,回头,在为时已晚之前!啊啊啊啊!邪神!!! (别问我是怎么知道的……)
  • @Bob。我喜欢“放弃所有希望”的情绪,并能清晰地听到你的声音。在这种情况下,我正在查看的是单个触发器,它可能会也可能不会根据“东西”进行插入。仍然很邪恶,但为什么我无法获得准确的行数?
  • 听起来像是阻抗不匹配。换句话说,您对数据库服务器的期望和期望与服务器实际所做的并不完全匹配。正如您所指出的,@@ROWCOUNT 正在计算尝试次数(我猜这是您的代码实际发出的 INSERT 次数),而不是在触发器执行期间发生的成功次数。如果可能的话,您最好进行一些重构以删除触发器。触发器并不邪恶,但它们可以在你最不期望的时间和地点咬你。以我的经验,“那个触发器是最好的,它做的最少”。

标签: sql sql-server sql-server-2008 triggers


【解决方案1】:

某些语句可能会更改触发器内的@@ROWCOUNT。

声明

SELECT * FROM INSERTED WHERE COL1 < 5

执行并将@@ROWCOUNT 设置为 1

Put 声明

SET NOCOUNT ON;

然后

IF NOT EXISTS (SELECT * FROM INSERTED WHERE COL1 < 5)
BEGIN
    SET NOCOUNT OFF;

    INSERT INTO dbo.ACCOUNT_CREDITS (COL1, COL2)
    SELECT COL1, COL2 from INSERTED
END

【讨论】:

  • 事实上,触发器中唯一应该影响@@ROWCOUNT 的语句就是插入本身。我根据您的观察更新了示例。 EXISTS 测试中的 SELECT 实际上并未出现在实际语句中。正如我所指出的,我“尝试过开启和关闭 NOCOUNT”。它似乎没有效果。 @@ROWCOUNT 总是报告尝试插入的行数,而不是实际插入的行数。
  • 原来返回给客户端的DONE_IN_PROC值是所有受影响记录的总和。最好的解决方案是在执行更新的过程中设置 NOCOUNT ON,然后在触发器本身中设置 NOCOUNT OFF。这将返回触发器插入的实际记录数。您的答案与我要找的很接近。谢谢:)
  • @Laramie 和 Lex:我知道 4 年前有人问过这个问题,但是如果您仍然对答案感兴趣,实际上有一种更直接的方式可以传递这个(和其他)信息。请看我刚刚发布的答案:)。
【解决方案2】:

问题

我需要仅在触发器上下文中可用的主进程上下文中的信息。

解决方案

无论是从触发器获取@@ROWCOUNT 或任何其他,甚至将信息传递触发器,有两种方法可以与触发器共享信息:

我在 DBA.StackExchange:Passing info on who deleted record onto a Delete trigger 的一个相关问题的答案中发布了一个使用 CONTEXT_INFO 的示例。 cmets 中讨论了与 CONTEXT_INFO 周围可能出现的并发症有关的答案,因此我使用临时表在该问题上发布了 another answer

由于该示例处理发送信息触发器,下面是一个获取信息的示例触发器,因为这就是这个问题的意义:

首先:创建一个简单的表格

CREATE TABLE dbo.InsteadOfTriggerTest (Col1 INT);

第二:创建触发器

CREATE TRIGGER dbo.tr_InsteadOfTriggerTest
   ON dbo.InsteadOfTriggerTest
   INSTEAD OF INSERT
AS
BEGIN
   PRINT 'Trigger (starting): ' + CONVERT(NVARCHAR(50), @@ROWCOUNT);

   SET NOCOUNT ON; -- do AFTER the PRINT else @@ROWCOUNT will be 0

   DECLARE @Rows INT;
   INSERT INTO dbo.InsteadOfTriggerTest (Col1)
      SELECT TOP (5) ins.Col1
      FROM inserted ins;

   SET @Rows = @@ROWCOUNT;
   PRINT 'Trigger (after INSERT): ' + CONVERT(NVARCHAR(50), @Rows);

   -- make sure temp table exists; no error if table is missing
   IF (OBJECT_ID('tempdb..#TriggerRows') IS NOT NULL)
   BEGIN
      INSERT INTO #TriggerRows (RowsAffected)
      VALUES (@Rows);
   END;
END;

第三次:进行测试

SET NOCOUNT ON;

IF (OBJECT_ID('tempdb..#TriggerRows') IS NOT NULL)
BEGIN
    DROP TABLE #TriggerRows;
END;
CREATE TABLE #TriggerRows (RowsAffected INT);

INSERT INTO dbo.InsteadOfTriggerTest (Col1)
   SELECT so.[object_id]
   FROM   [master].[sys].[objects] so;

PRINT 'Final @@ROWCOUNT (what we do NOT want): ' + CONVERT(NVARCHAR(50), @@ROWCOUNT);

SELECT * FROM #TriggerRows;

输出(在消息选项卡中):

触发器(开始):91
触发器(插入后):5
最终的@@ROWCOUNT(我们不想要的):91

结果:

受影响的行
5

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-03-05
    • 2022-12-01
    • 2022-12-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-04
    相关资源
    最近更新 更多