web-dev-qa-db-ja.com

PL / SQL:テーブルから連想配列への選択

1つのクエリでpl/sql連想配列にデータを選択しようとしています。ハードコードされたキーでこれを実行できることはわかっていますが、代わりに別の列(キー列)を参照できる方法があるかどうかを確認したいと思いました。


DECLARE
TYPE VarAssoc IS TABLE OF varchar2(2) INDEX BY varchar2(3);
vars VarAssoc;
BEGIN
SELECT foo, bar INTO vars(foo) FROM schema.table;
END;

これを行うとfooを宣言する必要があるというエラーが表示されます。関連付けられた配列を1つのクエリで作成する方法はありますか、それともFORループにフォールバックする必要がありますか?

14
Seaux

APCの回答についてのコメントを読んでください。自分でこれを理解したようです。しかし、私は将来の検索者のためにとにかく答えを入れると思った。

これはより単純なコードですが、BULK COLLECTを使用する速度の利点はありません。クエリによって返された行をループして、連想配列の要素を個別に設定するだけです。

DECLARE
  TYPE VarAssoc IS TABLE OF varchar2(200) INDEX BY varchar2(30);
  vars VarAssoc;
BEGIN
  FOR r IN (SELECT table_name,tablespace_name FROM user_tables) LOOP
    vars(r.table_name) := r.tablespace_name;
  END LOOP;

  dbms_output.put_line( vars('Java$OPTIONS') );
END;
17
Dave Costa

それが可能であるならばそれはきちんとしているでしょう、しかしそれはこれを達成する簡単な方法ではありません。

私たちができることは、データを通常のPL/SQLコレクションにロードし、それを連想配列にロードすることです。これがテーブルをループするだけよりも速いかどうかは、問題です。データの負荷を処理しているのでなければ、おそらく問題ではありません。

このテストデータを考えると...

SQL> select * from t23
  2  order by c1
  3  /

C1 C2
-- ---
AA ABC
BB BED
CC CAR
DD DYE
EE EYE
ZZ Zoo

6 rows selected.

SQL>

... 2つの手順で連想配列を設定できます。

SQL> set serveroutput on
SQL>
SQL> declare
  2      type varassoc is table of varchar2(3) index by varchar2(2);
  3      vars varassoc;
  4
  5      type nt is table of t23%rowtype;
  6      loc_nt nt;
  7
  8  begin
  9      select * bulk collect into loc_nt from t23;
 10      dbms_output.put_line('no of recs = '||sql%rowcount);
 11
 12      for i in loc_nt.first()..loc_nt.last()
 13      loop
 14          vars(loc_nt(i).c1) := loc_nt(i).c2;
 15      end loop;
 16
 17      dbms_output.put_line('no of vars = '||vars.count());
 18
 19      dbms_output.put_line('ZZ = '||vars('ZZ'));
 20
 21  end;
 22  /
no of recs = 6
no of vars = 6
ZZ = Zoo

PL/SQL procedure successfully completed.

SQL>

本当の問題は、おそらく連想配列へのデータ投入がテーブル内の行を選択することよりも優れているかどうかです。確かに11g Enterpriseエディションを使用している場合は、代わりに 結果セットキャッシュ を検討する必要があります。

6
APC

連想配列と完全に結婚していますか?そして、文字キーを使用して配列に対してルックアップを実行できるようにしたいので、これを行っていると思います。

もしそうなら、代わりにこれをコレクション型として実装することを検討しましたか?

例えば.

CREATE OR REPLACE TYPE VAR_ASSOC as OBJECT(
  KEYID   VARCHAR2(3),
  DATAVAL VARCHAR2(2)
)
/

CREATE OR REPLACE TYPE VAR_ASSOC_TBL AS TABLE OF VAR_ASSOC
/

CREATE OR REPLACE PROCEDURE USE_VAR_ASSOC_TBL
AS
  vars Var_Assoc_tbl; 
  -- other variables...
BEGIN 
    select cast ( multiset (
                        select foo as keyid,
                               bar as dataval
                        from   schema.table
                           ) as var_Assoc_tbl
                )
     into vars
     from dual;   
     -- and later, when you want to do your lookups
     select  ot.newfoo 
            ,myvars.dataval
            ,ot.otherval
     into   ....       
     from   schema.other_Table ot
     join   table(vars) as myvars
     on     ot.newfoo = myvars.keyid;
end;
/     

これにより、文字のキー値による検索が可能になり、すべてを一括で実行できます。

0