An associative array is a type of collection that associates a unique key with a value. Associative arrays can use integers or strings as keys.

An associative array has the following characteristics:

  • An associative array type must be defined before array variables of that array type can be declared. Data manipulation is implemented by using array variables.
  • When an array variable is declared, an empty associative array is created. You can assign values to array elements.
  • If INDEXBY BINARY_INTEGER or PLS_INTEGER is specified, a key of the associative array can be a negative integer, a positive integer, or zero.
  • If INDEXBY VARCHAR2 is specified, a key of the associative array can be a string.
  • No limit is predefined for the number of elements in the array. The number dynamically grows as elements are added.
  • An associative array can be sparse, which means that gaps may exist in the assignment of values to keys.
  • An attempt to reference an array element that has not been assigned a value results in an exception.

The TYPE IS TABLE OF ... INDEX BY statement is used to define an associative array type.

TYPE assoctype IS TABLE OF { datatype | rectype | objtype }
  INDEX BY { BINARY_INTEGER | PLS_INTEGER | VARCHAR2(n) };

assoctype specifies an identifier for the array type. datatype specifies a scalar data type, such as VARCHAR2 or NUMBER. rectype specifies a previously defined record type. objtype specifies a previously defined object type. n specifies the maximum length of a character key.

To use a type of an array, you must declare a variable of the array type. The following syntax is used to declare an array variable:

array assoctype

In the preceding syntax, array indicates an identifier that is assigned to the associative array. assoctype indicates the identifier for a previously defined array type.

The following syntax can be used to reference an element of the array:

array(n)[.field ]

array indicates the identifier for a previously declared array. n indicates a value of the data type specified by the INDEX BY clause. If the array is defined from a record type or object type, [.field ] must reference an individual field defined within the record type or attribute within the object type from which the array type is defined. To reference the entire record, omit [.field ].

The following code provides an example on how to read the first ten employee names from the emp table, store them in an array, and then display the data from the array:

DECLARE
    TYPE emp_arr_typ IS TABLE OF VARCHAR2(10) INDEX BY BINARY_INTEGER;
    emp_arr         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;

After the preceding code is run, the following sample output is generated:

SMITH
ALLEN
WARD
JONES
MARTIN
BLAKE
CLARK
SCOTT
KING
TURNER

The example can be modified to use a record type in the array definition.

DECLARE
    TYPE emp_rec_typ IS RECORD (
        empno       NUMBER(4),
        ename       VARCHAR2(10)
    );
    TYPE emp_arr_typ IS TABLE OF emp_rec_typ INDEX BY BINARY_INTEGER;
    emp_arr         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;

After the preceding anonymous block is executed, the following sample output is generated:

EMPNO    ENAME
-----    -------
7369     SMITH
7499     ALLEN
7521     WARD
7566     JONES
7654     MARTIN
7698     BLAKE
7782     CLARK
7788     SCOTT
7839     KING
7844     TURNER

This example can be further modified to use the emp%ROWTYPE attribute to define emp_arr_typ, instead of using the emp_rec_typ record type. The following code provides an example:

DECLARE
    TYPE emp_arr_typ IS TABLE OF emp%ROWTYPE INDEX BY BINARY_INTEGER;
    emp_arr         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;

In this case, the sample output is the same as that of the preceding example.

Instead of individually assigning each field of the record, a record-level assignment can be made from r_emp to emp_arr.

DECLARE
    TYPE emp_rec_typ IS RECORD (
        empno       NUMBER(4),
        ename       VARCHAR2(10)
    );
    TYPE emp_arr_typ IS TABLE OF emp_rec_typ INDEX BY BINARY_INTEGER;
    emp_arr         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;

Keys in an associative array can be strings as shown in the following example:

DECLARE
    TYPE job_arr_typ IS TABLE OF NUMBER INDEX BY VARCHAR2(9);
    job_arr         job_arr_typ;
BEGIN
    job_arr('ANALYST')   := 100;
    job_arr('CLERK')     := 200;
    job_arr('MANAGER')   := 300;
    job_arr('SALESMAN')  := 400;
    job_arr('PRESIDENT') := 500;
    DBMS_OUTPUT.PUT_LINE('ANALYST  : ' || job_arr('ANALYST'));
    DBMS_OUTPUT.PUT_LINE('CLERK    : ' || job_arr('CLERK'));
    DBMS_OUTPUT.PUT_LINE('MANAGER  : ' || job_arr('MANAGER'));
    DBMS_OUTPUT.PUT_LINE('SALESMAN : ' || job_arr('SALESMAN'));
    DBMS_OUTPUT.PUT_LINE('PRESIDENT: ' || job_arr('PRESIDENT'));
END;

ANALYST  : 100
CLERK    : 200
MANAGER  : 300
SALESMAN : 400
PRESIDENT: 500

Two-dimensional associative arrays

