创建通用的PL SQL过程以动态记录批量收集错误

问题描述

我最近了解了在SQL中使用BULK COLLECT的知识。我找到了一种处理DML语句生成的异常的方法:

SET SERVEROUTPUT ON SIZE 99999;
--
DECLARE
--
bulk_errors       exception;
PRAGMA exception_init(bulk_errors,-24381);
--
--
CURSOR cursEmployee IS
SELECT EMPLOYEE_ID,EMPLOYEE_NAME
FROM EMPLOYEE;

TYPE employee_table IS TABLE OF cursEmployee%rowtype;
employee_rec            employee_table;
--
BEGIN
--  
        OPEN cursEmployee;
        FETCH cursEmployee BULK COLLECT INTO employee_rec LIMIT 10000;
        --
        WHILE employee_rec.COUNT != 0 LOOP
            --
            FORALL indx IN INDICES OF employee_rec save exceptions
                --
                
                INSERT INTO EMPLOYEE (
                    EMPLOYEE_ID,EMPLOYEE_NAME
                    )
                VALUES (
                    employee_rec.EMPLOYEE_ID,employee_rec.EMPLOYEE_NAME
                    );
            --
            COMMIT;
            --
            FETCH cursEmployee BULK COLLECT INTO employee_rec LIMIT 10000;
            --
        
        END LOOP;
           exception when bulk_errors then
             
       
        for i in 1 .. sql%bulk_exceptions.COUNT loop
            dbms_output.put_line('Employee Id : ' || sql%bulk_exceptions(i).EMPLOYEE_ID);
            dbms_output.put_line('Employee Id : ' || sql%bulk_exceptions(i).EMPLOYEE_NAME);
            dbms_output.put_line('Error Message: '||sqlerrm(-sql%bulk_exceptions(i).error_code));
       
        end loop;
           
    CLOSE  cursEmployee;
       
END;
/  

然后我创建了一个通用过程来记录异常:

CREATE OR REPLACE PROCEDURE LOG_BULK_EXCEPTIONS IS
    BEGIN
        IF SQL%BULK_EXCEPTIONS.COUNT > 0 THEN
            DBMS_OUTPUT.PUT_LINE(' Errors occured during a BULK COLLECT statement : ');
            DBMS_OUTPUT.PUT_LINE(' Number of exceptions : ' || SQL%BULK_EXCEPTIONS.COUNT );
            --
            FOR i IN 1 .. SQL%BULK_EXCEPTIONS.COUNT LOOP    
                DBMS_OUTPUT.PUT_LINE(' Error : ' || SQLERRM(-SQL%BULK_EXCEPTIONS(i).ERROR_CODE));
                DBMS_OUTPUT.PUT_LINE('Backtrace : ' || DBMS_UTILITY.FORMAT_ERROR_BACKTRACE);    
            END LOOP;
        --
        END IF;
END;
/

我发现这种记录异常的方式有点受限制:我们只得到错误(数值,不能将null插入等等)。我正在寻找一种方法来添加有关引发错误的游标中的数据/特定元素的信息。

为此,我需要将列名作为参数传递给我的过程,并将其连接起来以获得这种语句:

  dbms_output.put_line(' Internal Id : ' || sql%bulk_exceptions(i).MY_COLUMN_PARAMETER);

这样,我可以在数据库中的任何地方使用此日志记录过程,这很好。

有人知道如何将字符串参数连接到此“ sql%bulk_exceptions(i)”并正确执行吗?

解决方法

是的,只要您想在原始集合中添加什么内容,就可以得到您想要的东西。 sql%bulk_exceptions集合还有另一列ERROR_INDEX。它包含原始集合中行的索引。这样,您就可以通过

引用该集合中的值
  employee_rec(sql%bulk_exceptions(i).error_index).id;
  employee_rec(sql%bulk_exceptions(i).error_index).name;

您的程序还有另一个问题。您的异常块在循环处理批量集合之外。结果,您的大容量缓冲区将仅在第一个缓冲区包含错误之前进行处理;没有后续的缓冲区将被处理。您可以通过在处理循环内创建一个块并在内部块内处理异常来避免这种情况。另外,很高兴看到您已努力实际上关闭了光标。但是,它在异常块中,因此仅在有异常时才执行。有关每个示例,请参见here。由于我不想为演示创建超过10000行,因此我将批量限制降低为3。

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...