设为首页 收藏本站
查看: 874|回复: 0

[经验分享] PL/SQL 联合数组与嵌套表

[复制链接]
累计签到:1 天
连续签到:1 天
发表于 2014-7-9 09:40:55 | 显示全部楼层 |阅读模式
通常情况下,在PL/SQL中,处理单行单列的数据可以使用标量变量,而处理单行多列的数据则使用PL/SQL记录是不错的选择。单列多行数据
则由联合数组或嵌套表来完成,其特点是类似于单列数据库表。在Oracle 9i 之前称为PL/SQL索引表,9i 之后称之为联合数组。嵌套表也是集合
类型中的一种,下面分别介绍这两种集合数据类型的使用方法。



一、联合数组


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

二、嵌套表


    1、嵌套表的特点:  
        元素下表从1开始,个数没有限制.即元素个数可以动态增长  
        嵌套表的数组元素值可以是稀疏的,即可以使得中间的某个元素没有赋值  
        嵌套表的语法与联合数组类似,不同的是仅仅是少了index by子句     
        嵌套表必需先初始化,然后才能引用其中的元素。如果初始化为空值,则后续需要使用extend来扩展其大小   
        嵌套表初始化时为密集的,但允许有间隙,即允许使用内置过程delete从嵌套表中删除元素  
        嵌套表类型可以作为表列的数据类型来使用  
      
    2、语法  
            TYPE type_name IS TABLE OF element_type [NOT NULL];   -->element_type为索引表元数据指定数据类型(先使用TYPE声明表结构)   
            table_name TYPE_NAME;                                 -->再使用声明的TYPE类型声明实际嵌套表         
      
    3、示例  
    --声明嵌套表并输出嵌套表的实际内容            
    scott@CNMMBO> DECLARE  
      2     CURSOR name_cur IS  
      3        SELECT dname  
      4        FROM   dept  
      5        WHERE  deptno < 40;  
      6   
      7     TYPE name_type IS TABLE OF dept.dname%TYPE;  
      8   
      9     dname_tab   name_type := name_type( );   -->需要初始化,否则将收到 ORA-06531:Reference to uninitialized collection.  
     10     v_counter   INTEGER := 0;  
     11  BEGIN  
     12     FOR name_rec IN name_cur  
     13     LOOP  
     14        v_counter   :=  
     15           v_counter  
     16           + 1;  
     17        dname_tab.EXTEND;         -->需要扩展,否则将收到 ORA-06533: Subscript beyond count  
     18        dname_tab( v_counter ) := name_rec.dname;  
     19        DBMS_OUTPUT.put_line(   'Dname ('  
     20                             || v_counter  
     21                             || ') is :'  
     22                             || dname_tab( v_counter ) );  
     23     END LOOP;  
     24  END;  
     25  /  
    Dname (1) is :ACCOUNTING  
    Dname (2) is :RESEARCH  
    Dname (3) is :SALES  
      
    PL/SQL procedure successfully completed.  
      
    --将嵌套表作为表列的数据类型来使用  
    scott@CNMMBO> CREATE OR REPLACE TYPE mail_type IS TABLE OF VARCHAR2( 100 );  
      2  /  
      
    Type created.  
      
    scott@CNMMBO> CREATE TABLE tb_tmp       -->创建表tb_tmp  
      2  (  
      3     empno   NUMBER( 4 )  
      4   , ename   VARCHAR2( 10 )  
      5   , mail    mail_type               -->列mail的类型为mail_type  
      6  )  
      7  NESTED TABLE mail                 -->注意此处需要指定嵌套表的存储方式  
      8     STORE AS mail_tab;  
      
    Table created.  
      
    --为嵌套表插入数据  
    scott@CNMMBO> insert into tb_tmp select 8888,'Jack','Jack@yahoo.com,Jack@163.com' from dual;  -->传统方式插入失败  
    insert into tb_tmp select 8888,'Jack','Jack@yahoo.com,Jack@163.com' from dual  
                                          *  
    ERROR at line 1:  
    ORA-00932: inconsistent datatypes: expected - got CHAR  
      
    scott@CNMMBO> insert into tb_tmp select 8888,'Jack',q'['Jack@yahoo.com','Jack@163.com']' from dual;  -->分割字符串方式插入失败  
    insert into tb_tmp select 8888,'Jack',q'['Jack@yahoo.com','Jack@163.com']' from dual  
                                          *  
    ERROR at line 1:  
    ORA-00932: inconsistent datatypes: expected - got CHAR  
      
    scott@CNMMBO> insert into tb_tmp select 8888,'Jack',mail_type('Jack@yahoo.com','Jack@163.com') from dual; -->插入时指定嵌套表类型   
      
    1 row created.  
      
    scott@CNMMBO> commit;  
      
    Commit complete.  
      
    --查看存在嵌套表数据类型的表中的记录  
    scott@CNMMBO> col mail format a30  
    scott@CNMMBO> select * from tb_tmp;                    -->查询数据时带有嵌套表的类型  
      
         EMPNO ENAME      MAIL  
    ---------- ---------- ------------------------------  
          8888 Jack       MAIL_TYPE('Jack@yahoo.com', 'J  
                          ack@163.com')  
      
    scott@CNMMBO> DECLARE  
      2     mail_tab   mail_type;    -->声明一个mail_type数据类型  
      3  BEGIN  
      4     SELECT mail  
      5     INTO   mail_tab          -->将数据保存到 mail_tab 变量中  
      6     FROM   tb_tmp  
      7     WHERE  empno = 8888;  
      8   
      9     FOR i IN 1 .. mail_tab.COUNT   -->轮循输出嵌套表类型中的值  
     10     LOOP  
     11        DBMS_OUTPUT.put_line( 'Jack mail address is '  
     12                             || mail_tab( i ) );  
     13     END LOOP;  
     14  END;  
     15  /  
    Jack mail address is Jack@yahoo.com  
    Jack mail address is Jack@163.com  
      
    PL/SQL procedure successfully completed.  
      
    --更新表中含有嵌套表类型中的值  
    scott@CNMMBO> DECLARE  
      2     mail_tab   mail_type := mail_type( 'Jackson@yahoo.com', 'Jackson@163.com' );  
      3  BEGIN  
      4     UPDATE tb_tmp  
      5     SET    mail         = mail_tab;  
      6   
      7     COMMIT;  
      8     DBMS_OUTPUT.put_line( 'Jack mail address was updated' );  
      9  END;  
     10  /  
    Jack mail address was updated  
      
    PL/SQL procedure successfully completed.  
      
    scott@CNMMBO> select * from tb_tmp;  
      
         EMPNO ENAME      MAIL  
    ---------- ---------- ------------------------------  
          8888 Jack       MAIL_TYPE('Jackson@yahoo.com',  
                           'Jackson@163.com')  
      
    --删除表中存在嵌套表类型的记录  
    scott@CNMMBO> delete from tb_tmp where empno=8888;  
      
    1 row deleted.  
      
    scott@CNMMBO> commit;  
      
    Commit complete.  
      
    scott@CNMMBO> select * from tb_tmp;  
      
    no rows selected                        
    --> Author: Robinson Cheng  
    --> Blog: http://blog.iyunv.com/robinson_0612  

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



运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-21854-1-1.html 上篇帖子: 批量SQL之 BULK COLLECT 子句 下篇帖子: PL/SQL 联合数组与嵌套表 联合
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表