继续执行而不引发异常

Continue execution without throw the exception

提问人:John 提问时间:10/25/2023 最后编辑:John 更新时间:10/27/2023 访问量:111

问:

我在 while 循环中运行一个过程,当出现异常时,它会退出该过程。 但是我希望该过程应该在 while 循环中继续执行其他实体,并且应该退出该过程,而是会在表中记录错误。这样我们就可以在过程完成执行后对表进行处理。 如果您有任何解决方案,请告诉我。

 CREATE PROC [DYNAMIC_PROC_MAIN]  AS
BEGIN

SET NOCOUNT ON

/* Variable Declaration */
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 @Vmonth VARCHAR(50) = '202306'

DECLARE @InputValue varchar(1000)
DECLARE @LastRefreshDate datetime

DECLARE @number_of_rows int 
DECLARE @row_count INT

DECLARE @Counter INT
SET @Counter = 1

DECLARE @CounterList INT
SET @CounterList = 1

DECLARE @Vtemp VARCHAR(4000)

SET @VMaxlevel = 
    (select max(level_id)
FROM Level_t)

WHILE (@Counter <= @VMaxlevel )


BEGIN TRY
        --Print(@VMaxlevel)
        Set @InputValue = @MonthValue

    SELECT @Current_date=GETUTCDATE()
    SELECT @LastRefreshDate=GETUTCDATE()
    
    
        --Print(@Counter)
      
        SET @RowCount = 
    (SELECT count(distinct lt.ID) FROM Level_t2 lt
WHERE lt.level=@counter)
         
        WHILE (@CounterList <= @RowCount )
     BEGIN
        

     /* Begin creation a temp table to store recrods in runtime */
            BEGIN
            IF OBJECT_ID('tempdb..#kpi_maintmptbl') IS NOT NULL
            BEGIN
            --print 'Hello'
            DROP TABLE #kpi_maintmptbl
            END
            --GO
            create table #kpi_maintmptbl
            with (
            DISTRIBUTION = ROUND_ROBIN
            ,HEAP
            )
            AS (select distinct lt.name FROM Level_t3 lt
            where lt.level=@CounterList)
            

            END

            /* End creation a temp table to store recrods in runtime */

            DECLARE @recordCount int = (SELECT COUNT(1) from #kpi_maintmptbl)
            DECLARE @counter1 int = 1
            DECLARE @name VARCHAR(50) -- database name 
            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 @Vlevel
                  Print @counter1

                
                EXEC DYNAMIC_PROC  @name
                 
                 
                  SET @counter1 = @counter1 + 1

             END
     SET @CounterList = @CounterList +1
    END
--SET @Counter = @Counter +1


END TRY

Begin Catch

    DECLARE
        @ErrorSeverity INT,
        @ErrorState INT;
                

            SELECT @ErrorMessage = ERROR_MESSAGE(),          
            @ErrorSeverity = ERROR_SEVERITY(),          
            @ErrorState = ERROR_STATE();
            RAISERROR(@ErrorMessage, @ErrorSeverity, @ErrorState);
    
        
        SELECT @Current_date=GETUTCDATE()
       

        SET @CheckError = ERROR_NUMBER()
        SET @ErrorMessage = concat(@name,'-',ERROR_MESSAGE())
        SELECT @Current_date=GETUTCDATE()

       INSERT INTO dl_config.CL_Error_Log 
       VALUES('DYNAMIC_PROC_MAIN',@CheckError,@ErrorMessage,@Current_date,NULL);

   --THROW

   End Catch

SET @Counter = @Counter +1      

    End
    
GO
sql-server stored-procedures azure-synapse

评论

1赞 GarethD 10/25/2023
如果您不想因错误而退出,请不要将错误抛出到块中。相反,只需记录它,并在 try/catch 块之外增加计数器。无论如何,有一个 try/catch 块来捕获错误,除了抛出它之外什么都不做,这是毫无意义的。CATCH
0赞 Charlieface 10/25/2023
这个过程到底在做什么,它需要循环运行?
0赞 John 10/25/2023
@Charlieface 此循环自动执行。这是简化手动干预所必需的。
0赞 Charlieface 10/25/2023
是的,我要说的是:为什么它需要是一个循环?你几乎从不需要SQL中的循环,所以如果你展示过程的实际作用,我们也许可以改进它。
0赞 John 10/25/2023
@GarethD我已经以给定的方式尝试过了。但是在异常的情况下,循环会继续执行。意味着无限循环。

答:

0赞 Zohar Peled 10/25/2023 #1

如果您希望您的过程在出错时继续,则不应在捕获它(或使用 )后抛出它(或使用 )。相反,您可以使用表、表变量或临时表来存储错误信息并继续循环。raiseerror

下面是一个示例:

DECLARE @Errors as Table
(
    Severity int,
    State int,
    Message nvarchar(4000)
);

WHILE (@Counter <= @VMaxlevel )
BEGIN TRY
    EXEC DYNAMIC_PROC
END TRY
BEGIN CATCH
    INSERT INTO @Errors(Severity, State, Message)
    VALUES(ERROR_SEVERITY(), ERROR_STATE(), ERROR_MESSAGE());
END CATCH
-- This will ensure the counter will be raised even in case of an error
SET @Counter = @Counter +1
END

顺便说一句,循环通常是在 SQL 中使用的错误工具,所以如果可以完全避免循环,那可能是一个更好的做法。

评论

0赞 John 10/25/2023
@GarethD 感谢您的回复。我会尝试确认。
0赞 John 10/25/2023
@GarethD Loops 实际上用于自动化。除此之外还有更好的方法吗?你能提出建议吗?
1赞 Zohar Peled 10/25/2023
我不是 GarethD,但在不知道具体细节的情况下,很难判断你是否真的可以避免循环。
0赞 GarethD 10/27/2023 #2

您的问题是您现在已经将递增计数器移到了循环本身之外。你有这个:SET

WHILE(@Counter <= @VMaxlevel)
BEGIN TRY
....
END TRY
BEGIN CATCH
....
END CATCH

SET @Counter = @Counter + 1;

由于您没有使用 is using your to determine 语句。这里需要一个额外的计数器,所以你在try/catch块之外,但在循环内部增加计数器BEGIN/ENDWHILEBEGIN TRY/END CATCHBEGIN/END

WHILE(@Counter <= @VMaxlevel)
BEGIN
    BEGIN TRY
    ....
    END TRY
    BEGIN CATCH
    ....
    END CATCH

    SET @Counter = @Counter + 1;
END

老实说,我几乎无法理解您的代码试图做什么,但我无法想象任何一种情况,即循环中的循环是一个好主意。在不知道修复程序是什么的情况下,很难确切地说出修复程序是什么,但几乎可以肯定的是,有一种更有效、更易于维护的方法。DYNAMIC_PROC

如果你的嵌套 BEGIN/END 和循环变得如此复杂,以至于即使是作者也无法跟踪哪个块中的内容,那么可能是时候重新考虑这种方法了......