您的位置:首页 > 数据库

PL/SQL集合类型

2010-10-25 22:46 429 查看
PL/SQL中没有数组的概念,他的集合数据类型和数组是相似的。在7.3以前的版本中只有一种集合,称为PL/SQL表,在这之后又有两种集合数据类型:嵌套表和varray。其中varray集合中的元素是有数量限制的,index_by表和嵌套表是没有这个限制的。index-by表是稀疏的,也就是说下标可以不连续,varray类型的集合则是紧密的,他的下标没有间隔。index_by表不能存储在数据库中,但是嵌套表和varray可以被存储在数据库中。 集合在使用时必须先使用type进行定义方可使用。

 

1.index_by表

type type_name is table of element_type [NOT NULL] index by binary_integer

2.嵌套表

type type_name is table of element_type [NOT NULL]

 

3.varray

type type_name is [varray ¦varying array](max_size) of element_type[NOT NULL]

一,index_by表

TYPE TYPE1 IS TABLE OF VARCHAR2(10) INDEX BY BINARY_INTEGER;

1.使用的时候需要先赋值后读取,至少也要先初期化一下,否则会出现异常:ORA-01403: no data found。

2.这种数组不需要事先指定上限,下标可以不连续,可以是0或负数。

 

或者叫做索引表(index by tables),可以使用任意数字或字符串来作为下标,
和其他语言(如java)里的hash table有点相似。
可以在包或者存储过程或者函数中定义集合类型,同时也可以用来作为过程或函数的参数。
和嵌套表与varray不同,索引表不能被存储在数据库表中。
type type_name is table of element_type [NOT NULL] index by {binary_integer|varchar2}
同样也用简单的例子来示意索引表的使用:
SQL> declare
 2   type tp_indexby_table1 is table of number(7, 2) index by pls_integer;
 3   v_indexby_table1 tp_indexby_table1;
 4 begin
 5   select sal
 6     into v_indexby_table1(1)
 7     from scott.emp a
 8    where a.empno = 7369;
 9 
 10   dbms_output.put_line('v_indexby_table1(1):' || v_indexby_table1(1));
 11 
 12   select a.sal bulk collect
 13     into v_indexby_table1
 14     from scott.emp a
 15    where rownum < 5;
 16 
 17   for i in v_indexby_table1.first .. v_indexby_table1.last loop
 18     dbms_output.put_line('v_indexby_table1(i):' || v_indexby_table1(i));
 19   end loop;
 20   dbms_output.put_line(v_indexby_table1.count);
 21   dbms_output.put_line(v_indexby_table1.next(1));
 22   v_indexby_table1.delete(1);
 23   dbms_output.put_line(v_indexby_table1.count);
 24 end;
 25 /
 
v_indexby_table1(1):800
v_indexby_table1(i):123
v_indexby_table1(i):800
v_indexby_table1(i):1600
v_indexby_table1(i):1250
4
2
3
 
PL/SQL procedure successfully completed
 
注意不能对index by table使用extend。当然table的类型也可以是ROWTYPE。

二,嵌套表

TYPE TYPE2 IS TABLE OF VARCHAR2(10);

 

1.必须进行初期化,否则会出现异常:ORA-06531: Reference to uninitialized collection

2.初期化方法:v1 TYPE2 := TYPE2(); --声明时初期化数组为空

 

拥有任意数量的元素,以连续的数字作为下标。可以定义等价的sql类型,允许嵌套表存储在数据库表,
并通过sql来操纵它们,这里的嵌套表是作为物理存储的,本节不做叙述,实际使用较少,在基础篇内的
数据库表一节中简述。本节只讲述其作为plsql类型使用的情况。
如果理解一维数组和多维数组的原理的话,嵌套表也容易理解,嵌套表可以看做是没有上界的一维数组,
其中的元素可以删除,可以使用next来遍历。也可以将嵌套表内的元素也使用嵌套表来实现多维。
具体的语法如下:
type type_name is table of element_type [NOT NULL]
看一个例子:
SQL> set serveroutput on;
SQL> declare
 2   type tp_nested_table_1 is table of number;
 3   v_nested_table_1 tp_nested_table_1 := tp_nested_table_1(1, 2);
 4 begin
 5   for i in v_nested_table_1.first .. v_nested_table_1.last loop
 6     dbms_output.put_line(i);
 7   end loop;
 8 end;
 9 /
  
PL/SQL procedure successfully completed
上述代码中定义了一个number类型的table,并初始化为tp_nested_table_1(1, 2),也即包含了2个元素,分别为1,2,,下面来修改一下上述代码,在使用时初始化:
SQL> declare
 2   type tp_nested_table_1 is table of number;
 3   v_nested_table_1 tp_nested_table_1 := tp_nested_table_1();
 4 begin
 5   v_nested_table_1 := tp_nested_table_1(1,2);
 6   for i in v_nested_table_1.first .. v_nested_table_1.last loop
 7     dbms_output.put_line(i);
 8   end loop;
 9 end;
 10 /
  
