当sp_executesql
返回错误消息时,是否有任何内置的错误处理方法/机制可用于标识此错误是由该过程返回的,还是直接从包含脚本的错误返回的? / p>
在以下情况下,错误详细信息将错误标识为发生在第1行,但它们并不表示所引用的第1行是不是行中的第行脚本本身 ,而是由脚本传递给sp_executesql
的查询中的第1行。
我正在寻找识别来源的方法,以便可以相应地对其进行记录。我想记录类似Script x - Call to inner query errored on that query's line 1
之类的内容,而不是一般的(且具有误导性的)Script x errored on line 1
。
-- do other things first
BEGIN TRY
EXECUTE sp_executesql @stmt = N'SELECT 1/0';
END TRY
BEGIN CATCH
SELECT ERROR_NUMBER() AS ErrorNumber
,ERROR_SEVERITY() AS ErrorSeverity
,ERROR_STATE() AS ErrorState
,ERROR_PROCEDURE() AS ErrorProcedure
,ERROR_LINE() AS ErrorLine
,ERROR_MESSAGE() AS ErrorMessage
END CATCH;
返回:
ErrorNumber ErrorSeverity ErrorState ErrorProcedure
----------- ------------- ----------- ---------------
8134 16 1 NULL
答案 0 :(得分:0)
您可以使用sp_executeSQL
的{{3}}:
DECLARE @ErrorLine NVARCHAR(32)
DECLARE @Params NVARCHAR(150) = '@Return INT OUTPUT'
DECLARE @SQL NVARCHAR(MAX) = ''
SET @SQL = @SQL + ' '
SET @SQL = @SQL + ' BEGIN TRY '
SET @SQL = @SQL + ' SELECT 100 AS First '
SET @SQL = @SQL + ' SELECT 1/0 AS Second '
SET @SQL = @SQL + ' END TRY '
SET @SQL = @SQL + ' BEGIN CATCH '
SET @SQL = @SQL + ' SELECT @Return = ERROR_LINE() '
SET @SQL = @SQL + ' END CATCH '
SET @SQL = @SQL + ' '
EXEC sp_executeSQL @SQL, @Params, @Return = @ErrorLine OUTPUT
SELECT @ErrorLine
无论错误在哪里,这段代码都将显示@ErrorLine
= 1,因为从技术上讲,整个SQL都在一行上,这使整个事情变得更加复杂,但是您明白了... >
编辑:如果@ErrorLine
是NULL
,则sp_executeSQL
中没有错误。
答案 1 :(得分:0)
不幸的是,调用堆栈不适用于T-SQL错误处理。考虑升级this feature request以便于捕获T-SQL堆栈详细信息。
下面的示例在内部脚本出错时使用嵌套的TRY / CATCH引发用户定义的错误(消息号50000),捕获可用的详细信息以及上下文描述(“内部脚本”)。当外部脚本中发生错误时,只需重新抛出原始错误即可。缺少上下文和系统错误号表示最外面的脚本犯了错误,尽管您可以在那里构建并引发用户定义的错误,包括外部脚本上下文描述。
BEGIN TRY
BEGIN TRY
EXECUTE sp_executesql @stmt = N'SELECT 1/0;';
END TRY
BEGIN CATCH
DECLARE
@ErrorNumber int
,@ErrorMessage nvarchar(2048)
,@ErrorSeverity int
,@ErrorState int
,@ErrorLine int;
SELECT
@ErrorNumber =ERROR_NUMBER()
,@ErrorMessage =ERROR_MESSAGE()
,@ErrorSeverity = ERROR_SEVERITY()
,@ErrorState =ERROR_STATE()
,@ErrorLine =ERROR_LINE();
RAISERROR('Error %d caught in inner script at line %d: %s'
,@ErrorSeverity
,@ErrorState
,@ErrorNumber
,@ErrorLine
,@ErrorMessage);
END CATCH;
END TRY
BEGIN CATCH
THROW;
END CATCH;
GO
答案 2 :(得分:0)
这是返回行号的解决方案。我们在一个接受参数的 SPROC 中。本质上,作为 tSQL 开发人员,您需要猜测问题会在哪里发生,通常是围绕形式参数输入的参数。
-- Preamble
CREATE PROCEDURE [Meta].[ValidateTable]
@DatabaseNameInput VARCHAR(100), -- = 'DatabaseNameInput',
@TableNameInput VARCHAR(100), -- = 'TableNameInput',
@SchemaNameInput VARCHAR(100), -- = 'SchemaNameInput',
AS
BEGIN
DECLARE @crlf CHAR(2) = CHAR(13) + CHAR(10),
-----------Database Validity------------------
@IsDatabaseValid BIT,
@DatabaseNumber INTEGER,
@DatabaseNamePredicate NVARCHAR(100),
@CurrentExecutingContext NVARCHAR(40),
@DatabaseValidityExecutable NVARCHAR(100),
@DatabaseParameterString NVARCHAR(50),
-----------Table Validity------------------
@TableObjectIdentity INTEGER,
@TableString NVARCHAR(500),
@TableParameterString NVARCHAR(50),
@TableValidityExecutable NVARCHAR(200),
-----------Error Handling------------------
@ErrorState INTEGER = 0,
@ErrorNumber INTEGER = 0,
@ErrorSeverity INTEGER = 0,
@MyErrorMessage NVARCHAR(150),
@SetMessageText NVARCHAR(1024) = 'No Error Message Text for sys.messages.',
@ErrorDescription NVARCHAR(1024) = 'No error description was given.';
-- Be aware of SQL Injection Risk with no semi-colons at the line tails
SET @TableString = 'N' + '''' + @DatabaseNameInput + '.' + @SchemaNameInput + '.' + @TableNameInput + '''';
SET @DatabaseParameterString = N'@DatabaseNumber INTEGER OUTPUT ';
SET @TableParameterString = N'@TableObjectIdentity INTEGER OUTPUT';
-- Phase 0.0, testing for database existence.
PRINT 'Table Validity Executable: ' + @TableValidityExecutable;
EXECUTE sp_executesql @DatabaseValidityExecutable, @DatabaseParameterString, @DatabaseNumber = @DatabaseNumber OUTPUT;
IF @DatabaseNumber IS NULL
BEGIN
SET @MyErrorMessage = 'The @DatabaseNameInput parameter: "%s" specified by the caller does not exist on this SQL Server - ' + @@SERVERNAME;
EXECUTE sys.sp_addmessage @msgnum = 59802, @severity = 16, @msgtext = @MyErrorMessage, @replace = 'replace', @lang = 'us_english';
RAISERROR(59802, 15, 1, @DatabaseNamePredicate);
END;
-- Phase 0.1, testing for table existence.
PRINT 'Table Validity Executable: ' + @TableValidityExecutable;
EXECUTE sp_executesql @TableValidityExecutable, @TableParameterString, @TableObjectIdentity = @TableObjectIdentity OUTPUT;
IF @TableObjectIdentity IS NULL
BEGIN
SET @MyErrorMessage = 'The @TableNameInput parameter: "%s" specified by the caller does not exist in this database - ' + DB_NAME() +';';
EXECUTE sys.sp_addmessage @msgnum = 59803, @severity = 16, @msgtext = @MyErrorMessage, @replace = 'replace', @lang = 'us_english';
RAISERROR(59803, 15, 1, @TableString);
END;