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: ("SCHEMA"."TMP_BEN_TEST"."A") に NULL を挿入できません 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 で実行できる方法もありません。コードの大部分は、ユーザー定義型で実行する必要があります。
この制限を回避する別の方法はありますか?