PL/SQL内でSQLクエリを実行し、結果を連想配列に入力します。ここで、SQLの列の1つが連想配列のキーになります。たとえば、列のあるテーブルPerson
があるとします。
_PERSON_ID INTEGER PRIMARY KEY
PERSON_NAME VARCHAR2(50)
_
...そして次のような値:
_ PERSON_ID | PERSON_NAME
------------------------
6 | Alice
15 | Bob
1234 | Carol
_
この連想配列のキー_6
_の値がAlice
になるように、このテーブルをTABLE OF VARCHAR2(50) INDEX BY INTEGER
に一括収集したいと思います。これはPL/SQLで実行できますか?もしそうなら、どのように?
いいえ、2つのコレクション(id、name)を使用するか、要素タイプがレコードであるコレクションを使用する必要があります。
後者のサンプルは次のとおりです。
cursor getPersonsCursor is
SELECT ID, Name
FROM Persons
WHERE ...;
subtype TPerson is getPersonsCursor%rowtype;
type TPersonList is table of TPerson;
persons TPersonList;
begin
open getPersonsCursor;
fetch getPersonsCursor
bulk collect into persons;
close getPersonsCursor;
if persons.Count > 0 then
for i in persons.First .. persons.Last loop
yourAssocArray(persons(i).ID) := persons(i).Name;
end loop;
end if;
連想配列のインデックスに値を指定する場合は、次の構文を使用する必要があります。
SQL> declare
2 type n_array is table of varchar2(30)
3 index by binary_integer;
4 emp_names n_array;
5 begin
6 for r in ( select ename, empno from emp )
7 loop
8 emp_names(r.empno) := r.ename;
9 end loop;
10
11 dbms_output.put_line('count='||emp_names.count()
12 ||'::last='||emp_names.last());
13 dbms_output.put_line(emp_names(8085));
14
15 end;
16 /
count=19::last=8085
TRICHLER
PL/SQL procedure successfully completed.
SQL>
can連想配列に一括収集を設定しますが、インデックスが整数の場合に限り、(暗黙の)ROWNUMでインデックスを作成できます。つまり、スパースキーではありません。
SQL> declare
2 type n_array is table of varchar2(30)
3 index by binary_integer;
4 emp_names n_array;
5 begin
6 select ename
7 bulk collect into emp_names
8 from emp ;
9
10 dbms_output.put_line('count='||emp_names.count()
11 ||'::last='||emp_names.last());
12 dbms_output.put_line(emp_names(19));
13
14 end;
15 /
count=19::last=19
FEUERSTEIN
PL/SQL procedure successfully completed.
SQL>
公平を期すために、BULK COLLECTを使用する必要がある場合は、連想配列に適しているよりも多くのデータを処理している可能性があります。
編集
2つのアプローチの安価なパフォーマンステスト:
SQL> declare
2 type n_array is table of varchar2(30)
3 index by binary_integer;
4 emp_names n_array;
5 s_time pls_integer;
6 e_time pls_integer;
7 begin
8 s_time := dbms_utility.get_time;
9 select ename
10 bulk collect into emp_names
11 from big_emp
12 where rownum <= 500;
13 dbms_output.put_line('bulk collect elapsed time = '
14 ||to_char(dbms_utility.get_time - s_time));
15 s_time := dbms_utility.get_time;
16 for r in ( select ename, empno from big_emp
17 where rownum <= 500 )
18 loop
19 emp_names(r.empno) := r.ename;
20 end loop;
21 dbms_output.put_line('sparse array elapsed time = '
22 ||to_char(dbms_utility.get_time - s_time));
23 end;
24 /
bulk collect elapsed time = 0
sparse array elapsed time = 0
PL/SQL procedure successfully completed.
SQL>
壁掛け時計の性能テストは悪名高いロープです。ただし、数百のレコードの場合、関連付け配列を使用する可能性のある場所のコンテキストでは、違いについて心配する価値はほとんどありません。
編集2
@ダンは言った:
一定時間のルックアップに使用できるデータ構造に適切なサイズの行をクエリしたいというのは、かなり一般的なニーズであると私には思えます。
それは本当にあなたの「まともなサイズの数」の定義に依存します。 連想配列に数千行、文字列インデックスを入力したい場合は本当にたくさんありますか?これらの種類の数値に到達すると、特に 11g Enterprise Editionと結果セットのキャッシュ では、通常のデータベーステーブルも同様に役立つ可能性があります。