【问题标题】:RaiseError not appearing from Trigger in Calling Stored Procedure调用存储过程中的触发器未出现 RaiseError
【发布时间】:2015-04-23 13:26:03
【问题描述】:

我们有一个旧产品,从最初在 SQL Server 2000 中构建,多年来发展缓慢,问题与 SQL 如何从 RaiseError 调用中冒泡错误有关。

例如,我在一个表上有一个触发器,它会引发类似于以下的错误:

ALTER TRIGGER [dbo].[Rotation_UTrig]
ON [dbo].[Rotation] FOR UPDATE AS
BEGIN
    SET NOCOUNT ON
.
.
.
    /* * VALIDATION RULE FOR FIELD 'RotationYear' */
            RAISERROR ('Invalid value entered for RotationYear, must be >=0', 44444, 1)
            goto fatalerror
.
.
fatalerror:
END

这在调用过程中具有所需的效果,即 if 语句具有 @@Error 的值:

 update Rotation 
 set OrderedQuantity = @OrderedQuantity, 
     DespatchedQuantity = @DespatchedQuantity 
 where ID = @RotationNo

 if @@Error != 0
 begin
    if @AlreadyInTrans = 0 begin rollback transaction end
        raiserror ('Error on update of Rotation.', 16, 1)
        goto fatalerror
end
.
.
.
fatalerror:

但父调用应用程序看到的错误是:

大于 18 的错误严重级别只能由 sysadmin 角色的成员使用 WITH LOG 选项指定

这是因为触发器中的错误级别是44444,如果我添加

With LOG

Raiserror 的触发代码,然后这会关闭连接(我们不想要)。如果我在触发器中将错误级别降低到 16,那么

if @@Error !=0

由于@@Error 设置为零,因此行未命中。

除了使用

Try... Catch

围绕父过程中的更新语句,是否有任何其他方法可以将@@Error 值冒泡到执行更新的过程中,以便过程代码(更新语句和以下 if @@Error != 0) 可以保持不变吗?如果不是,那么这对我的应用程序来说是一个巨大的变化,因为我需要更改受影响表正在更新的所有位置以及所有触发器。

【问题讨论】:

  • 我知道这是遗留代码,但是一旦您开始看到 GOTO 语句,就该卷起袖子,将代码从黑暗时代拉出来,开始使用 TRY/Catch。十多年来,它一直是一种更好的错误处理技术。
  • 您发布的一小段代码中的另一个巨大的代码气味是,您在整个过程中都有标量变量。这是一个很好的迹象,表明您的触发器假设只会有一个单行操作。它们需要重写为基于集合的方法来处理多行。
  • 如果您在fatalerror: 之后引发另一个错误怎么办?
  • 这是旧代码,但除此之外运行良好,在此阶段重写可能会增加更多错误,因此重写会更进一步。现在我需要找出如何让 Raiseerror 错误冒泡到@@error 或使用不同的变量,但我不确定那会是什么。
  • 我尝试在触发器中的 fatalerror 之后添加另一个错误,没有变化。

标签: sql-server errorlevel raiserror


【解决方案1】:

找到了!问题是,当另一个触发器出现并且正常工作时,@@Error 被重置为 0。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-08-09
    • 1970-01-01
    • 2015-05-28
    • 1970-01-01
    • 1970-01-01
    • 2023-04-02
    • 2021-11-02
    • 1970-01-01
    相关资源
    最近更新 更多