从 INSTEAD OF TRIGGER 获取 ROWCOUNT

发布于 2024-10-04 14:30:39 字数 1232 浏览 0 评论 0原文

旧应用程序使用替代触发器在表上执行 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 或那些其他知识库中找不到任何关于此问题的参考。这只是触发器是邪恶的吗?

我可以影响@@ROWCOUNT吗?

A legacy app does an INSERT on a table with an instead of trigger and subsequently uses the rowcount for further processing.

We now need to opt out of certain INSERTs with the use of an INSTEAD OF INSERT trigger.

The problem is that @@ROWCOUNT still returns the number of attempted inserts.

For example, a fictitious trigger that will never complete an insert might be

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

and some INSERT statements might be

--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

I can work around the issue, but it bothers me that I can't trust @@ROWCOUNT. I can find no reference to this issue on SO or those other knowledge banks. Is this simply a case of TRIGGERS ARE EVIL?

Can I affect @@ROWCOUNT?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

听不够的曲调 2024-10-11 14:30:39

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

执行语句

SELECT * FROM INSERTED WHERE COL1 < 5

并将 @@ROWCOUNT 设置为 1

语句

SET NOCOUNT ON;

Put

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

Some statements may change @@ROWCOUNT inside the trigger.

Statement

SELECT * FROM INSERTED WHERE COL1 < 5

executes and set @@ROWCOUNT to 1

Put statement

SET NOCOUNT ON;

then

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
那支青花 2024-10-11 14:30:39

问题

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

解决方案

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

我发布了一个使用 CONTEXT_INFO 的示例> 在 DBA.StackExchange 上的相关问题的回答中: 将有关删除记录的人的信息传递到删除触发器。评论中对该答案进行了讨论,该答案与 CONTEXT_INFO 可能出现的并发症有关,因此我发布了 关于该问题的另一个答案,而是使用临时表。

由于该示例涉及向触发器发送信息,因此下面是从触发器获取信息的示例,这就是该问题的内容:

第一:< /strong> 创建一个简单的表

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

The Problem

I need information in the context of the main process that is only available in the context of the trigger.

The Solution

Whether getting @@ROWCOUNT or anything else from a trigger, or even passing information to a trigger, there are two methods that allow for sharing information with triggers:

I posted an example of using CONTEXT_INFO in an answer on a related question over at DBA.StackExchange: Passing info on who deleted record onto a Delete trigger. There was a discussion in the comments on that answer related to possible complications surrounding CONTEXT_INFO, so I posted another answer on that question using a temporary table instead.

Since that example dealt with sending information to a trigger, below is an example of getting information from a trigger as that is what this question is about:

First: Create a simple table

CREATE TABLE dbo.InsteadOfTriggerTest (Col1 INT);

Second: Create the trigger

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;

Third: Do the test

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;

Output (in Messages tab):

Trigger (starting): 91
Trigger (after INSERT): 5
Final @@ROWCOUNT (what we do NOT want): 91

Results:

RowsAffected
5

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文