如何从错误消息中获取实际的存储过程行号?

Posted

技术标签:

【中文标题】如何从错误消息中获取实际的存储过程行号?【英文标题】:How can I get the actual stored procedure line number from an error message? 【发布时间】:2010-12-30 19:30:44 【问题描述】:

当我使用 SQL Server 并且出现错误时,错误消息给出的行号与存储过程中的行号无关。我认为差异是由于空白和 cmets 造成的,但真的是这样吗?

如何将这两组行号相互关联?如果有人能至少给我一个正确方向的指针,我将不胜感激。

我使用的是 SQL Server 2005。

【问题讨论】:

我认为行号与 proc 的主体有关。即忽略标题。 也许***.com/questions/4550342/… 会有所帮助。 标题在哪里结束?在改变过程之后的开始之后...... AS? 它似乎从我的测试中的create proc 行开始计数。我假设您看到的是不同的东西。 在我的回答中描述:***.com/questions/2947173/… 【参考方案1】:

IIRC,它从创建该过程的批处理开始计算行数。这意味着要么是脚本的开始,要么是 create/alter proc 语句之前的最后一个“GO”语句。

查看这一点的更简单方法是提取 SQL Server 在创建对象时使用的实际文本。将输出切换到文本模式(使用默认键映射的 CTRL-T)并运行

sp_helptext proc_name

将结果复制粘贴到脚本窗口中以获得语法高亮等,并使用 goto line 功能(我认为是 CTRL-G)转到报告的错误行。

【讨论】:

当我在网格输出模式下执行此操作时,它也将行号卡住了 @codeulike - 好点,如果您使用网格输出,行号将匹配行号,因此您不需要使用 CTRL+G。我对 Grid 输出的唯一问题是它会将 TAB 字符更改为单个空格,因此您会丢失所有格式。【参考方案2】:

出于习惯,我在存储过程中将LINENO 0 直接放在BEGIN 之后。在这种情况下,这会将行号 - 重置为零。然后只需将错误消息报告的行号添加到您编写LINENO 0 和宾果游戏的 SSMS 中的行号 - 您将在查询窗口中获得错误的行号。

【讨论】:

为什么不直接将“LineNo X”放在 X= 语句所在的行号处,以便自动添加到报告的行号中? @LarryBud 可能是由于存储过程中的 cmets?【参考方案3】:

如果您使用 Catch 块并在 Try 块中使用 RAISERROR() 进行任何代码验证,则错误行会报告 Catch 块所在的位置,而不是真正发生错误的位置。我用它来清除它。

BEGIN CATCH
  DECLARE @ErrorMessage NVARCHAR(4000);
  DECLARE @ErrorSeverity INT;
  DECLARE @ErrorState INT;

  SELECT 
     @ErrorMessage = ERROR_MESSAGE() + ' occurred at Line_Number: ' + CAST(ERROR_LINE() AS VARCHAR(50)),
     @ErrorSeverity = ERROR_SEVERITY(),
     @ErrorState = ERROR_STATE();

  RAISERROR (@ErrorMessage, -- Message text.
     @ErrorSeverity, -- Severity.
     @ErrorState -- State.
  );

END CATCH

【讨论】:

太棒了!这是一个包含LINENO 指令的示例: ``` BEGIN TRY -- 将批处理行# 转换为文件#LINENO 21; -- 保持匹配文件 # -- 生成被零除错误。选择 1 / 0; END TRY BEGIN CATCH DECLARE @err_msg NVARCHAR(4000), @err_severity INT, @err_state INT; SET @err_msg = '在第 # 行' + cast(error_line() AS VARCHAR(50)) + ': ' + error_message(); SET @err_severity = error_severity(); SET @err_state = error_state(); RAISERROR (@err_msg, @err_severity, @err_state);结束捕获;去```【参考方案4】:

其实这个Error_number() 效果很好。

这个函数从最后一个 GO(批处理分隔符)语句开始计数,所以如果你没有使用任何 Go 空格并且它仍然显示错误的行号 - 然后将 7 添加到它,如第 7 行中的存储过程自动使用批处理分隔符。所以如果你使用 选择 Cast(Error_Number()+7 as Int) as [Error_Number] - 你会得到想要的答案。

【讨论】:

if you have not used any Go spaces and it is still showing a wrong line number - then add 7 to it, as in stored procedure in line number 7 the batch separator is used automatically. - 这是什么意思?【参考方案5】:

在 TSQL / 存储过程中

您可能会收到如下错误:

消息 206,级别 16,状态 2,过程 myproc,第 177 行 [批处理开始第 7 行]