Two-dimensional associative arrays are nested associative arrays. The values of a two-dimensional associative array are one-dimensional arrays. You can use two keys to associate the elements of the innermost associative array. The basic characteristics of a two-dimensional associative array are the same as those of an associative array.

  • Scenarios that are supported by two-dimensional associative arrays
    When only one-dimensional associative arrays are supported, you can use an intermediate table to implement the features of a two-dimensional associative array, as shown in the following example:
    DECLARE
        type TB1 is table of varchar(10) index by varchar(10);
        type TB2 is table of TB1 index by varchar(10);
        v_table1 TB1;
        v_table2 TB2;
    BEGIN
        v_table1('a') := 1;
        v_table1('b') := 2;
        v_table1('c') := 3;
        v_table2('a') := v_table1;
    END;
    When two-dimensional associative arrays are supported, you can use two-dimensional subscripts to assign values to elements in v_table2 instead of using the intermediate table v_table1, as shown in the following example:
    DECLARE
        type TB1 is table of varchar(10) index by varchar(10);
        type TB2 is table of TB1 index by varchar(10);
        v_table2 TB2;
    BEGIN
        v_table2('a')('a') := 1;
        v_table2('a')('b') := 2;
        v_table2('a')('c') := 3;
    END;
  • Examples
    The following example shows how to use a two-dimensional associative array:
    -- Examples of dim-2 associative array 
    DECLARE
        type type_row is table of varchar(10) index by varchar(10);
        type type_table is table of type_row index by varchar(10);
        v_table type_table;
        i varchar2(64);
        i_2 varchar2(64);
    BEGIN
        v_table('a')('b') := 10;
        v_table('a')('c') := 11;
        v_table('z')('b') := 12;
        v_table('z')('c') := 13;
        i := v_table.FIRST;
        WHILE i IS NOT NULL LOOP
            i_2 := v_table(i).FIRST;
            WHILE i_2 IS NOT NULL LOOP
                dbms_output.put_line(i || ' ' || i_2 || '-' || TO_CHAR(v_table(i)(i_2)));
                i_2 := v_table(i).NEXT(i_2);
            END LOOP;
            i := v_table.NEXT(i);
        END LOOP;
    END;
    After the preceding anonymous block is executed, the following sample output is generated:
    a b-10
    a c-11
    z b-12
    z c-13
  • Collection methods
    Two-dimensional associative arrays support the following collection methods: COUNT, FIRST, LAST, NEXT, PRIOR, and EXISTS.
    You can use the following method to call collection methods that do not take parameters, such as COUNT:
    array_dim2(n)
    You can use the following method to call collection methods that take only one parameter, such as NEXT:
    array_dim2(n).op(n)
    Note
    • array_dim2: indicates the identifier for a previously declared two-dimensional associative array.
    • n: indicates a value of the data type specified by the INDEX BY clause.
    • op: indicates a collection method.
    The following code provides an example on how to call collection methods in a two-dimensional associative array:
    DECLARE
        type TB1 is table of varchar(10) index by varchar(10);
        type TB2 is table of TB1 index by varchar(10);
        type TB3 is table of TB2 index by varchar(10);
        v_table TB2;
        v_table3 TB3;
    BEGIN
        v_table('a')('b') := 10;
        v_table('b')('c') := 11;
        v_table('c')('b') := 12;
        v_table('d')('c') := 13;
        v_table3('a') := v_table;
        
        dbms_output.put_line(v_table3('a').COUNT); 
        dbms_output.put_line(v_table3('a').FIRST);
        dbms_output.put_line(v_table3('a').LAST); 
        dbms_output.put_line(v_table3('a').NEXT(v_table3('a').FIRST));
        dbms_output.put_line(v_table3('a').prior(v_table3('a').LAST));
        dbms_output.put_line(v_table3('a').exists(v_table3('a').FIRST));
    END;
    After the preceding anonymous block is executed, the following sample output is generated:
    4
    a
    d
    b
    c
    t
  • Scenarios that are not supported by two-dimensional associative arrays

    Two-dimensional subscripts are supported only in two-dimensional associative arrays but not in nested tables or varrays.

    Two-dimensional associative arrays do not support the record type, as shown in the following example:
    DECLARE
        TYPE emp_typ IS RECORD (
            ename       varchar(10),
            first         varchar(10)
        );
        type TB is table of emp_typ index by varchar(10);
        type TB2 is table of TB index by varchar(10);
        mytable     TB2;
        myrecord    emp_typ;
    BEGIN
        mytable('a')('b') := myrecord;
    END;
    After the preceding anonymous block is executed, the following sample output is generated:
    ERROR:  At present, only associative array without package and IS TABLE OF type is not record type support multidimensional subscripts search and assignment
    CONTEXT:  compilation of SPL function "inline_code_block" near line 11
    Nested tables or varrays cannot contain a two-dimensional associative array, as shown in the following example:
    DECLARE
        type TB1 is table of number index by number;
        type TB2 is table of TB1 index by number;
        type TB3 is table of TB2;
        v_table2 TB2;
        v_table3 TB3;
    BEGIN
        v_table2(1)(1) := 1;
        v_table2(1)(2) := 2;
        v_table2(2)(3) := 3;
        v_table2(2)(4) := 4;
    
        v_table3 := TB3(v_table2);
    END;
    After the preceding anonymous block is executed, the following sample output is generated:
    ERROR:  Nested table and Varray can't be assgined with a multidimensional associative array