You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

存储过程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

关键说明

  1. 错误捕获范围缩小:现在每个EXEC DYNAMIC_PROC调用都被独立的TRY/CATCH包裹,单个实体执行失败只会记录日志,不会中断外层循环。
  2. 移除错误抛出:CATCH块中不再使用RAISERROR或THROW,避免终止整个存储过程。
  3. 变量作用域优化:@name在TRY块外赋值,确保CATCH块中能正确获取出错的实体名称。
  4. 循环计数器重置:修正原代码中@CounterList未在每次外层循环开始时重置的问题,避免逻辑错误。

内容的提问来源于stack exchange,提问作者John

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 21:40:02