集合
集合是相同数据类型元素的组合,类似于编程语言中的数组。它包含如下三种类型:关联数组Associative array(索引表 pl/sql table)、嵌套表(Nested Table)、变长数组(VARRAY)
下面我们来看看官方对于三者的比较
一、 集合方法
exists(index) 索引处的元素是否存在
count 当前集合中的元素总个数
limit 集合元素索引的最大值,索引表和嵌套表是不限个数的,所以返回null,变长数组返回定义时的最大索引
first 返回集合第一个元素索引
last 返回集合最后一个元素索引
prior 当前元素的前一个元素的索引
next 当前元素的后一个元素的索引
extend 扩展集合的容量,增加元素 只是用于嵌套表和varry类型
x.extend 增加一个null元素
x.extend(n) 增加n个null元素
x.extend(n,i) 增加n个元素,元素值与第i个元素相同
trim 从集合的尾部删除元素 只用于NEST TABLE和VARRY类型
trim 从集合尾部删除一个元素
trim(n) 从集合尾部删除n个元素
delete 按索引删除集合元素
delete 删除所有
delete(index) 删除第index个
delete(a,b) 删除a--b之间的所有元素
注意:用DELETE删除元素时,PL/SQL会保存所删除元素的占位符。而用TRIM删除时,却不会保存所删除元素的占位符。
二、关联数组Associative array
关联数组具有以下特征:
1> 下标无限制,可以为负数。
2> 元素个数无限制。
创建关联数组的语法如下所示:
TYPE type_name IS TABLE OF element_type [NOT NULL] INDEX BY index_type;
table_name TYPE_NAME;
其中,type_name是用户自定义数据类型的名字,element_type是关联数组中元素类型,index_type是元素下标的数据类型(BINARY_INTEGER,PLS_INTEGER,VARCHAR2);
例一:
DECLARE CURSOR c_ename IS SELECT * FROM EMP; TYPE t_ename IS TABLE OF emp.ename%TYPE INDEX BY BINARY_INTEGER; ename_tab t_ename; v_counter INTEGER :=0; BEGIN FOR i IN c_ename LOOP v_counter := v_counter+1; ename_tab(v_counter) := i.ename; DBMS_OUTPUT.PUT_LINE(v_counter||': '||ename_tab(v_counter)); END LOOP; END; /
结果输出为:
1: SMITH
2: ALLEN
3: WARD
4: JONES
5: MARTIN
6: BLAKE
7: CLARK
8: SCOTT
9: KING
10: TURNER
11: ADAMS
12: JAMES
13: FORD
14: MILLER
上述范例元素下标的类型为BINARY_INTEGER。
下面另举一例index_type为string的。
例二:
DECLARE TYPE t_dept IS TABLE OF NUMBER -- Associative array type INDEX BY VARCHAR2(64); -- indexed by string dept_no t_dept; -- Associative array variable i VARCHAR2(64); -- Scalar variable BEGIN -- Add elements (key-value pairs) to associative array: dept_no('Ca') := 10; dept_no('Ba') := 30; dept_no('Bb') := 20; -- Print associative array: i := dept_no.FIRST; -- Get first element of array WHILE i IS NOT NULL LOOP DBMS_Output.PUT_LINE ('Dept No. for ' || i || ' is ' || dept_no(i)); i := dept_no.NEXT(i); -- Get next element of array END LOOP; END; /
输出结果为:
Dept No. for Ba is 30
Dept No. for Bb is 20
Dept No. for Ca is 10
由此可见,输出结果是经过排序的,该排序依据的是元素下标的sort order,而不是元素的creation order。
三、 嵌套表Nested table
嵌套表具有以下特征:
1> 下标从1开始,元素个数没有限制
2> 使用时必须先初始化,用extend属性可以扩展元素个数
3> 可以作为表定义数据类型,但是前提是要先create创造嵌套表类型
4> 和索引表的区别也就是看看有无index by语句,嵌套表的索引固定是int型的
创建语法:
TYPE type_name IS TABLE OF element_type;
例一,修改上述索引表的例一
DECLARE CURSOR c_ename IS SELECT * FROM EMP; TYPE t_ename IS TABLE OF emp.ename%TYPE; ename_tab t_ename := t_ename(); -- 初始化 v_counter INTEGER :=0; BEGIN FOR i IN c_ename LOOP v_counter := v_counter+1; ename_tab.EXTEND; -- 增加集合大小 ename_tab(v_counter) := i.ename; DBMS_OUTPUT.PUT_LINE(v_counter||': '||ename_tab(v_counter)); END LOOP; END; /
如官方对于集合三种类型的比较,当声明索引表时,索引表被自动设置为空,而当声明嵌套表和变长数组时,它们被自动设置为NULL,所以必须对其进行初始化。
该例中还包含一个集合方法:EXTEND,这个方法允许你增加集合的大小。注意,EXTEND不能和索引表一起使用。
例二,在表列中使用嵌套表,嵌套表类型的列是单独一个表存储,先创建一个这样的类型才能使用。
1> 创建嵌套表类型
SQL> create type nest_tab_type is table of varchar2(30);
2> 创建表
SQL> create table test (
id int,
vals nest_tab_type --嵌套表类型
) nested table vals store as nest_tab; --vals字段用嵌套表存储,表名为nest_tab
3> 插入数据
SQL> insert into test values(1,nest_tab_type('one','two','three','four'));
4> 查询数据
SQL> select * from test;
ID VALS
---------- ------------------------------------------------------------
1 NEST_TAB_TYPE('one', 'two', 'three', 'four')
declare v_id int; v_tab nest_tab_type; begin select * into v_id,v_tab from test where id=1; dbms_output.put_line(v_id); for i in 1..v_tab.count loop dbms_output.put_line(v_tab(i)); end loop; end;
输出结果为:
1
one
two
three
four
PL/SQL procedure successfully completed.
四、 可变数组Varray
变长数组具有以下特征:
1> 下标从1开始,元素个数有最大限制。
2> 类似于嵌套表,当变长数组被声明时,自动设置为NULL。必须在引用某个元素之前,初始化
3> 不能对变长数组使用DELETE方法来删除元素。
4> 可以作为表列类型
创建语法如下:
TYPE type_name IS VARRAY(size_limit) OF element_type;
例一,
DECLARE TYPE varray_type IS VARRAY(10) OF NUMBER; varray varray_type := varray_type(10,20,30,40,50,60); BEGIN DBMS_OUTPUT.PUT_LINE('varray.COUNT = '||varray.COUNT); DBMS_OUTPUT.PUT_LINE('varray.LIMIT = '||varray.LIMIT); DBMS_OUTPUT.PUT_LINE('varray.FIRST = '||varray.FIRST); DBMS_OUTPUT.PUT_LINE('varray.LAST = '||varray.LAST); varray.EXTEND(2,4); DBMS_OUTPUT.PUT_LINE('varray.LAST = '||varray.LAST); DBMS_OUTPUT.PUT_LINE('varray('||varray.LAST||')='||varray(varray.LAST)); --Tirm last two elements varray.TRIM(2); DBMS_OUTPUT.PUT_LINE('varray.LAST = '||varray.LAST); END;
输出结果为:
varray.COUNT = 6
varray.LIMIT = 10
varray.FIRST = 1
varray.LAST = 6
varray.LAST = 8
varray(8)=40
varray.LAST = 6
PL/SQL procedure successfully completed.
例二,可变数组作为表列类型
可变数组是存储在表内部的,不同于嵌套表
1> 创建可变数组类型
SQL> create type varr_type is varray(10) of varchar2(30);
2> 创建表
declare v_varr varr_type; begin select varr into v_varr from test_varray where id=1; for i in 1..v_varr.count loop dbms_output.put_line(v_varr(i)); end loop; end;
五、多维集合(Multidimensional Collections)
从Oracle 9i开始,PL/SQL允许创建元素类型为集合类型的集合,这种集合称为多维集合。
试举一例:
DECLARE TYPE varray_type1 IS VARRAY(4) OF INTEGER; TYPE varray_type2 IS VARRAy(3) OF varray_type1; varray1 varray_type1 := varray_type1(2,4,6,8); varray2 varray_type2 := varray_type2(varray1); BEGIN DBMS_OUTPUT.PUT_LINE('Varray of integers'); FOR i IN 1..4 LOOP DBMS_OUTPUT.PUT_LINE('varray('||i||'): '||varray1(i)); END LOOP; varray2.EXTEND; varray2(2) := varray_type1(1,3,5,7); DBMS_OUTPUT.PUT_LINE(chr(10)||'Varray of varrays of integers'); FOR i IN 1..2 LOOP FOR j IN 1..4 LOOP DBMS_OUTPUT.PUT_LINE ('varray2('||i||')('||j||'): '||varray2(i)(j)); END LOOP; END LOOP; END;
输出结果为:
SQL> /
Varray of integers
varray(1): 2
varray(2): 4
varray(3): 6
varray(4): 8
Varray of varrays of integers
varray2(1)(1): 2
varray2(1)(2): 4
varray2(1)(3): 6
varray2(1)(4): 8
varray2(2)(1): 1
varray2(2)(2): 3
varray2(2)(3): 5
varray2(2)(4): 7
PL/SQL procedure successfully completed.
总结: 通常来说,对集合类型的第一选择应该是Associative array,因为它不需要初始化或者EXTEND操作,并且是迄今为止最高效的集合类型。唯一不足的一点是它只能用于PL/SQL而不能直接用于数据库。