这意味着错误在批处理中的第 177 行。 SQL 中不是 177。你应该看到你的批处理开始的行号,在我的例子中 [7],然后你将该值添加到行号以查找错误的语句

【讨论】:

【参考方案6】:

你可以用这个

CAST(ERROR_LINE() AS VARCHAR(50))

如果你想制作错误日志表,你可以使用这个:

INSERT INTO dbo.tbname( Source, Message) VALUES ( ERROR_PROCEDURE(), '[ ERROR_SEVERITY : ' + CAST(ERROR_SEVERITY() AS VARCHAR(50)) + ' ] ' + '[ ERROR_STATE : ' + CAST(ERROR_STATE() AS VARCHAR(50)) + ' ] ' + '[ ERROR_PROCEDURE : ' + CAST(ERROR_PROCEDURE() AS VARCHAR(50)) + ' ] ' + '[ ERROR_NUMBER : ' + CAST(ERROR_NUMBER() AS VARCHAR(50)) + ' ] ' +  '[ ERROR_LINE : ' + CAST(ERROR_LINE() AS VARCHAR(50)) + ' ] ' + ERROR_MESSAGE())

【讨论】:

请注意,ERROR_LINE() 仅在存储过程中的 TRY/CATCH 的 CATCH 部分中可用。如果您没有发现错误,它报告的行号与 SQL Server 返回的行号相同。因此,虽然这可能有用,但无助于解决这个问题。【参考方案7】:

长答案:行号从CREATE PROCEDURE 语句中计算,加上您实际运行CREATE 语句时可能在其上方的任何空白行或注释行,但不计算@ 之前的任何行987654323@声明…

我发现制作一个存储过程来进行确认要容易得多:

GO

-- =============================================
-- Author:          <Author,,Name>
-- Create date: <Create Date,,>
-- Description:     <Description,,>
-- =============================================
CREATE PROCEDURE ErrorTesting
       -- Add the parameters for the stored procedure here
AS
BEGIN
       -- SET NOCOUNT ON added to prevent extra result sets from
       -- interfering with SELECT statements.
       SET NOCOUNT ON;

       -- Insert statements for procedure here
       SELECT 1/0

END
GO

创建完成后,可以将其切换为ALTER PROCEDURE,并在 cmets 上方和第一个 GO 语句的上方和下方添加一些空行以查看效果。

我注意到一件非常奇怪的事情是我必须在一个新的查询窗口中运行EXEC ErrorTesting,而不是在同一窗口的底部突出显示它并运行……当我这样做时,行号一直在上升!不知道为什么会这样..

【讨论】:

【参考方案8】:

关于这个问题的有用文章:

http://tomaslind.net/2013/10/15/line-numbers-in-t-sql-error-messages/

“如果您改为使用 Management Studio 生成脚本,则自动添加 USE dbname 语句以及 ANSI_NULLS 和 QUOTED_IDENTIFIER 的设置。删除这些语句(9 行)以获得正确的行号脚本窗口:"

【讨论】:

【参考方案9】:

您可以像这样在 catch 块中获取错误消息和错误行:

'Ms Sql Server Error: - ' + ERROR_MESSAGE() + ' - Error occured at: ' + CONVERT(VARCHAR(20),  ERROR_LINE())

【讨论】:

【参考方案10】:

只需将以下代码添加到您的存储过程中,以“LINENO xx”表示绝对行起始号,其中“xx”是您在 SQL Mgt Studio 中打开 SP 时的实际行号

例如,

USE [Northwind]
GO
/****** Object:  StoredProcedure [automate].[workorders_exceptions_generate]    Script Date: 03/03/2021 8:49:23 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
/*

Here are some comments here
Which are white spaces
But the actual line after the "BEGIN" statement is 21

*/
CREATE PROCEDURE dbo.something
    @ChildWOID varchar(30)
    , @DontByPass bit = 0
    , @BillingStatus varchar(30) = null OUTPUT
AS
BEGIN
    LINENO 21
    
    PRINT 'HELLO WORLD'
END

【讨论】:

以上是关于如何从错误消息中获取实际的存储过程行号?的主要内容,如果未能解决你的问题,请参考以下文章

从存储过程返回错误消息

如何在 MySQL 5.5 中获取存储过程的异常消息

如果存储过程失败,则在执行 SQL 任务中将输出变量值获取到 ssis 变量中

获取存储过程 SQL 文本很热门?

MySQL 存储过程错误处理

如何在存储过程中使用动态表名编写 Select 查询?