如何在WHILE循环中忽略自定义RAISERROR以确保SQL作业正常完成?
问题:SQL作业中RAISERROR导致步骤失败的解决办法
我有一个通过SQL作业执行的存储过程,需按周处理4年的数据(最长耗时4小时)。为在SQL Server外部监控进度,我在WHILE循环开头添加了RAISERROR语句,用于输出每次循环的日期范围到日志文件,相关代码如下:
DECLARE @START_DATE date, @END_DATE date, @DATE_RANGE nvarchar(255) SELECT @START_DATE = '20231029', @END_DATE = DATEADD(day, 6, @START_DATE) BEGIN TRY WHILE @END_DATE <= CAST(GETDATE() as date) BEGIN SET @DATE_RANGE = 'Start date: ' + CAST(@START_DATE as nvarchar(10)) + '.....End date: ' + CAST(@END_DATE as nvarchar(10)) + '(' + CAST(GETDATE() as nvarchar(50)) + ')' RAISERROR(@DATE_RANGE, 2, 1) WITH NOWAIT -- INSERT statement to execute -- 补充循环变量更新,避免无限循环 SET @START_DATE = DATEADD(day, 7, @START_DATE) SET @END_DATE = DATEADD(day, 7, @END_DATE) END END TRY BEGIN CATCH DECLARE @ErrorMessage nvarchar(MAX), @ErrorSeverity int, @ErrorState int SELECT @ErrorMessage = ERROR_MESSAGE(), @ErrorSeverity = ERROR_SEVERITY(), @ErrorState = ERROR_STATE() RAISERROR (@ErrorMessage, -- Message text @ErrorSeverity, -- Severity @ErrorState -- State ) END CATCH
该代码在WHILE循环前几次执行均正常,但最后一次循环后SQL作业失败,报错信息如下:
Step ID 1 Server <my server> Job Name Process Historic Invoices Step Name Collect Historic Invoices Duration 00:02:05 Sql Severity 2 Sql Message ID 50000 Operator Emailed Operator Net sent Operator Paged Retries Attempted 0 Message Executed as user: <domain service account user>. Start date: 2023-10-29.....End date: 2023-11-04(Nov 6 2023 6:27AM) [SQLSTATE 01000] (Error 50000). The step failed.
查询ERROR 50000后确认,该错误由WHILE循环开头的RAISERROR语句导致。注释掉该语句后,作业步骤可正常完成。请问是否有办法在WHILE循环结束时清除RAISERROR的影响,使作业步骤能报告成功并让后续作业继续执行?
解决方案
1. 改用PRINT + 强制刷新(推荐)
RAISERROR即使是severity=2的信息,也会被SQL Agent判定为错误导致步骤失败。换成PRINT语句配合空RAISERROR强制刷新缓存,既能实时输出进度,又不会触发错误:
SET @DATE_RANGE = 'Start date: ' + CAST(@START_DATE as nvarchar(10)) + '.....End date: ' + CAST(@END_DATE as nvarchar(10)) + '(' + CAST(GETDATE() as nvarchar(50)) + ')' PRINT @DATE_RANGE RAISERROR(N'', 0, 1) WITH NOWAIT -- 强制刷新PRINT缓存,实现实时输出
2. 调整RAISERROR的严重性级别为0
将RAISERROR的severity参数改为0,该级别属于纯信息性消息,不会被SQL Agent判定为错误,也不会触发CATCH块:
RAISERROR(@DATE_RANGE, 0, 1) WITH NOWAIT
3. 在CATCH块中过滤进度信息
如果必须保留severity=2,可以在CATCH块里判断错误严重性,只抛出真正的业务错误:
BEGIN CATCH DECLARE @ErrorMessage nvarchar(MAX), @ErrorSeverity int, @ErrorState int SELECT @ErrorMessage = ERROR_MESSAGE(), @ErrorSeverity = ERROR_SEVERITY(), @ErrorState = ERROR_STATE() -- 仅抛出严重性大于2的错误,忽略进度信息 IF @ErrorSeverity > 2 BEGIN RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState) END END CATCH
内容的提问来源于stack exchange,提问作者Kulstad
相关产品推荐
相关产品推荐

