关联数组 (PL/SQL)

PL/SQL 关联数组是一种集合类型,它使唯一的键与值相关联。

关联数组具有下列特征:
  • 必须先定义关联数组类型,然后才能声明具有该数组类型的数组变量。 数据处理在数组变量中进行。
  • 无需对此数组进行初始化;只需将值指定给数组元素。
  • 对此数组中的元素数目没有已定义的限制;此数组可以在添加元素时动态地增大。
  • 此数组可以是稀疏数组;即,对键进行的赋值可以有间隔。
  • 尝试引用尚未进行赋值的数组元素将导致异常。

请使用 TYPE IS TABLE OF 语句来定义关联数组类型。

语法

Read syntax diagramSkip visual syntax diagramTYPEassoctypeIS TABLE OF datatype INDEX BY BINARY_INTEGERPLS_INTEGERVARCHAR2(nBYTECHAR)

描述

类型 assoctype
指定数组类型的标识。
数据类型
指定受支持的数据类型,例如 VARCHAR2、NUMBER、RECORD、VARRAY 或关联数组类型。 另外,还支持 %TYPE 属性和 %ROWTYPE 属性。
INDEX BY
指定关联数组按此子句所引入的其中一种数据类型建立索引。
BINARY INTEGER
整型数字数据。
PLS_INTEGER
整型数字数据。
VARCHAR2 (n[BYTE | CHAR])
最大长度为 n 个代码单元的可变长度字符串,可介于 1 到 32 672 字节或者 1 到 8 168 个字符。 如果 %TYPE 属性所应用于的对象具有 BINARY_INTEGER、PLS_INTEGER 或 VARCHAR2 数据类型,那么还支持 %TYPE 属性。

要声明具有关联数组类型的变量,请指定 array-name assoctype,其中 array-name 表示分配给关联数组的标识, assoctype 表示先前声明的数组类型的标识。

要引用数组的特定元素,请指定 array-name(n),其中 array-name 表示先前声明的数组的标识, n 表示 INDEX BY 数据类型 assoctype的值。 如果从记录类型定义数组,那么引用将变为 array-name(n).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%ROWTYPE 属性来定义 emp_arr_typ,而不是使用 emp_rec_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_empemp_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
/