【发布时间】:2012-05-19 01:09:57
【问题描述】:
当通过数据库链接使用时,似乎存在禁止在 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,然后通过 DB 链接,对于已经属于用户定义类型的一组数据来说似乎是一种过度杀伤。
只是为了澄清这个例子与实际发生的事情相比非常简单化了。我们无法做一个简单的insert into,也无法在 GTT 上完成所有操作。大部分代码必须以用户定义的类型完成。
是否有另一种更简单或更少 DMLy 的方法绕过此限制?
【问题讨论】:
-
您尝试过 GTT 理念吗?比较 11g 中的性能。我想这不是矫枉过正,而是一种快速移动日期的方法。
-
不,我没试过。如果没有其他选择,我显然会。从记忆中获取某些东西似乎很奇怪。将其移动到不同的内存中,然后执行一些 DML。我希望有一个更简单的解决方案。如果存在。
-
想一想。 GTT 部分是纯 SQL,速度很快(有 dblink 惩罚)。缓慢的是带有数组的 ps/sql 部分...
标签: oracle plsql oracle11g oracle9i