批量收集到 DBMS_OUTPUT 中的数组和错误处理

Posted

技术标签:

【中文标题】批量收集到 DBMS_OUTPUT 中的数组和错误处理【英文标题】:Bulk collect into array and error handling in DBMS_OUTPUT 【发布时间】:2017-12-06 22:54:01 【问题描述】:

我正在将数据从表 A 复制到表 B。在表 A 中,我有四个国家/地区列(EN、ES、RU、UK)。每个国家的列是表 B 中的单独行。此外,表 B 中的每一行都必须重复并接收下一个序列号。

表 A - 我的光标

+---------+---------+---------+---------+---------+
| Company |   EN    |   ES    |   RU    |   UK    |
+---------+---------+---------+---------+---------+
| Intel   | 123 345 | 453 343 | 444 101 | 110 232 |
+---------+---------+---------+---------+---------+

表 B

+---------+---------+-----+
| Company | Country | SEQ |
+---------+---------+-----+
| Intel   | 123 345 |   0 |
| Intel   | 123 345 |   1 |
| Intel   | 453 343 |   0 |
| Intel   | 453 343 |   1 |
| INTEL   | 444 101 |   0 |
| INTEL   | 444 101 |   1 |
| INTEL   | 110 232 |   0 |
| INTEL   | 110 232 |   1 |
+---------+---------+-----+

在表 A 中,我有 1,000,000 行。 在表 B 中,我应该有 1,000,000(行)x 4(国家)x 2(序列)= 8,000,000。

我准备了插入数据的过程。

BEGIN

OPEN my_cursor;
    LOOP
        EXIT WHEN my_cursor%notfound;
        FETCH my_cursor BULK COLLECT INTO TAB LIMIT 500;

        FOR y in 0..1 LOOP 

                FORALL x IN TAB.first..TAB.last 
                    INSERT INTO table_B ("company","country","seq") VALUES (tab(x)."company", tab(x)."EN", y);

                FORALL x IN TAB.first..TAB.last
                    INSERT INTO table_B ("company","country","seq") VALUES (tab(x)."company", tab(x)."ES", y);

                FORALL x IN TAB.first..TAB.last 
                    INSERT INTO table_B ("company","country","seq") VALUES (tab(x)."company", tab(x)."RU", y);

                FORALL x IN TAB.first..TAB.last 
                    INSERT INTO table_B ("company","country","seq") VALUES (tab(x)."company", tab(x)."UK", y);

        END LOOP;

        COMMIT;
    END LOOP;     
CLOSE my_cursor;

END;

在表 B 中出现 DML 错误的情况下,我必须从数组(选项卡)中返回变量的值以及 DBMS_OUTPUT 中的错误代码 例如:

DBMS_OUTPUT.PUT_LINE(tab(x)."company" || ' ' || tab(x)."UK" || SQLERRM);

是否可以处理此类错误?我该如何实施这样的解决方案? .

【问题讨论】:

【参考方案1】:

是的,您可以处理此类错误并继续使用SAVE EXCEPTIONSFORALL 进行所有插入,如下所示: PLSQL 在所有语句执行后引发ORA:24381

BEGIN
FORALL x IN TAB.first..TAB.last SAVE EXCEPTIONS
                    INSERT INTO table_B ("company","country","seq") VALUES (tab(x)."company", tab(x)."EN", y);
EXCEPTION 
WHEN OTHERS THEN
 IF sqlcode = -24381
     FOR indx IN 1 .. SQL%BULK_EXCEPTIONS.COUNT
         LOOP
            DBMS_OUTPUT.put_line (
                  SQL%BULK_EXCEPTIONS (indx).ERROR_INDEX
               || ‘: ‘
               || SQL%BULK_EXCEPTIONS (indx).ERROR_CODE);
         END LOOP;
else 
raise;
end if;
END;

【讨论】:

【参考方案2】:

您可以通过使用FOR ALL ... SAVE EXCEPTIONS 指令来实现您的目标。 这将为您提供以下信息:

DECLARE
    ln_error_count NUMBER;
    ln_line_error  NUMBER;
BEGIN

    OPEN my_cursor;
    LOOP
        EXIT WHEN my_cursor%notfound;
        FETCH my_cursor BULK COLLECT INTO TAB LIMIT 500;

        FOR y in 0..1 LOOP

            BEGIN
                FORALL x IN TAB.first..TAB.last SAVE EXCEPTIONS
                    INSERT INTO table_B ("company","country","seq") VALUES (tab(x)."company", tab(x)."EN", y);
            EXCEPTION
                WHEN ex_dml_errors THEN
                    ln_error_count := SQL%BULK_EXCEPTIONS.count;
                    FOR i IN 1 .. ln_error_count LOOP
                        ln_line_error := SQL%BULK_EXCEPTIONS(i).error_index;
                        DBMS_OUTPUT.PUT_LINE(tab(ln_line_error)."company" || ' ' || tab(ln_line_error)."EN" || SQLERRM(-SQL%BULK_EXCEPTIONS(i).ERROR_CODE));
                    END LOOP;
            END;

            BEGIN
                FORALL x IN TAB.first..TAB.last SAVE EXCEPTIONS
                    INSERT INTO table_B ("company","country","seq") VALUES (tab(x)."company", tab(x)."ES", y);
            EXCEPTION
                WHEN ex_dml_errors THEN
                    ln_error_count := SQL%BULK_EXCEPTIONS.count;
                    FOR i IN 1 .. ln_error_count LOOP
                        ln_line_error := SQL%BULK_EXCEPTIONS(i).error_index;
                        DBMS_OUTPUT.PUT_LINE(tab(ln_line_error)."company" || ' ' || tab(ln_line_error)."ES" || SQLERRM(-SQL%BULK_EXCEPTIONS(i).ERROR_CODE));
                    END LOOP;
                END;

            BEGIN
                FORALL x IN TAB.first..TAB.last SAVE EXCEPTIONS
                    INSERT INTO table_B ("company","country","seq") VALUES (tab(x)."company", tab(x)."RU", y);
            EXCEPTION
                WHEN ex_dml_errors THEN
                    ln_error_count := SQL%BULK_EXCEPTIONS.count;
                    FOR i IN 1 .. ln_error_count LOOP
                        ln_line_error := SQL%BULK_EXCEPTIONS(i).error_index;
                        DBMS_OUTPUT.PUT_LINE(tab(ln_line_error)."company" || ' ' || tab(ln_line_error)."RU" || SQLERRM(-SQL%BULK_EXCEPTIONS(i).ERROR_CODE));
                    END LOOP;
            END;

            BEGIN
                FORALL x IN TAB.first..TAB.last SAVE EXCEPTIONS
                    INSERT INTO table_B ("company","country","seq") VALUES (tab(x)."company", tab(x)."UK", y);
            EXCEPTION
                WHEN ex_dml_errors THEN
                    ln_error_count := SQL%BULK_EXCEPTIONS.count;
                    FOR i IN 1 .. ln_error_count LOOP
                        ln_line_error := SQL%BULK_EXCEPTIONS(i).error_index;
                        DBMS_OUTPUT.PUT_LINE(tab(ln_line_error)."company" || ' ' || tab(ln_line_error)."UK" || SQLERRM(-SQL%BULK_EXCEPTIONS(i).ERROR_CODE));
                    END LOOP;
            END;
        END LOOP;

        COMMIT;
    END LOOP;     
    CLOSE my_cursor;

END;

【讨论】:

虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接答案可能会失效。 - From Review 感谢@max23_ 的评论。我已经相应地更新了我的帖子。

以上是关于批量收集到 DBMS_OUTPUT 中的数组和错误处理的主要内容,如果未能解决你的问题,请参考以下文章

如何批量收集到子查询中的 UDT 类型

批量收集到表类型的对象

PL / SQL:ORA-00907:批量收集错误

从引用游标中获取批量收集时出现不一致的数据类型错误

oracle ORA-06502:PL/SQL:数字或值错误:批量绑定:截断绑定

使用 LOOP 将 Oracle 批量收集到集合中