关联数组 (PL/SQL)

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

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

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

语法

阅读语法图跳过直观语法图TYPE关联类型IS TABLE OF datatype INDEX BY BINARY_INTEGERPLS_INTEGERVARCHAR2(nBYTECHAR)

描述

TYPE 关联类型
指定数组类型的标识。
datatype
指定受支持的数据类型,例如 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 属性。

要声明具有关联数组类型的变量,请指定 数组名 关联类型,其中 数组名 表示对关联数组指定的标识,关联类型 表示先前声明的数组类型的标识。

要引用数组的特定元素,请指定 数组名(n),其中 数组名 表示先前声明的数组的标识,n 表示 INDEX BY 数据类型为 关联类型 的值。如果根据记录类型来定义数组,那么该引用将变为 数组名(n).字段,其中 字段 在数组类型的定义所基于记录类型中定义。要引用整个记录,请省略 字段

示例

以下示例从 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   /