連想配列 (PL/SQL)

PL/SQL 連想配列とは、ユニーク・キーを値と関連付けるコレクション・タイプのことです。

連想配列には以下の特性があります。
  • 連想配列タイプを定義した後でなければ、その配列タイプの配列変数を宣言できません。 配列変数内でデータ操作が行われます。
  • 配列を初期設定する必要はありません。配列エレメントに値を割り当てるだけです。
  • 配列内のエレメント数について、定義された制限はありません。エレメントを追加するにつれて、エレメント数は動的に増加します。
  • 配列は であっても構いません。すなわち、キーに対する値の割り当てに間隔があっても構いません。
  • 値が割り当てられていない配列エレメントを参照しようとすると、例外が発生します。

TYPE IS TABLE OF ステートメントを使用して、連想配列タイプを定義します。

構文

構文図を読む構文図をスキップするTYPEassoctypeIS TABLE OF datatype INDEX BY BINARY_INTEGERPLS_INTEGERVARCHAR2(nBYTECHAR)

説明

TYPE assoctype
配列タイプの ID を指定します。
datatype
サポートされるデータ・タイプ (VARCHAR2、NUMBER、RECORD、VARRAY、または連想配列タイプなど) を指定します。 %TYPE 属性および %ROWTYPE 属性もサポートされます。
INDEX BY
この節によって導入されるデータ・タイプの 1 つによって、連想配列を索引付けすることを指定します。
BINARY INTEGER
整数値データ。
PLS_INTEGER
整数値データ。
VARCHAR2 (n[BYTE|CHAR])
最大長 n コード単位の可変長文字ストリング。最大長は、1 から 32672 までの BYTE、または 1 から 8168 までの CHAR の範囲で指定できます。 %TYPE 属性の適用対象となるオブジェクトが、BINARY_INTEGER、PLS_INTEGER、または VARCHAR2 データ・タイプである場合、%TYPE 属性もサポートされます。

連想配列タイプの変数を宣言するには、array-name assoctype と指定します。ここで、array-name は連想配列に割り当てる ID を表し、assoctype は既に宣言されている配列タイプの ID を表します。

配列に含まれる特定のエレメントを参照するには、array-name(n) と指定します。ここで、array-name は既に宣言されている配列の ID を表し、nassoctype の INDEX BY データ・タイプの値を表します。 レコード・タイプから配列が定義されている場合は、参照は array-name(n).field となります。ここで、field は、この配列タイプを定義する元となった当該レコード・タイプ内で定義されています。 このレコード全体を参照するには、field を省きます。

以下の例では、EMP 表から最初の 10 人分の従業員名を読み取り、それらを配列に格納した後、その配列の内容を表示します。
SET SERVEROUTPUT ON
/

CREATE OR REPLACE PACKAGE pkg_test_type1
IS
    TYPE emp_arr_typ IS TABLE OF VARCHAR2(10) INDEX BY BINARY_INTEGER;
END pkg_test_type1
/

DECLARE
    emp_arr         pkg_test_type1.emp_arr_typ;
    CURSOR emp_cur IS SELECT ename FROM emp WHERE ROWNUM <= 10;
    i               INTEGER := 0;
BEGIN
    FOR r_emp IN emp_cur LOOP
        i := i + 1;
        emp_arr(i) := r_emp.ename;
    END LOOP;
    FOR j IN 1..10 LOOP
        DBMS_OUTPUT.PUT_LINE(emp_arr(j));
    END LOOP;
END
/
このコードによって生成される出力例を以下に示します。
SMITH
ALLEN
WARD
JONES
MARTIN
BLAKE
CLARK
SCOTT
KING
TURNER
この例を変更して、配列定義でレコード・タイプを使用することができます。
SET SERVEROUTPUT ON
/

CREATE OR REPLACE PACKAGE pkg_test_type2
IS
    TYPE emp_rec_typ IS RECORD (
        empno       INTEGER,
        ename       VARCHAR2(10)
    );
END pkg_test_type2
/

