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

当我使用 SQLServer 时,出现了一个错误,错误消息给出的行号与存储过程中的行号没有相关性。我假设这种差异是由于空白和注释造成的,但是真的是这样吗?

如何将这两组行号相互关联?如果有人能给我指点一下正确的方向,我会很感激的。

我正在使用 SQL Server 2005。

118669 次浏览

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

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

sp_helptext proc_name

将结果复制粘贴到脚本窗口以获得语法突显等,然后使用 goto line 函数(我认为是 CTRL-G)进入所报告的错误行。

你可以用这个

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_number()工作得很好。

这个函数从最后一个 GO (批分隔符)语句开始计数,所以如果您没有使用任何 GO 空格,并且它仍然显示错误的行号——那么向它添加7,就像在第7行的存储过程中一样,批分隔符是自动使用的。所以如果你用 选择 Cast (Error _ Number () + 7 as Int) as [ Error _ Number ]-您将得到所需的答案。

长一点的答案是: 行号是从 CREATE PROCEDURE语句中计算出来的,再加上实际运行 CREATE语句时在它上面的任何空行或注释行,但是不计算 GO语句之前的任何行..。

我发现制作一个存储的程序来确认要容易得多:

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,并在注释上方和第一个 GO语句上下添加一些空行,以查看效果。

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

出于习惯,我将 LINENO 0直接放在 BEGIN之后的存储过程中。在本例中,这会将行号重置为零。然后只需将错误消息报告的行号添加到 SSMS 中的行号中,您在 SSMS 中编写了 LINENO 0,然后就可以得到查询窗口中表示的错误行号。

你可以像下面这样在 catch 块中得到错误消息和错误行:

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

如果您使用了一个 Catch Block 并且在 TryBlock 中的任何代码验证中使用了一个 RAISERROR () ,那么错误行将被报告在 Catch Block 所在的位置,而不是真正的错误发生的位置。我用这个来澄清。

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

在 TSQL/存储过程中

您可能会遇到以下错误:

味精206,等级16,状态2,程序 myproc,第177行[批次开始行7]

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

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

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

”如果使用 ManagementStudio 生成脚本,则会自动添加 USEDbname语句以及 ANSI _ NULLS 和 QUOTED _ IDENTIFIER 的设置。删除这些语句(9行)以获得脚本窗口中正确的行号:

只需将以下代码添加到存储过程中,以指示绝对行开始号 WITH“ 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