SET NOCOUNT ON,但仍然会返回受影响的行数信息
我想写一个简单的触发器。触发器开头有 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导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。