存储过程While循环异常处理需求:记录错误并继续执行
解决方案
核心问题是你的TRY/CATCH块覆盖了整个外层循环,一旦循环内任何环节出错就会触发CATCH并抛出错误,导致整个存储过程终止。要实现「出错仅记录日志、继续执行」,需要将错误捕获范围缩小到单个实体的存储过程调用层级,具体修改如下:
修改要点
- 将
TRY/CATCH移至调用DYNAMIC_PROC的最内层循环中,确保单个实体执行失败不影响其他实体。 - 删除CATCH中的
RAISERROR语句,避免抛出错误中断流程。 - 修正变量作用域问题,保证错误日志能正确记录当前出错的实体名称。
- 补充原代码中未声明的
@MonthValue变量(若实际需动态传入,可改为存储过程参数)。
修改后的完整代码
CREATE PROC [DYNAMIC_PROC_MAIN] AS BEGIN SET NOCOUNT ON /* 变量声明 */ DECLARE @CheckError INT = 0; DECLARE @ErrorMessage VARCHAR(4000); DECLARE @Current_date datetime DECLARE @VMaxlevel bigint DECLARE @RowCount bigint DECLARE @Vraa_name VARCHAR(50) DECLARE @Vformula VARCHAR(50) DECLARE @Vlevel INT DECLARE @MonthValue VARCHAR(50) = '202306' -- 补充未声明的变量,可按需改为输入参数 DECLARE @InputValue varchar(1000) DECLARE @LastRefreshDate datetime DECLARE @number_of_rows int DECLARE @row_count INT DECLARE @Counter INT = 1 DECLARE @CounterList INT = 1 DECLARE @Vtemp VARCHAR(4000) -- 获取最大层级数 SET @VMaxlevel = (SELECT MAX(level_id) FROM Level_t) -- 外层层级循环 WHILE (@Counter <= @VMaxlevel ) BEGIN SET @InputValue = @MonthValue SELECT @Current_date = GETUTCDATE(), @LastRefreshDate = GETUTCDATE() -- 获取当前层级下的记录数 SET @RowCount = (SELECT COUNT(DISTINCT lt.ID) FROM Level_t2 lt WHERE lt.level = @Counter) SET @CounterList = 1 -- 重置中层循环计数器 -- 中层记录循环 WHILE (@CounterList <= @RowCount ) BEGIN /* 创建临时表存储运行时记录 */ IF OBJECT_ID('tempdb..#kpi_maintmptbl') IS NOT NULL BEGIN DROP TABLE #kpi_maintmptbl END CREATE TABLE #kpi_maintmptbl WITH ( DISTRIBUTION = ROUND_ROBIN ,HEAP ) AS (SELECT DISTINCT lt.name FROM Level_t3 lt WHERE lt.level = @CounterList) /* 内层实体循环 */ DECLARE @recordCount int = (SELECT COUNT(1) FROM #kpi_maintmptbl) DECLARE @counter1 int = 1 DECLARE @name VARCHAR(50) -- 实体名称 WHILE @counter1 <= @recordCount BEGIN -- 获取当前要处理的实体名称 SET @name = ( SELECT [name] FROM ( SELECT *, ROW_NUMBER() OVER(ORDER BY [raa_name]) AS RN FROM #kpi_maintmptbl ) as T WHERE RN = @counter1 ) PRINT '正在处理实体: ' + @name PRINT '当前层级: ' + CAST(@Counter AS VARCHAR) PRINT '当前序号: ' + CAST(@counter1 AS VARCHAR) -- 为单个实体调用添加独立错误捕获 BEGIN TRY EXEC DYNAMIC_PROC @name END TRY BEGIN CATCH -- 捕获错误信息并写入日志 SELECT @CheckError = ERROR_NUMBER(), @ErrorMessage = CONCAT(@name, '-', ERROR_MESSAGE()), @Current_date = GETUTCDATE() INSERT INTO dl_config.CL_Error_Log VALUES('DYNAMIC_PROC_MAIN', @CheckError, @ErrorMessage, @Current_date, NULL); -- 不抛出错误,继续执行后续实体 END CATCH SET @counter1 = @counter1 + 1 END SET @CounterList = @CounterList + 1 END SET @Counter = @Counter + 1 END END GO
关键说明
- 错误捕获范围缩小:现在每个
EXEC DYNAMIC_PROC调用都被独立的TRY/CATCH包裹,单个实体执行失败只会记录日志,不会中断外层循环。 - 移除错误抛出:CATCH块中不再使用
RAISERROR或THROW,避免终止整个存储过程。 - 变量作用域优化:
@name在TRY块外赋值,确保CATCH块中能正确获取出错的实体名称。 - 循环计数器重置:修正原代码中
@CounterList未在每次外层循环开始时重置的问题,避免逻辑错误。
内容的提问来源于stack exchange,提问作者John
相关产品推荐
相关产品推荐