PL/SQL procedure successfully completed
或者:
SQL> declare
 2   type tp_nested_table_1 is table of number;
 3   v_nested_table_1 tp_nested_table_1 := tp_nested_table_1(1,2,3);
 4 begin
 5   v_nested_table_1 := tp_nested_table_1(1,2);
 6   v_nested_table_1 := tp_nested_table_1(1,2,3,4,5);
 7   for i in v_nested_table_1.first .. v_nested_table_1.last loop
 8     dbms_output.put_line(i);
 9   end loop;
 10 end;
 11 /
 
 
PL/SQL procedure successfully completed
可以看出前面介绍的嵌套表的一个特质,即无上限。
另外,使用了嵌套表的first和last属性,来看看nested table的几个属性:
SQL> declare
 2   type tp_nested_table_1 is table of number;
 3   v_nested_table_1 tp_nested_table_1 := tp_nested_table_1(1,2,3);
 4 begin
 5   v_nested_table_1 := tp_nested_table_1(1,2,3,4,5,6);
 6   dbms_output.put_line('v_nested_table_1.first :'||v_nested_table_1.first);
 7   dbms_output.put_line('v_nested_table_1.next(1) :'||v_nested_table_1.next(1));
 8   dbms_output.put_line('v_nested_table_1.next(3) :'||v_nested_table_1.next(3));
 9   dbms_output.put_line('v_nested_table_1.next(1) :'||v_nested_table_1.next(1));
 10   dbms_output.put_line('v_nested_table_1.last :'||v_nested_table_1.last);
 11 end;
 12 /
 
v_nested_table_1.first :1
v_nested_table_1.next(1) :2
v_nested_table_1.next(3) :4
v_nested_table_1.next(1) :2
v_nested_table_1.last :6
 
PL/SQL procedure successfully completed
SQL> declare
 2   type tp_nested_table_1 is table of number;
 3   v_nested_table_1 tp_nested_table_1 := tp_nested_table_1(1,2,3);
 4 begin
 5   v_nested_table_1 := tp_nested_table_1(1,2,3,4,5,6);
 6   dbms_output.put_line('v_nested_table_1.count :'||v_nested_table_1.count);
 7   v_nested_table_1.delete(2);
 8   v_nested_table_1.extend(2);
 9   dbms_output.put_line('v_nested_table_1.count :'||v_nested_table_1.count);
 10   dbms_output.put_line('v_nested_table_1.first :'||v_nested_table_1.first);
 11   dbms_output.put_line('v_nested_table_1.next(1) :'||v_nested_table_1.next(1));
 12   dbms_output.put_line('v_nested_table_1.next(3) :'||v_nested_table_1.next(3));
 13   dbms_output.put_line('v_nested_table_1.next(1) :'||v_nested_table_1.next(1));
 14   dbms_output.put_line('v_nested_table_1.last :'||v_nested_table_1.last);
 15 end;
 16 /
 
v_nested_table_1.count :6
v_nested_table_1.count :7
v_nested_table_1.first :1
v_nested_table_1.next(1) :3
v_nested_table_1.next(3) :4
v_nested_table_1.next(1) :3
v_nested_table_1.last :8
 
PL/SQL procedure successfully completed
上面2个例子很清楚的看出了first,next,last的意义,
另外,可以使用delete(x)来删除指定的元素Delete()删除全部元素,
delete(x,y)删除下标从x到y的元素,
可以使用extend(x)来扩展指定数量的元素,而extend是在末尾添加一个元素,extend(x,n)是添加x元素的n个副本,注意新扩展的元素默认值是null。
next(x)是紧跟着当前元素x个位置后的元素,
count是当前的元素个数,注意添加或者删除元素后count值变化了,
 

3.数组元素的访问:

下标从1开始,不能超过数组所有元素的总和,当下标超出允许范围时,出现异常:ORA-06532: Subscript outside of limit

因为不能访问空数组,所以空数组的场合,必须进行数组扩展。 54ne.com

例:v1.EXTEND;

V1(1):= ‘1’; --访问合法 54com.cn

v1(2):= ‘2’; --访问非法,之前必须再次执行v1.EXTEND; 网管网bitsCN_com

例:v2的下标范围是1~5。

v2(5):= ‘Hello’; --访问合法

DBMS_OUTPUT.put_line(v2(6)); --访问非法

 

 

三,Varray

TYPE TYPE3 IS ARRAY(5) OF VARCHAR2(10);

由于类型定义时的元素个数限制,所以TYPE3的变量在使用时最大的元素个数不能超过5个。

 

