关联数组是一种将唯一键与值相关联的集合。键不必是数字,也可以是字符数据。
关联数组具有以下特征:
- 必须定义关联数组类型,然后才能声明该数组类型的数组变量。使用数组变量进行数据操作。
- 声明数组变量时,会创建关联数组,但它是空的 - 只需开始为键值赋值即可。
- 如果指定了INDEXBY BINARY_INTEGER或PLS_INTEGER,则键可以是任何负整数、正整数或零。
- 如果指定了INDEXBY VARCHAR2,则键可以是字符数据。
- 数组中的元素数量没有预定义的限制 - 它会随着添加的元素而动态增长。
- 数组可能是稀疏的 - 在键值的赋值中可能存在间隙。
- 尝试引用尚未赋值的数组元素将导致异常。
TYPE IS TABLE OF ... INDEX BY语句用于定义关联数组类型。
TYPE assoctype IS TABLE OF { datatype | rectype | objtype }
INDEX BY { BINARY_INTEGER | PLS_INTEGER | VARCHAR2(n) };
assoctype是分配给数组类型的标识符。datatype是标量数据类型,例如VARCHAR2或NUMBER。rectype是先前定义的记录类型。objtype 是先前定义的对象类型。n是字符键的最大长度。
为了使用该数组,必须声明一个该数组类型的变量。以下是声明数组变量的语法。
array assoctype
array是分配给关联数组的标识符。assoctype是先前定义的数组类型的标识符。
使用以下语法引用数组的元素。
array(n)[.field ]
array是先前声明的数组的标识符。n是键值,其类型与INDEX BY子句中给出的数据类型兼容。如果从记录类型或对象类型定义array的数组类型,则 [.field ] 必须引用定义数组类型时所依据的对象类型中的记录类型或属性内的单个字段。或者,可以通过省略 [.field ] 来引用整个记录。
以下示例从emp表中读取前十名员工的姓名,将它们存储在一个数组中,然后显示数组中的结果。
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;
上面的示例生成以下输出:
SMITH
ALLEN
WARD
JONES
MARTIN
BLAKE
CLARK
SCOTT
KING
TURNER
现在修改上一个示例以使用数组定义中的记录类型。
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;
下面是此匿名块的输出。
EMPNO ENAME
----- -------
7369 SMITH
7499 ALLEN
7521 WARD
7566 JONES
7654 MARTIN
7698 BLAKE
7782 CLARK
7788 SCOTT
7839 KING
7844 TURNER
emp%ROWTYPE属性可用于定义emp_arr_typ,而不是使用emp_rec_typ记录类型,如下所示。
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;
结果与前面的例子相同。
不是单独分配记录的每个字段,而是可以从r_emp到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;
关联数组的键可以是字符数据,如以下示例所示。
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
二维关联数组
二维关联数组是嵌套的关联数组,二维关联数组的值是一维关联数组,可以同时使用两个键关联到最内层关联数组的元素。二维关联数组的基本特征和关联数组相同。
- 二维关联数组支持的场景在只有一维关联数组的情况下,如果需要实现类似二维关联数组的功能,需要使用一个中转表间接实现,示例如下:
在支持了二维关联数组后,可以不用定义中转数组v_table1,直接使用二维下标,对v_table2完成赋值操作: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;
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 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;
a b-10 a c-11 z b-12 z c-13
- 集合方法目前二维关联数组支持的集合方法有:COUNT,FIRST,LAST,NEXT,PRIOR,EXISTS。
-- 对于无参数的集合方法,比如COUNT,采用如下形式的方法进行调用: array_dim2(n) -- 对于含有一个参数的集合方法,比如NEXT,采用如下形式的方法进行调用: array_dim2(n).op(n)
说明- array_dim2:为先前声明的二维关联数组的标识符。
- n:为键值,其类型与
INDEX BY
子句中给出的数据类型兼容。 - op:为集合方法。
以下为一个二维关联数组使用集合方法的示例:
以下是此匿名块的输出: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;
4 a d b c t
- 暂不支持的场景
目前只支持二维的关联数组,嵌套表和varray目前还不支持二维下标操作。
目前二维关联数组还不支持记录类型(record类型):
以下是此匿名块的输出: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;
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
嵌套表和varray不能包含一个二维关联数组,示例如下:
以下是此匿名块的输出: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;
ERROR: Nested table and Varray can't be assgined with a multidimensional associative array