T-SQL 抛出异常

Posted

技术标签:

【中文标题】T-SQL 抛出异常【英文标题】:T-SQL Throw Exception 【发布时间】:2014-12-10 04:57:19 【问题描述】:

在 T-SQL 存储过程中使用 THROW 语句时,我遇到了著名的“语法错误”。我在 Google 上搜索并检查了 *** 上的问题,但提出的解决方案(奇怪的是,被接受)对我不起作用。

我正在修改一个存储过程如下:

ALTER PROCEDURE [dbo].[CONVERT_Q_TO_O]
    @Q_ID int = NULL,
    @IDENTITY INT = NULL OUTPUT
AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @EXISTING_RECORD_COUNT [int];

    SELECT
        @EXISTING_RECORD_COUNT = COUNT (*)
    FROM
        [dbo].[O]
    WHERE
        [Q_ID] = @Q_ID

    IF @EXISTING_RECORD_COUNT = 0
    BEGIN
        -- DO SOME STUFF HERE

        -- RETURN NEW ID
        SELECT @IDENTITY = SCOPE_IDENTITY()
    END
    ELSE
    BEGIN
         THROW 99001, 'O associated with the given Q Id already exists', 1;
    END
END
GO

当我编写这个 T-SQL 代码时,我得到一个错误提示

“THROW”附近的语句不正确。期待 CONVERSATION、DIALOG、DISTRIBUTED 或 TRANSACTION

所有解决方案都建议在“THROW”之前或“ELSE BEGIN”语句之后放置一个分号。当我修改 T-SQL 时,我只是收到“Incorrect statement near 'THROW'”错误并且似乎找不到解决方案。

有什么建议吗?

【问题讨论】:

你用的是什么版本的sql server? 您使用的可能是不支持 THROW 的版本 THROW 是 SQL Server 2012 中的新功能,因此如果您使用的是 2012 年以前的版本,则不能使用该功能 - 检查您的 SELECT @@VERSION 输出以了解您正在使用的数据库引擎版本! 对于 SQL Server 2012+ 中的相同错误,请参阅 Incorrect syntax near 'THROW' 确保前面的语句以分号“;”结尾 【参考方案1】:

这在 SQL Server 2014 中继续发生。

我发现将分号放在 BEGIN 末尾会有所帮助。

这种方法有错误

IF 'A'='A'
BEGIN
   THROW 51000, 'ERROR', 1;
END;

而且这种做法没有错误

IF 'A'='A'
BEGIN;
  THROW 51000, 'ERROR', 1;
END;

【讨论】:

不以分号结尾的语句现在是deprecated,所以即使不扔,这也是一个养成的好习惯。 好消息,罗杰 确保THROW前面的语句以分号“;”结尾。例如,您可以有一个“PRINT 'Before Throw';”声明。 这一定是我见过的 SQL 最愚蠢的事情之一。并且永远不需要分号,数十亿行代码不会被更新。那艘船已经航行了。【参考方案2】:

为了解决你的问题,

“THROW”附近的语句不正确。期待对话,对话, 分布式,或交易

在你的 throw 语句前加上分号:

BEGIN
    ;THROW 99001, 'O associated with the given Q Id already exists', 1;
END

关于

“'THROW' 附近的语句不正确”。

如果您使用的是 SQL 2012 之前的旧版本,请尝试使用它:

RAISERROR('O associated with the given Q Id already exists',16,1);

因为THROW是SQL 2012的新特性。

【讨论】:

请不要在语句前加分号。放在上一行的语句之后。 BEGIN 后面加分号看起来很奇怪,恕我直言。 如果你没有,分号只是完成最后一条指令。这样可以确保不会发生错误。【参考方案3】:

对于 SQL Server 2012 或更高版本:

;THROW 60000, 'your message here', 1

如果您希望将变量传递给您的消息,请使用:

DECLARE
    @Errors INT = 2,
    @ErrMsg NVARCHAR(500)

SET @ErrMsg = 'You have '+CAST(@Errors AS NVARCHAR) + ' errors!'
;THROW 60000, @ErrMsg, 1

请注意,与 RAISERROR 不同,THROW 会阻止进一步的代码执行。

THROW documentation

旧版选项:

RAISERROR('your message here', 16, 1)

如果您希望将变量传递给您的消息,请使用:

DECLARE
    @Errors INT = 2,
    @ErrMsg NVARCHAR(500)

SET @ErrMsg = 'You have '+CAST(@Errors AS NVARCHAR) + ' errors!'
RAISERROR(@ErrMsg, 16, 1)

查看sql server版本:SELECT @@VERSION

【讨论】:

【参考方案4】:

; 放在THROW 关键字之前,它会起作用。

【讨论】:

这也适用于其他关键字有问题的情况,例如我在END CATCH 之后有一个ENABLE TRIGGER 命令 - 添加分号解决了它。【参考方案5】:

如果您错误地编码,也会发生此错误:

RAISEERROR('your message here',16,1)

我盯着它看了四个小时,到处都是分号,直到我意识到我拼错了“RAISERROR”

【讨论】:

这令人沮丧。我也拼错了 RAISEERROR。花了大约一个小时寻找解决方案。 我认为是开发人员将其命名为 RAISERROR 是拼写错误...【参考方案6】:

正如很多回答所指出的,THROW语句是在SQL Server 2012中引入的。所以如果你使用的是这个版本的SQL Server或更高版本,建议使用THROW,否则使用RAISERROR。

此外,THROW 语句之前的语句必须后跟分号 (;) 语句终止符。这就是为什么你必须在 throw 前加上一个分号。

看看这篇关于Differences Between RAISERROR and THROW in Sql Server的文章

我还想鼓励您阅读来自 MSDN THROW (Transact-SQL) 的文档,该文档在备注部分解释了这些问题。

【讨论】:

【参考方案7】:

感谢您发布此问题。虽然 IDE 给出了语法错误,但我发现它编译并运行良好(注意,我使用的是 SQL Server 2106)。

我也发现,如果只需要一个语句,我可以直接使用

ELSE 
    THROW 99001, 'O associated with the given Q Id already exists', 1;

这不会显示语法错误消息。

【讨论】:

以上是关于T-SQL 抛出异常的主要内容,如果未能解决你的问题,请参考以下文章

T-SQL 抛出异常并返回(不使用 TRY)

关于java异常抛出与返回值

Java 异常 重写方法时抛出异常

Java:抛出异常后如何终止执行后面的代码?

JAVA如何抛出异常

java中异常抛出后代码还会继续执行吗