2

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

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 建议使用全局临时表。将数据插入 GTT,然后通过 DB 链接,对于已经属于用户定义类型的一组数据来说似乎是一种过度杀伤。

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

是否有另一种更简单或更少 DMLy 的方法来绕过这个限制?

4

2 回答 2

2

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

于 2012-05-10T13:06:22.833 回答
1

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

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

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

于 2012-06-15T11:40:20.060 回答