1

データベース テーブルの %rowtype の型テーブルのコレクションを宣言するパッケージがあります。また、パッケージ レベルの変数にデータを入力する関数も宣言します。dbms_output でデータを出力できるようになりました。問題ないようです。

しかし、一部の SQL でパッケージ レベルの変数を使用すると、次のエラーが発生します。

ORA-21700: object does not exist or is marked for delete
ORA-06512: at "TESTDB.SESSIONGLOBALS", line 17
ORA-06512: at line 5

これが私のコードです:

いくつかのダミー データを作成します。

drop table "TESTDATA";
/
CREATE TABLE "TESTDATA" 
(   "ID" NUMBER NOT NULL ENABLE, 
    "NAME" VARCHAR2(20 BYTE), 
    "STATUS" VARCHAR2(20 BYTE)
);
/   
insert into "TESTDATA" (id, name, status) values (1, 'Hans Wurst', 'J');
insert into "TESTDATA" (id, name, status) values (2, 'Hans-Werner', 'N');
insert into "TESTDATA" (id, name, status) values (3, 'Hildegard v. Bingen', 'J');
/

パッケージを作成します。

CREATE OR REPLACE 
PACKAGE SESSIONGLOBALS AS 
  type t_testdata is table of testdata%rowtype;
  v_data t_testdata := t_testdata();
  function load_testdata return t_testdata;

END SESSIONGLOBALS;

およびパッケージ本体:

CREATE OR REPLACE
PACKAGE BODY SESSIONGLOBALS AS
  function load_testdata return t_testdata AS
    v_sql varchar2(500);
  BEGIN
    if SESSIONGLOBALS.v_data.count = 0 
    then
      v_sql := 'select * from testdata';
      execute immediate v_sql 
      bulk collect into SESSIONGLOBALS.v_data;

      dbms_output.put_line('data count:');
      dbms_output.put_line(SESSIONGLOBALS.v_data.count);

    end if; -- SESSIONGLOBALS.v_data.count = 0 

    -- ******************************
    -- this line throws the error
    insert into testdata select * from table(SESSIONGLOBALS.v_data);
    -- ******************************

    return SESSIONGLOBALS.v_data;
  END load_testdata;

END SESSIONGLOBALS;

サンプルを実行します。

DECLARE
  v_Return SESSIONGLOBALS.T_TESTDATA;
BEGIN
    v_Return := SESSIONGLOBALS.LOAD_TESTDATA();
    dbms_output.put_line('data count (direct access):');
    dbms_output.put_line(SESSIONGLOBALS.v_data.count);
    dbms_output.put_line('data count (return value of function):');
    dbms_output.put_line(v_Return.count);
END;

上記の行がコメントアウトされている場合、期待される結果が得られます。

上記の例外が発生する理由を誰か教えてもらえますか?

ところで:コンパイル時にテーブル名がわからないため、動的SQLとしてコレクションにデータを入力するステートメントを実行することは絶対に必要です。(v_sql := 'select * from testdata';)

4

3 に答える 3

1

パッケージ レベルの型は、SQL では使用できません。SQL がパッケージ内から呼び出されたとしても、そのパッケージの型を認識できません。

どのようにしてそのエラー メッセージが表示されたのかわかりません。パッケージをコンパイルしたときに、このエラーが表示されました。これは問題のヒントを示しています。

PLS-00642: local collection types not allowed in SQL statements

この問題を解決するには、型とその型のネストされたテーブルを作成します。

create or replace type t_testdata_rec is object
(
    "ID" NUMBER, 
    "NAME" VARCHAR2(20 BYTE), 
    "STATUS" VARCHAR2(20 BYTE)
);

create or replace type t_testdata as table of t_testdata_rec;
/

パッケージ変数を設定する動的 SQL はさらに複雑になります。

  execute immediate
  'select cast(collect(t_testdata_rec(id, name, status)) as t_testdata)
  from testdata ' into SESSIONGLOBALS.v_data;

しかし、これでインサートはそのまま機能します。

于 2013-06-09T04:50:47.857 に答える