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 抛出异常的主要内容,如果未能解决你的问题,请参考以下文章