Sql server 错误处理-确定sp_executesql是否为源

Sql server 错误处理-确定sp_executesql是否为源,sql-server,tsql,error-handling,sp-executesql,Sql Server,Tsql,Error Handling,Sp Executesql,当sp_executesql返回错误消息时,是否有任何内置的错误处理方法/机制可用于识别此错误是由此过程返回的,而不是直接从包含的脚本返回的 在以下情况下,错误详细信息将错误标识为发生在第1行,但它们并不表示所引用的第1行不是脚本本身的第1行,而是脚本传递给sp_executesql的查询中的第1行 我正在寻找某种方法来识别源代码,以便相应地记录它。我想在该查询的第1行记录类似于Script x-Call to internal query errored的内容,而不是在第1行记录通用的(且具有

当sp_executesql返回错误消息时,是否有任何内置的错误处理方法/机制可用于识别此错误是由此过程返回的,而不是直接从包含的脚本返回的

在以下情况下,错误详细信息将错误标识为发生在第1行,但它们并不表示所引用的第1行不是脚本本身的第1行,而是脚本传递给sp_executesql的查询中的第1行

我正在寻找某种方法来识别源代码,以便相应地记录它。我想在该查询的第1行记录类似于
Script x-Call to internal query errored的内容,而不是在第1行记录通用的(且具有误导性的)
Script x errored

演示 返回:

ErrorNumber ErrorSeverity ErrorState  ErrorProcedure 
----------- ------------- ----------- ---------------
8134        16            1           NULL           


您可以使用
sp\u executeSQL

这段代码将显示
@ErrorLine
=1,不管错误在哪里,因为从技术上讲,整个SQL都在一行上,这使整个事情变得更复杂,但您知道


编辑:如果
@ErrorLine
NULL
,则
sp_executeSQL

中没有错误。您可以使用
sp_executeSQL

这段代码将显示
@ErrorLine
=1,不管错误在哪里,因为从技术上讲,整个SQL都在一行上,这使整个事情变得更复杂,但您知道


编辑:如果
@ErrorLine
NULL
,则
sp_executeSQL

中没有错误。不幸的是,调用堆栈不可用于t-SQL错误处理。考虑一下投票,以便于捕获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

不幸的是,调用堆栈不能用于t-SQL错误处理。考虑一下投票,以便于捕获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

下面是返回行号的解决方案。我们正处于一个获取参数的存储过程中。本质上,作为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;

下面是返回行号的解决方案。我们正处于一个获取参数的存储过程中。本质上,作为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;
签出此线程:签出此线程: