恢复非插入行Oracle

时间:2016-08-18 15:16:51

标签: oracle plsql

我有10.000行要插入表格。

对于oracle中的FORALL插入...

FORALL x IN TABLE_NAME.First .. TABLE_NAME.Last
  INSERT
  INTO TABLE_NAME VALUES
    (
      TABLE_NAME(x).VAL1,
      TABLE_NAME(x).VAL2,
      TABLE_NAME(x).VAL3,
      TABLE_NAME(x).VAL4,
      TABLE_NAME(x).VAL5
    );

如何从因违反约束而未插入表格的行中恢复数据,以便将这些项目插入拒绝项目的非类型表中?

1 个答案:

答案 0 :(得分:4)

您可以使用save exceptions clause of the forall statement收集错误,然后使用the sql%bulk_exceptions implicit cursor attribute查看实际发生的情况。该文档中有an example,但在您的情况下,您可以(使用组合表和数据):

create table your_table (val1 number primary key, val2 number, val3 number, val4 number, val5 number);

declare
  type l_table_type is table of your_table%rowtype;
  l_table l_table_type := l_table_type();

  dml_errors exception;
  pragma exception_init(dml_errors, -24381);
begin
  l_table.extend;
  l_table(l_table.count).val1 := 1;
  l_table(l_table.count).val2 := 1.2;
  l_table(l_table.count).val3 := 1.3;
  l_table(l_table.count).val4 := 1.4;
  l_table(l_table.count).val5 := 1.5;

  l_table.extend;
  l_table(l_table.count).val1 := 2;
  l_table(l_table.count).val2 := 2.2;
  l_table(l_table.count).val3 := 2.3;
  l_table(l_table.count).val4 := 2.4;
  l_table(l_table.count).val5 := 2.5;

  l_table.extend;
  l_table(l_table.count).val1 := 1;
  l_table(l_table.count).val2 := 3.2;
  l_table(l_table.count).val3 := 3.3;
  l_table(l_table.count).val4 := 3.4;
  l_table(l_table.count).val5 := 3.5;

  forall x in l_table.first .. l_table.last save exceptions
    insert
    into your_table values
      (
        l_table(x).val1,
        l_table(x).val2,
        l_table(x).val3,
        l_table(x).val4,
        l_table(x).val5
      );

exception
  when dml_errors then
    for i in 1..sql%bulk_exceptions.count loop
      dbms_output.put_line('Index ' || sql%bulk_exceptions(i).error_index
        || ' error ' || -sql%bulk_exceptions(i).error_code);
      dbms_output.put_line(' val1: ' || l_table(sql%bulk_exceptions(i).error_index).val1);
      dbms_output.put_line(' val2: ' || l_table(sql%bulk_exceptions(i).error_index).val2);
      dbms_output.put_line(' val3: ' || l_table(sql%bulk_exceptions(i).error_index).val3);
      dbms_output.put_line(' val4: ' || l_table(sql%bulk_exceptions(i).error_index).val4);
      dbms_output.put_line(' val5: ' || l_table(sql%bulk_exceptions(i).error_index).val5);
    end loop;
end;
/

产生输出:

PL/SQL procedure successfully completed.

Index 3 error -1
 val1: 1
 val2: 3.2
 val3: 3.3
 val4: 3.4
 val5: 3.5

成功插入了val1设置为1的第一个集合元素;第二个获得了唯一约束异常而不是 - 但它被放入批量异常机制而不是导致整个语句失败。

然后,您可以决定是引发异常(或重新引发),还是立即回滚(可能是保存点);或者提交没有错误的插入。

您也可以在被拒绝的项目表中插入相同的值,但如果您要回滚其他更改,则需要小心一点(可能您不会在那里情景虽然)。

您无法直接使用其他forall来执行此操作 - 由于l_table(sql%bulk_exceptions(i).error_index).val1字符,引用values()子句中的%会引发ORA-00911 - 因此,您必须在for循环内进行单独插入,或将值复制到另一个集合并从中进行批量插入。除非你期望大量拒绝,否则单个插件可能就足够了。