PL/SQL 联合数组与嵌套表

本文详细介绍了PL/SQL中联合数组与嵌套表的使用方法,包括它们的特点、语法及示例。联合数组类似于单列数据库表,适用于多行单列数据处理;嵌套表则支持作为表列数据类型,适用于单行多列数据处理。

 通常情况下,在PL/SQL中,处理单行单列的数据可以使用标量变量,而处理单行多列的数据则使用PL/SQL记录是不错的选择。单列多行数据
则由联合数组或嵌套表来完成,其特点是类似于单列数据库表。在Oracle 9i 之前称为PL/SQL索引表,9i 之后称之为联合数组。嵌套表也是集合
类型中的一种,下面分别介绍这两种集合数据类型的使用方法。

 

一、联合数组

  1. 1、联合数组的特性  
  2.     类似于一张简单的SQL表,按照主键进行检索数据  
  3.     其数据行并不是按照预定义的顺序存储。当使用变量来检索其数据时,每行数据会分配一个连续的下标且从1开始。  
  4.     下标可以为负值,且下标的数据类型支持binary_integer,pls_integer,varchar2  
  5.     其数据元素个数无限制  
  6.     不能作为表列的数据类型使用,即只能作为PL/SQL复合数据类型使用  
  7.     存放的数据类型是临时数据,故不支持insert,select into 等SQL语句,等同于SQL server中的表变量  
  8.           
  9. 2、语法          
  10.     TYPE type_name IS TABLE OF element_type [NOT NULL]  -->element_type为联合数组元数据指定数据类型(先使用TYPE声明表结构)  
  11.     INDEX BY key_type;                                  -->元素下标的数据类型  
  12.     table_name TYPE_NAME;                               -->再使用声明的TYPE类型声明实际数组名  
  13.           
  14. 3、示例  
  15. --使用PLS_INTEGE类型联合数组  
  16. scott@CNMMBO> DECLARE                                   -->定义游标         
  17.   2     CURSOR name_cur IS  
  18.   3        SELECT dname  
  19.   4        FROM   dept  
  20.   5        WHERE  deptno < 40;  
  21.   6    
  22.   7     TYPE name_type IS TABLE OF dept.dname%TYPE      -->定义一个联合数组类型,且其下标的数据类型为PLS_INTEGER  
  23.   8                          INDEX BY PLS_INTEGER;  
  24.   9    
  25.  10     dname_tab   name_type;                          -->声明类型为name_type的联合数组dname_tab  
  26.  11     v_counter   INTEGER := 0;  
  27.  12  BEGIN  
  28.  13     FOR name_rec IN name_cur  
  29.  14     LOOP  
  30.  15        v_counter   :=  
  31.  16           v_counter  
  32.  17           + 1;  
  33.  18        dname_tab( v_counter ) := name_rec.dname;      -->对联合数据进行循环赋值  
  34.  19        DBMS_OUTPUT.put_line(   'Dname is('  
  35.  20                             || v_counter  
  36.  21                             || '):'  
  37.  22                             || dname_tab( v_counter ) );   -->输出联合数组中的所有元素  
  38.  23     END LOOP;  
  39.  24  END;  
  40.  25  /  
  41. Dname is(1):ACCOUNTING  
  42. Dname is(2):RESEARCH  
  43. Dname is(3):SALES  
  44.   
  45. PL/SQL procedure successfully completed.  
  46.   
  47. --使用VARCHAR2类型联合数组  
  48. scott@CNMMBO> DECLARE  
  49.   2     TYPE score_type IS TABLE OF NUMBER  
  50.   3                           INDEX BY VARCHAR2( 10 );    -->注意此处声明的联合数组的下标数据类型为varchar2  
  51.   4    
  52.   5     score_tab   score_type;  
  53.   6  BEGIN  
  54.   7     score_tab( 'SCOTT' ) := 95;                       -->对不同下标分别进行赋值  
  55.   8     score_tab( 'JOHN' ) := 98;  
  56.   9     score_tab( 'ROBINSON' ) := 96;  
  57.  10     DBMS_OUTPUT.put_line( 'First element is '  
  58.  11                          || score_tab.FIRST );        -->输出联合数组score_tab中的第一个元素的下标  
  59.  12     DBMS_OUTPUT.put_line( 'last element is '  
  60.  13                          || score_tab.LAST );         -->输出联合数组score_tab中的最后一个元素的下标  
  61.  14     DBMS_OUTPUT.put_line( 'The score of Scott is '  
  62.  15                          || score_tab( 'SCOTT' ) );   -->输出下标为SCOTT的元素的值  
  63.  16  END;  
  64.  17  /  
  65. First element is JOHN                                     -->注意此处输出的是JOHN(第一个和最后一个是按字母排序得到的)  
  66. last element is SCOTT  
  67. The score of Scott is 95  
  68.   
  69. PL/SQL procedure successfully completed.  
  70.   
  71. --下标超范围的情况  
  72. scott@CNMMBO> DECLARE  
  73.   2     TYPE score_type IS TABLE OF NUMBER  
  74.   3                           INDEX BY VARCHAR2( 10 );  
  75.   4    
  76.   5     score_tab   score_type;  
  77.   6  BEGIN  
  78.   7     score_tab( 'SCOTT' ) := 95;  
  79.   8     score_tab( 'JOHN' ) := 98;  
  80.   9     score_tab( 'ROBINSON' ) := 96;  
  81.  10     DBMS_OUTPUT.put_line( 'The score of Jason is  '  
  82.  11                          || score_tab( 'JASON' ) );  
  83.  12  END;  
  84.  13  /  
  85. DECLARE  
  86. *  
  87. ERROR at line 1:  
  88. ORA-01403: no data found                              -->当下标超范围时,将收到ORA-01403错误  
  89. ORA-06512: at line 10  

