5

行 ID で削除してから、削除するデータをすぐに監査テーブルに挿入できるようにしたいと考えています。

するレコードが多すぎ INSERT INTO ... SELECT CRITERIAますDELETE ... CRITERIA

rowid とINSERT INTO ... SELECT.

パッケージ本体内:

TYPE some_type IS RECORD (
   row_id    ROWID,
   full_row  table_name%ROWTYPE
);
TYPE some_type_list IS TABLE OF some_type
   INDEX BY BINARY_INTEGER;

PROCEDURE do_stuff
IS
   lc_data  SYS_REFCURSOR;
   lt_recs  some_type_list;
BEGIN
   OPEN lc_date FOR
      SELECT rowid, a.*
      FROM   table_name;
   LOOP
      FETCH lc_data
      BULK COLLECT INTO lt_recs
      LIMIT 50000;
      EXIT WHEN lt_recs.COUNT = 0;
      --
      FORALL i IN lt_recs.FIRST..lt_recs.LAST
         DELETE table_name
         WHERE  ROWID = lt_recs(i).row_id;
      --
      FORALL i IN lt_recs.FIRST..lt_recs.LAST
         INSERT INTO table_name_audit VALUES lt_recs(i).full_row;
   END LOOP;
END;

試してみると、次のエラーが表示されます。

Line: 117 Column: 25 Type: error Text: PLS-00597: expression 'LT_RECS' in the INTO list is of wrong type

4

3 に答える 3

3

11gR2 より前のバージョンの Oracle では、BULK COLLECT を使用してレコードのコレクション (ネストしたテーブルまたは VARRAY) を作成するように制限されていました。詳細については、Oracle Docs を参照してください。

11gR2でどのように行われるかを確認したい場合は、この回答のEDIT 2セクションまでスクロールしてください。

これに代わる方法は、列ごとに個別のコレクションを使用することです。これは、最も広く使用されているアプローチです。これには、次のものがあります。

/*
TYPE some_type IS RECORD (
   row_id    ROWID,
   full_row  table_name%ROWTYPE
);
TYPE some_type_list IS TABLE OF some_type
   INDEX BY BINARY_INTEGER;
-- */
CREATE TYPE t_row_id IS TABLE OF ROWID;
CREATE TYPE t_col1 IS TABLE OF table_name.col1%TYPE;
CREATE TYPE t_col2 IS TABLE OF table_name.col2%TYPE;
CREATE TYPE t_col3 IS TABLE OF table_name.col3%TYPE;
...
...
CREATE TYPE t_colN IS TABLE OF table_name.colN%TYPE;

PROCEDURE do_stuff
IS
   lc_data  SYS_REFCURSOR;
   -- lt_recs  some_type_list;
   row_id t_row_id;
   col1 t_col1;
   col2 t_col2;
   col3 t_col3;
   ...
   ...
   colN t_colN;
BEGIN
   OPEN lc_date FOR
      SELECT rowid, a.*
      FROM   table_name;
   LOOP
      FETCH lc_data
      BULK COLLECT INTO row_id, col1, col2, col3, ..., colN
      LIMIT 50000;
      EXIT WHEN lt_recs.COUNT = 0;
      --
      FORALL i IN row_id.FIRST..row_id.LAST
         DELETE table_name
         WHERE  ROWID = row_id(i);
      --
      FORALL i IN col1.FIRST..col1.LAST
         INSERT INTO table_name_audit VALUES (col1(i), col2(i), col3(i), ..., colN(i));
   END LOOP;
END;

変更点を理解していただくために、プログラムの行の多くを削除していません。

編集:上記のOracle Docsリンクの「BULK COLLECTの制限」セクションと、こちらも参照してください。


編集#2:


CREATE TYPE ... IS OBJECTの代わりに使用する必要がありRECORDます。SELECTまた、私が試したときに行った方法でステートメントを変更する必要があります。詳細については、こちらの Oracle ドキュメントとこちらの StackOverflow の質問をご覧ください。

私のマシン(Oracle 11g R2を実行)で試したコードは次のとおりです。

-- SELECT * FROM user_objects WHERE object_type = 'TYPE'; クリアスクリーン; SERVEROUTPUT をオンに設定します。

CREATE OR REPLACE TYPE temp_t_test AS OBJECT ( -- << OBJECT, not RECORD.
  test_id  INTEGER
, test_val VARCHAR2(50)
);
/

CREATE OR REPLACE TYPE temp_tbl_test AS TABLE OF TEMP_T_TEST;
/

DECLARE
  v_test TEMP_TBL_TEST;
BEGIN
  SELECT temp_t_test(t_id, t_val) -- << Notice the syntax
  -- I'm selecting the columns as the defined OBJECT type.
  BULK COLLECT INTO v_test
    FROM (SELECT 1 AS t_id, 'ABCD' AS t_val FROM dual
          UNION ALL
          SELECT 2, 'WXYZ' FROM dual
          UNION ALL
          SELECT 3, 'PQRS' FROM dual);

  dbms_output.put_line('Bulk Collect Successful!');
END;
/

** 出力 **:

TYPE temp_t_test compiled
TYPE temp_tbl_test compiled
anonymous block completed
Bulk Collect Successful!
于 2013-03-22T19:18:38.483 に答える
2

正直なところ、私はこのアプローチを取るとはまったく思いません。

より高速な方法は、マルチテーブルの挿入を実行する方法です。

  1. 効率のためにダイレクト パス (APPEND ヒント) を使用して、監査テーブルにテーブル列を挿入します。
  2. 行 ID を on-commit-delete-rows グローバル一時テーブルに挿入します。

次に、DELETE .. WHERE ROWID IN (SELECT ORIGINAL_ROWID FROM MY_GLOBAL_TEMP_TAB) を使用して、元のテーブルに対して削除を実行します。

...そしてコミットします。

より速く、より少ないコードだと思います。

于 2013-03-23T10:28:50.857 に答える
1

11gR2で何をしようとしているのですか?どのバージョンを使用していますか?

あなたの投稿で唯一間違っているのはこれです:

OPEN lc_date FOR
  SELECT rowid, a.*
  FROM   table_name;

これであるはずです...

OPEN lc_data FOR
  SELECT a.rowid, a.*
  FROM   table_name a;

...しかし、これらは、ここに投稿するためにコードをサニタイズするときに導入したタイプミスである可能性があります。

于 2013-03-22T22:14:47.913 に答える