克服数据库链接上批量插入的限制

时间:2012-05-10 12:50:57

标签: oracle plsql oracle11g oracle9i

在数据库链接上使用时,似乎存在禁止在Oracle上使用forall .. insert的实现限制。这是一个简单的例子来说明:

connect schema/password@db1

create table tmp_ben_test (
   a number
 , b number
 , c date
 , constraint pk_tmp_ben_test primary key (a, b)
    );

Table created.

connect schema/password@db2
Connected.

declare

   type r_test is record ( a number, b number, c date);
   type t__test is table of r_test index by binary_integer;
   t_test t__test;

   cursor c_test is
    select 1, level, sysdate
      from dual
   connect by level <= 10
           ;

begin

   open c_test;
   fetch c_test bulk collect into t_test;

   forall i in t_test.first .. t_test.last
     insert into tmp_ben_test@db1
     values t_test(i)
            ;

   close c_test;

end;
/

非常令人困惑地在9i中失败,出现以下错误:

  

第1行的错误:ORA-01400:无法插入NULL   (“SCHEMA”。“TMP_BEN_TEST”。“A”)ORA-02063:DB1的前一行   ORA-06512:第18行

如果只是在检查了11g后我发现这是一个实施限制。

  

第18行的错误:ORA-06550:第18行,第4栏:PLS-00739:FORALL   远程表不支持INSERT / UPDATE / DELETE

真正明显的方法是将forall ..更改为:

for i in t_test.first .. t_test.last loop
    insert into tmp_ben_test@db1
    values t_test(i);
end loop;

但是,如果可能的话,我宁愿将其保留到单个插页中。 Tom Kyte suggests the use of a global temporary table。将数据插入GTT然后通过数据库链接,对于已经处于用户定义类型的一组数据来说,似乎是一种过度杀伤。

只是为了澄清这个例子与实际发生的事情相比,极其简单。我们无法做一个简单的insert into,并且无法在GTT上完成所有操作。代码的大部分必须以用户定义的类型完成。

是否有另一种更简单或更少DML的解决方法?

2 个答案:

答案 0 :(得分:2)

您在远程数据库上有哪些限制?如果你可以在那里创建对象,你有一个解决方法:在远程数据库上创建集合类型和一个过程,该过程将集合作为参数并执行FORALL语句。

答案 1 :(得分:1)

如果在db2中创建t__test / r_test类型然后在db1上为它们创建公共同义词,那么您应该能够调用从db1到db2的过程来填充t_table并返回到db1。然后你应该能够插入到本地表中。

我假设您将在现实世界中使用打包类型和过程,而不是匿名块。

此外,对于大数据集来说,它不是理想的解决方案,那么GTT或类似技术会更好。