二、嵌套表

  1. 1、嵌套表的特点:  
  2.     元素下表从1开始,个数没有限制.即元素个数可以动态增长  
  3.     嵌套表的数组元素值可以是稀疏的,即可以使得中间的某个元素没有赋值  
  4.     嵌套表的语法与联合数组类似,不同的是仅仅是少了index by子句     
  5.     嵌套表必需先初始化,然后才能引用其中的元素。如果初始化为空值,则后续需要使用extend来扩展其大小    
  6.     嵌套表初始化时为密集的,但允许有间隙,即允许使用内置过程delete从嵌套表中删除元素  
  7.     嵌套表类型可以作为表列的数据类型来使用  
  8.   
  9. 2、语法  
  10.         TYPE type_name IS TABLE OF element_type [NOT NULL];   -->element_type为索引表元数据指定数据类型(先使用TYPE声明表结构)   
  11.         table_name TYPE_NAME;                                 -->再使用声明的TYPE类型声明实际嵌套表         
  12.   
  13. 3、示例  
  14. --声明嵌套表并输出嵌套表的实际内容            
  15. scott@CNMMBO> DECLARE  
  16.   2     CURSOR name_cur IS  
  17.   3        SELECT dname  
  18.   4        FROM   dept  
  19.   5        WHERE  deptno < 40;  
  20.   6    
  21.   7     TYPE name_type IS TABLE OF dept.dname%TYPE;  
  22.   8    
  23.   9     dname_tab   name_type := name_type( );   -->需要初始化,否则将收到 ORA-06531:Reference to uninitialized collection.  
  24.  10     v_counter   INTEGER := 0;  
  25.  11  BEGIN  
  26.  12     FOR name_rec IN name_cur  
  27.  13     LOOP  
  28.  14        v_counter   :=  
  29.  15           v_counter  
  30.  16           + 1;  
  31.  17        dname_tab.EXTEND;         -->需要扩展,否则将收到 ORA-06533: Subscript beyond count  
  32.  18        dname_tab( v_counter ) := name_rec.dname;  
  33.  19        DBMS_OUTPUT.put_line(   'Dname ('  
  34.  20                             || v_counter  
  35.  21                             || ') is :'  
  36.  22                             || dname_tab( v_counter ) );  
  37.  23     END LOOP;  
  38.  24  END;  
  39.  25  /  
  40. Dname (1) is :ACCOUNTING  
  41. Dname (2) is :RESEARCH  
  42. Dname (3) is :SALES  
  43.   
  44. PL/SQL procedure successfully completed.  
  45.   
  46. --将嵌套表作为表列的数据类型来使用  
  47. scott@CNMMBO> CREATE OR REPLACE TYPE mail_type IS TABLE OF VARCHAR2( 100 );  
  48.   2  /  
  49.   
  50. Type created.  
  51.   
  52. scott@CNMMBO> CREATE TABLE tb_tmp       -->创建表tb_tmp  
  53.   2  (  
  54.   3     empno   NUMBER( 4 )  
  55.   4   , ename   VARCHAR2( 10 )  
  56.   5   , mail    mail_type               -->列mail的类型为mail_type  
  57.   6  )  
  58.   7  NESTED TABLE mail                 -->注意此处需要指定嵌套表的存储方式  
  59.   8     STORE AS mail_tab;  
  60.   
  61. Table created.  
  62.   
  63. --为嵌套表插入数据  
  64. scott@CNMMBO> insert into tb_tmp select 8888,'Jack','Jack@yahoo.com,Jack@163.com' from dual;  -->传统方式插入失败  
  65. insert into tb_tmp select 8888,'Jack','Jack@yahoo.com,Jack@163.com' from dual  
  66.                                       *  
  67. ERROR at line 1:  
  68. ORA-00932: inconsistent datatypes: expected - got CHAR  
  69.   
  70. scott@CNMMBO> insert into tb_tmp select 8888,'Jack',q'['Jack@yahoo.com','Jack@163.com']' from dual;  -->分割字符串方式插入失败  
  71. insert into tb_tmp select 8888,'Jack',q'['Jack@yahoo.com','Jack@163.com']' from dual  
  72.                                       *  
  73. ERROR at line 1:  
  74. ORA-00932: inconsistent datatypes: expected - got CHAR  
  75.   
  76. scott@CNMMBO> insert into tb_tmp select 8888,'Jack',mail_type('Jack@yahoo.com','Jack@163.com'from dual; -->插入时指定嵌套表类型   
  77.   
  78. 1 row created.  
  79.   
  80. scott@CNMMBO> commit;  
  81.   
  82. Commit complete.  
  83.   
  84. --查看存在嵌套表数据类型的表中的记录  
  85. scott@CNMMBO> col mail format a30  
  86. scott@CNMMBO> select * from tb_tmp;                    -->查询数据时带有嵌套表的类型  
  87.   
  88.      EMPNO ENAME      MAIL  
  89. ---------- ---------- ------------------------------  
  90.       8888 Jack       MAIL_TYPE('Jack@yahoo.com', 'J  
  91.                       ack@163.com')  
  92.   
  93. scott@CNMMBO> DECLARE  
  94.   2     mail_tab   mail_type;    -->声明一个mail_type数据类型  
  95.   3  BEGIN  
  96.   4     SELECT mail  
  97.   5     INTO   mail_tab          -->将数据保存到 mail_tab 变量中  
  98.   6     FROM   tb_tmp  
  99.   7     WHERE  empno = 8888;  
  100.   8    
  101.   9     FOR i IN 1 .. mail_tab.COUNT   -->轮循输出嵌套表类型中的值  
  102.  10     LOOP  
  103.  11        DBMS_OUTPUT.put_line( 'Jack mail address is '  
  104.  12                             || mail_tab( i ) );  
  105.  13     END LOOP;  
  106.  14  END;  
  107.  15  /  
  108. Jack mail address is Jack@yahoo.com  
  109. Jack mail address is Jack@163.com  
  110.   
  111. PL/SQL procedure successfully completed.  
  112.   
  113. --更新表中含有嵌套表类型中的值  
  114. scott@CNMMBO> DECLARE  
  115.   2     mail_tab   mail_type := mail_type( 'Jackson@yahoo.com''Jackson@163.com' );  
  116.   3  BEGIN  
  117.   4     UPDATE tb_tmp  
  118.   5     SET    mail         = mail_tab;  
  119.   6    
  120.   7     COMMIT;  
  121.   8     DBMS_OUTPUT.put_line( 'Jack mail address was updated' );  
  122.   9  END;  
  123.  10  /  
  124. Jack mail address was updated  
  125.   
  126. PL/SQL procedure successfully completed.  
  127.   
  128. scott@CNMMBO> select * from tb_tmp;  
  129.   
  130.      EMPNO ENAME      MAIL  
  131. ---------- ---------- ------------------------------  
  132.       8888 Jack       MAIL_TYPE('Jackson@yahoo.com',  
  133.                        'Jackson@163.com')  
  134.   
  135. --删除表中存在嵌套表类型的记录  
  136. scott@CNMMBO> delete from tb_tmp where empno=8888;  
  137.   
  138. 1 row deleted.  
  139.   
  140. scott@CNMMBO> commit;  
  141.   
  142. Commit complete.  
  143.   
  144. scott@CNMMBO> select * from tb_tmp;  
  145.   
  146. no rows selected                         
  147. --> Author: Robinson Cheng  
  148. --> Blog: http://blog.youkuaiyun.com/robinson_0612  

三、总结
1、不论是联合数组还是嵌套表,应当以集合的方式来看待与处理
2、联合数组在声明其类型时需要指定index by子句,而嵌套表则不需要
3、联合数组和嵌套表两者元素个数无限制    
4、联合数组不需要初始化,而嵌套表则需要对其进行初始化。其次是嵌套表初始化赋空值的情形则后续需要使用extend方式来扩展集合尺寸的大小
5、联合数组不能作为表上列的数据类型,而嵌套表无此限制



转载地址:http://blog.youkuaiyun.com/robinson_0612/article/details/7372061

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值