在数据库链接上使用时,似乎存在禁止在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的解决方法?
答案 0 :(得分:2)
您在远程数据库上有哪些限制?如果你可以在那里创建对象,你有一个解决方法:在远程数据库上创建集合类型和一个过程,该过程将集合作为参数并执行FORALL语句。
答案 1 :(得分:1)
如果在db2中创建t__test / r_test类型然后在db1上为它们创建公共同义词,那么您应该能够调用从db1到db2的过程来填充t_table并返回到db1。然后你应该能够插入到本地表中。
我假设您将在现实世界中使用打包类型和过程,而不是匿名块。
此外,对于大数据集来说,它不是理想的解决方案,那么GTT或类似技术会更好。