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: ("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 で実行できる方法もありません。コードの大部分は、ユーザー定義型で実行する必要があります。

この制限を回避する別の方法はありますか?

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 に答える