4

マージステートメントのソースとして配列を使用することは可能ですか?

たとえば、以下のマージ ステートメントがあり、コンパイルするとエラーが発生します。配列をソーステーブルとしてマージを使用するにはどうすればよいですか?

PLS-00436: implementation restriction: cannot reference fields of BULK In-BIND 
table of records 

手続きコード

CREATE or REPLACE PROCEDURE my_proc (varray IN my_array)
     AS
     BEGIN
          FORALL i IN varray.first..varray.last
          MERGE INTO tab t
          USING dual
          ON ( t.proj_id = varray(i).proj_id)
          WHEN MATCHED THEN
          UPDATE  set
          proj_title = varray (i).proj_title
                      WHERE   proj_id = varray (i).proj_id
            WHEN NOT MATCHED THEN
            insert (proj_id,proj_title)
            values (varray (i).proj_id,varray (i).proj_title);
         values (varray (i).proj_id,varray (i).proj_title);
4

3 に答える 3

5

FORALLOracle 10g には制限があります。ステートメント内のレコードの個々のフィールドにアクセスすることはできません。Oracle 11g を使用している場合は、それを行うことができます。

ただし、回避策はあります。そのうちのいくつかを提案する次の記事をお勧めします: PLS-00436 in 10g - 回避策

于 2013-11-11T13:08:55.140 に答える
2

MERGE以下から選択することにより、節でソース データセットを生成できますDUAL

SQL> set serveroutput on
SQL> create table projects (
  2     proj_id integer not null primary key,
  3     proj_title varchar2(20)
  4  );

Table created.

SQL> insert into projects (proj_id, proj_title) values (1, 'Project One');

1 row created.

SQL> insert into projects (proj_id, proj_title) values (2, 'Project Two');

1 row created.

SQL> commit;

Commit complete.

SQL> select *
  2    from projects;

   PROJ_ID PROJ_TITLE
---------- --------------------
         1 Project One
         2 Project Two

2 rows selected.

SQL> declare
  2     type varray_t is varray(2) of projects%rowtype;
  3     arr varray_t;
  4  begin
  5     with test_data as (select 2 as proj_id, 'New Project Two' as proj_title from dual
  6                        union all select 3 as proj_id, 'New Project Three' as proj_title from dual)
  7     select proj_id, proj_title
  8       bulk collect into arr
  9       from test_data;
 10
 11     forall i in arr.first .. arr.last
 12        merge into projects
 13        using (select arr(i).proj_id as proj_id,
 14                      arr(i).proj_title as proj_title
 15                 from dual) mrg
 16           on (projects.proj_id = mrg.proj_id)
 17         when matched then update set projects.proj_title = mrg.proj_title
 18         when not matched then insert (proj_id, proj_title) values (mrg.proj_id, mrg.proj_title);
 19
 20     dbms_output.put_line(sql%rowcount || ' rows merged');
 21
 22     commit;
 23  end;
 24  /
2 rows merged

PL/SQL procedure successfully completed.

SQL> select *
  2    from projects;

   PROJ_ID PROJ_TITLE
---------- --------------------
         1 Project One
         2 New Project Two
         3 New Project Three

3 rows selected.
于 2013-11-11T12:54:41.420 に答える
2

ここでの問題は、SET句とWHERE句で同じコレクションを参照していることです。Forall ステートメントについては、Oracle ドキュメントを参照してください。制限セクションの 2 番目の箇条書きに移動してください。

varrayコレクションはキーワードであるため、別の名前に変更することをお勧めします。また、このコレクションを複数のスカラー コレクション (1 つの列のみを持つ varray または入れ子になったテーブル) に分割し、これらのコレクションを forall ステートメントで使用することもお勧めします。

于 2013-11-11T12:34:23.693 に答える