CREATE OR REPLACE PACKAGE pkg_test_type3
IS
    TYPE emp_arr_typ IS TABLE OF pkg_test_type2.emp_rec_typ INDEX BY BINARY_INTEGER;
END pkg_test_type3
/

DECLARE
    emp_arr         pkg_test_type3.emp_arr_typ;
    CURSOR emp_cur IS SELECT empno, ename FROM emp WHERE ROWNUM <= 10;
    i               INTEGER := 0;
BEGIN
    DBMS_OUTPUT.PUT_LINE('EMPNO    ENAME');
    DBMS_OUTPUT.PUT_LINE('-----    -------');
    FOR r_emp IN emp_cur LOOP
        i := i + 1;
        emp_arr(i).empno := r_emp.empno;
        emp_arr(i).ename := r_emp.ename;
    END LOOP;
    FOR j IN 1..10 LOOP
        DBMS_OUTPUT.PUT_LINE(emp_arr(j).empno || '     ' ||
            emp_arr(j).ename);
    END LOOP;
END
/
変更されたこのコードによって生成される出力例を以下に示します。
EMPNO    ENAME
-----    -------
1001     SMITH
1002     ALLEN
1003     WARD
1004     JONES
1005     MARTIN
1006     BLAKE
1007     CLARK
1008     SCOTT
1009     KING
1010     TURNER
この例をさらに変更して、emp_rec_typ レコード・タイプを使用する代わりに、emp%ROWTYPE 属性を使用して emp_arr_typ を定義するようにできます。
SET SERVEROUTPUT ON
/

CREATE OR REPLACE PACKAGE pkg_test_type4
IS
    TYPE emp_arr_typ IS TABLE OF emp%ROWTYPE INDEX BY BINARY_INTEGER;
END pkg_test_type4
/

DECLARE
    emp_arr         pkg_test_type4.emp_arr_typ;
    CURSOR emp_cur IS SELECT empno, ename FROM emp WHERE ROWNUM <= 10;
    i               INTEGER := 0;
BEGIN
    DBMS_OUTPUT.PUT_LINE('EMPNO    ENAME');
    DBMS_OUTPUT.PUT_LINE('-----    -------');
    FOR r_emp IN emp_cur LOOP
        i := i + 1;
        emp_arr(i).empno := r_emp.empno;
        emp_arr(i).ename := r_emp.ename;
    END LOOP;
    FOR j IN 1..10 LOOP
        DBMS_OUTPUT.PUT_LINE(emp_arr(j).empno || '     ' ||
            emp_arr(j).ename);
    END LOOP;
END
/
このケースでは、出力例は前述の例と同一になります。
最後の例として、以下のようにすると、レコードの各フィールドを個別に割り当てる代わりに、r_emp から emp_arr にレコード・レベルの割り当てを行うことができます。
SET SERVEROUTPUT ON
/

CREATE OR REPLACE PACKAGE pkg_test_type5
IS
    TYPE emp_rec_typ IS RECORD (
        empno       INTEGER,
        ename       VARCHAR2(10)
    );
END pkg_test_type5
/

CREATE OR REPLACE PACKAGE pkg_test_type6
IS
    TYPE emp_arr_typ IS TABLE OF pkg_test_type5.emp_rec_typ INDEX BY BINARY_INTEGER;
END pkg_test_type6
/

DECLARE
    emp_arr         pkg_test_type6.emp_arr_typ;
    CURSOR emp_cur IS SELECT empno, ename FROM emp WHERE ROWNUM <= 10;
    i               INTEGER := 0;
BEGIN
    DBMS_OUTPUT.PUT_LINE('EMPNO    ENAME');
    DBMS_OUTPUT.PUT_LINE('-----    -------');
    FOR r_emp IN emp_cur LOOP
        i := i + 1;
        emp_arr(i) := r_emp;
    END LOOP;
    FOR j IN 1..10 LOOP
        DBMS_OUTPUT.PUT_LINE(emp_arr(j).empno || '     ' ||
            emp_arr(j).ename);
    END LOOP;
END
/