代码之家  ›  专栏  ›  技术社区  ›  Laramie

从INSTEAD OF触发器获取行计数

  •  6
  • Laramie  · 技术社区  · 14 年前

    遗留应用程序使用instead of触发器在表上执行插入,然后使用行数进行进一步处理。

    我们现在需要使用 INSTEAD OF 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
    

    一些插入语句可能是

    --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,这让我很困扰。我找不到关于这个问题的任何资料 其他 知识银行。这只是一个 触发器是邪恶的?

    我可以影响@@ROWCOUNT吗?

    2 回复  |  直到 14 年前
        1
  •  3
  •   Lex    14 年前

    某些语句可能会更改触发器内的@@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
    
        2
  •  1
  •   Community Mr_and_Mrs_D    7 年前

    问题

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

    解决方案

    是否得到 @@ROWCOUNT 或者别的什么 触发器,甚至传递信息 作为触发器,有两种方法允许与触发器共享信息:

    我发布了一个使用 CONTEXT_INFO 在DBA.StackExchange上回答相关问题时: Passing info on who deleted record onto a Delete trigger . 在对这个答案的评论中有一个讨论,涉及到围绕着 上下文信息 ,所以我发布了 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
    Final@@ROWCOUNT(我们不想要的):91

    结果:

    感染罗莎芬