SET NOCOUNT ON,但仍然会返回受影响的行数信息

编程语言 2026-07-11

我想写一个简单的触发器。触发器开头有 SET NOCOUNT ON,来自插入行的 SELECT 语句。

在选定所需数据后,执行一个 IF-ELSE 语句。

触发器按我预期工作,但仍返回一个:

1行受影响

消息是因为 SELECT 语句导致的。

而插入实际数据的软件以为一切正常,但实际上在 IF 块内存在 RAISEERROR

我用 SET NOCOUNT ON 除了触发器之外的其他方式进行测试,它会阻塞以下输出:

受影响的行

消息会正确显示。

我的错误可能是什么?

ALTER TRIGGER [dbo].[TEST_TRIGGER]
ON [dbo].[TEST_TABLE] 
FOR INSERT,UPDATE
AS 
BEGIN
    SET NOCOUNT ON;

    DECLARE @vade int

    SELECT @vade = vade FROM inserted

    IF @vade = 0
    BEGIN
        RAISERROR('Error Message', 16, 1);
        ROLLBACK TRANSACTION
    END
END

SSMS返回的消息

(1 row affected)
Msg 50000, Level 16, State 1, Procedure TEST_TRIGGER, Line 21 [Batch Start Line 0]
Error Message
Msg 3609, Level 16, State 1, Line 1
The transaction ended in the trigger. The batch has been aborted.

Completion time: 2026-03-11T09:30:16.3873382+03:00

解决方案

(1 row affected) 可能来自外部作用域(INSERT),而非内部作用域(TRIGGER)。这是因为你选择使用 RAISERROR 而不是 THROW,它并不具备 XACT_ABORT 的感知能力,其使用不被推荐,微软在 [文档] 中也有说明:

注: RAISERROR 语句不遵守 SET XACT_ABORT。新应用应使用 THROW 代替 RAISERROR

如果你使用 THROW,就不会出现无端的错误,也不会收到 (1 row affected) 的消息。在下面的示例中,我还修正了你提到的关于你以为 INSERT 只包含1 行的说法;这是错误的,一个 INSERT 可以包含0 行或多行。

CREATE TABLE dbo.MyTable (MyInt int NOT NULL);
GO

CREATE TRIGGER dbo.trg_MyTable_Ins ON dbo.MyTable
AFTER INSERT AS
BEGIN
    IF EXISTS (SELECT 1 
               FROM inserted i
               WHERE i.MyInt = 0)
        THROW 98765, N'Cannot insert the value 0 into table ''dbo.MyTable''.', 1;
END;
GO

INSERT INTO dbo.MyTable (MyInt)
VALUES(1);
GO

INSERT INTO dbo.MyTable (MyInt)
VALUES(0);
GO

INSERT INTO dbo.MyTable (MyInt)
VALUES(1),(0);
GO

上述批处理,即使在 TRIGGER 中没有声明 NOCOUNT ON,也只会产生一个 (1 row affected),它是第一个 INSERT

当然,对于这个具体的示例, TRIGGER 也不正确,你应该直接使用 CONSTRAINT

DROP TRIGGER dbo.trg_MyTable_Ins;
GO

ALTER TABLE dbo.MyTable ADD CONSTRAINT chk_MyTable_MyInt CHECK (MyInt <> 0);
GO

INSERT INTO dbo.MyTable (MyInt)
VALUES(0);
GO

--Clean up
DROP TABLE dbo.MyTable;
GO
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章