从INSTEAD OF TRIGGER获得ROWCOUNT

时间:2010-11-26 23:16:16

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

遗留应用程序使用而不是触发器对表执行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或其他其他知识库中找不到这个问题的参考。这只是 TRIGGERS EVIL的情况吗?

我可以影响@@ ROWCOUNT吗?

2 个答案:

答案 0 :(得分:3)

某些陈述可能会在触发器内改变@@ ROWCOUNT。

声明

SELECT * FROM INSERTED WHERE COL1 < 5

执行并将@@ ROWCOUNT设置为1

发表声明

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

答案 1 :(得分:1)

问题

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

解决方案

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

我在DBA.StackExchange:Passing info on who deleted record onto a Delete trigger的相关问题的答案中发布了一个使用CONTEXT_INFO的示例。关于该问题的评论中有关于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
  触发(INSERT后):5
  最终@@ ROWCOUNT(我们不想要的):91

结果:

  

的RowsAffected
  5