拥有固定数量的元素(虽然可以在运行时改变元素的数量),使用连续的数字作为下标,和nested table
一样可以定义等价的sql类型,允许varray被存储在数据库表中,也可以通过sql来操纵,但是灵活性较
嵌套表差一些。
Varray拥有一个最大长度,需要显示的定义。它由从1开始的下标开始,可以在运行时扩展上界。
具体语法如下:
type type_name is [varray ¦varying array](max_size) of element_type[NOT NULL]
看一个例子:
SQL> declare
 2   type tp_varray1 is varray(6) of varchar2(10);
 3   v_varray tp_varray1;
 4 begin
 5   v_varray := tp_varray1('1', 'a');
 6   for i in v_varray.first .. v_varray.last loop
 7     dbms_output.put_line('v_varray(i):' || v_varray(i));
 8   end loop;
 9   --注意虽然定义了varray(6)但上述事实上只有2个元素,下面的赋值为非法
 10   --v_varray(3) := null;
 11   --可以扩展一个元素,然后赋值,默认值为null
 12   v_varray.extend;
 13   v_varray(3) := null;
 14   dbms_output.put_line('v_varray.count:' || v_varray.count);
 15   dbms_output.put_line('v_varray.next(1):' || v_varray.next(1));
 16   --注意varray不能删除元素,但可以清除其的值:v_varray(x) := null;
 17   --dbms_output.put_line('v_varray.delete(1):'||v_varray.delete(1));
 18 end;
 19 /
 
v_varray(i):1
v_varray(i):a
v_varray.count:3
v_varray.next(1):2
 
PL/SQL procedure successfully completed
 
再来看看多维的情况:
SQL> declare
 2   type tp_varray1 is varray(6) of varchar2(10);
 3   type tp_varray2 is varray(6) of tp_varray1;
 4   v_varray1 tp_varray1;
 5   v_varray2 tp_varray2;
 6   v_varray3 tp_varray2;
 7 begin
 8   v_varray1 := tp_varray1('1', 'a');
 9 
 10   for i in v_varray1.first .. v_varray1.last loop
 11     dbms_output.put_line('v_varray1(i):' || v_varray1(i));
 12     v_varray2 := tp_varray2(v_varray1);
 13     for j in v_varray2.first .. v_varray2.last loop
 14       dbms_output.put_line('v_varray2(1)(j):' || v_varray2(j) (i));
 15     end loop;
 16   end loop;
 17 
 18   v_varray3 := tp_varray2(v_varray1, tp_varray1('a', 'd'));
 19 
 20   for n in v_varray3.first .. v_varray3.last loop
 21     for m in v_varray3(n).first .. v_varray3(n).last loop
 22       dbms_output.put_line('v_varray3(n) (m):' || v_varray3(n) (m));
 23     end loop;
 24   end loop;
 25 
 26   dbms_output.put_line('v_varray3.count:' || v_varray3.count);
 27   v_varray3.extend;
 28   dbms_output.put_line('v_varray3.count:' || v_varray3.count);
 29 
 30   dbms_output.put_line('v_varray3(1).count:' || v_varray3(1).count);
 31   v_varray3(1) .extend;
 32   dbms_output.put_line('v_varray3(1).count:' || v_varray3(1).count);
 33 
 34 end;
 35 /
 
v_varray1(i):1
v_varray2(1)(j):1
v_varray1(i):a
v_varray2(1)(j):a
v_varray3(n) (m):1
v_varray3(n) (m):a
v_varray3(n) (m):a
v_varray3(n) (m):d
v_varray3.count:2
v_varray3.count:3
v_varray3(1).count:2
v_varray3(1).count:3
 
PL/SQL procedure successfully completed
 

四,集合内建函数

集合还有很多内建函数,这些函数称为方法,调用方法的语法如下:

collection.method

下表中列出oracle中集合的方法

方法 描述 使用限制

COUNT 返回集合中元素的个数 网管网bitsCN.com

DELETE 删除集合中所有元素 54com.cn

DELETE(x) 删除元素下标为x的元素,如果x为null,则集合保持不变 对VARRAY非法

DELETE(x,y) 删除元素下标从X到Y的元素,如果X>Y集合保持不变 对VARRAY非法

EXIST(x) 如果集合元素x已经初始化,则返回TRUE, 否则返回FALSE

EXTEND 在集合末尾添加一个元素 对Index_by非法

EXTEND(x) 在集合末尾添加x个元素 对Index_by非法

EXTEND(x,n) 在集合末尾添加元素n的x个副本 对Index_by非法

FIRST 返回集合中的第一个元素的下标号,对于VARRAY集合始终返回1。 feedom.net

LAST 返回集合中最后一个元素的下标号, 对于VARRAY返回值始终等于COUNT。

LIMIT 返回VARRY集合的最大的元素个数,对于嵌套表和Index_by集合无用。

NEXT(x) 返回在元素x之后及紧挨着它的元素的值,如果该元素是最后一个元素,则返回null。

PRIOR(x) 返回集合中在元素x之前紧挨着它的元素的值,如果该元素是第一个元素,则返回null。

TRIM 从集合末端开始删除一个元素 对index_by不合法

TRIM(x) 从集合末端开始删除x个元素 对index_by不合法
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息