PL/SQL 嵌套记录与记录集合_MySQL, Oracle及数据库讨论区_Weblogic技术|Tuxedo技术|中间件技术|Oracle论坛|JAVA论坛|Linux/Unix技术|hadoop论坛_联动北方技术论坛  
网站首页 | 关于我们 | 服务中心 | 经验交流 | 公司荣誉 | 成功案例 | 合作伙伴 | 联系我们 |
联动北方-国内领先的云技术服务提供商
»  游客             当前位置:  论坛首页 »  自由讨论区 »  MySQL, Oracle及数据库讨论区 »
总帖数
1
每页帖数
101/1页1
返回列表
0
发起投票  发起投票 发新帖子
查看: 1833 | 回复: 0   主题: PL/SQL 嵌套记录与记录集合        下一篇 
Michelle
注册用户
等级:列兵
经验:88
发帖:58
精华:0
注册:2011-8-11
状态:离线
发送短消息息给Michelle 加好友    发送短消息息给Michelle 发消息
发表于: IP:您无权察看 2015-7-21 15:29:21 | [全部帖] [楼主帖] 楼主

将多个逻辑上不相关列组合到一起形成了PL/SQL的记录类型,从而可以将记录类型作为一个整体对待来处理。而且PL/SQL记录类型可以进行嵌套以及基于PL/SQL记录来定义联合数组,嵌套表等。

    1、下面的示例同时描述了基于表,基于游标,以及基于用户自定义的记录  

    DECLARE
    rec_tab       dept%ROWTYPE;             -->基于表类型使用ROWTYPE来声明记录变量  


    v_counter     PLS_INTEGER := 0;
    CURSOR cur_tab IS-->声明游标
    SELECT dname, loc FROM dept;
    rec_cur_tab   cur_tab%ROWTYPE;          -->基于定义的游标使用ROWTYPE来声明记录变量  


    TYPE dept_rec_type IS RECORD            -->用户自定义记录类型
    (
    dname   dept.dname%TYPE              -->可以使用TYPE属性,也可以使用自定义的数据类型


    ,loc     dept.loc%TYPE
    );
    dept_rec      dept_rec_type;            -->基于自定义的记录类型来声明记录变量  


    BEGIN
    SELECT *
    INTO   rec_tab                          -->使用select into为记录变量赋值
    FROM   dept
    WHERE  deptno = 10;
    DBMS_OUTPUT.put_line( '------- First print record based on table--------' );
    DBMS_OUTPUT.put_line( 'Record is '   rec_tab.dname   ','   rec_tab.loc );
    OPEN cur_tab;
    DBMS_OUTPUT.put_line( '------- Next print record based on cursor--------' );
    LOOP
    FETCH cur_tab INTO rec_cur_tab;     -->使用fetch into为记录变量赋值  
    EXIT WHEN cur_tab%NOTFOUND;
    v_counter   := v_counter + 1;
    DBMS_OUTPUT.put_line( 'Record '   v_counter   ' is '   rec_cur_tab.dname   ','   rec_cur_tab.loc );
    END LOOP;
    CLOSE cur_tab;
    SELECT dname, loc                     -->对自定义的记录变量赋值     
    INTO   dept_rec
    FROM   dept
    WHERE  deptno = 20;
    DBMS_OUTPUT.put_line( '------- Finally print record based on user defined record--------' );
    DBMS_OUTPUT.put_line( 'Record is '   dept_rec.dname   ','   dept_rec.loc );
    END;


    2、记录的赋值与引用  

    DECLARE
    TYPE rec1_t IS RECORD       -->声明自定义记录类型
    (
    field1   VARCHAR2( 16 )
    ,field2   DATE
    );
    TYPE rec2_t IS RECORD       -->声明自定义记录类型
    (
    id     INTEGERNOTNULL:= -1    -->注意,此时使用NOT NULL约束,因此要赋初值,否则报错
    ,name   VARCHAR2( 64 ) NOTNULL:= '[anonymous]'
    );
    rec1   rec1_t;              -->声明自定义记录类型变量rec1和rec2


    rec2   rec2_t;
    BEGIN
    rec1.field1 := 'Yesterday';    -->赋值与引用时,使用record_name.field_name方式
    rec1.field2 := TRUNC( SYSDATE - 1 );
    DBMS_OUTPUT.put_line( 'rec1 values are '   rec1.field1   ','   rec1.field2 );
    DBMS_OUTPUT.put_line(  'rec2 values is ' rec2.name );
    END;


    3、为记录赋缺省值  

    DECLARE
    TYPE recordtyp IS RECORD
    (
    field1   NUMBER
    ,field2   VARCHAR2( 32 ) DEFAULT'something'
    );
    rec1   recordtyp;
    rec2   recordtyp;
    BEGIN
    -- 下面为变量rec1赋值


    rec1.field1 := 100;
    rec1.field2 := 'something else';
    --下面通过使用变量rec2将其值赋给rec1,则rec1恢复到原始状态,即Field1为NULL,field2为something


    rec1        := rec2;
    DBMS_OUTPUT.put_line( 'Field1 = '   NVL( TO_CHAR( rec1.field1 ), '<NULL>' )   ',
    field2 = '   rec1.field2 );
    END;


    4、记录类型作为过程的参数进行传递  

    DECLARE
    TYPE emp_rec_type IS RECORD                               -->自定义记录类型
    (
    eno     NUMBER( 6 )
    ,esal    NUMBER( 8, 2 )
    ,ename   VARCHAR2( 10 )
    );
    emp_info   emp_rec_type;                                  -->声明记录类型变量


    PROCEDURE raise_salary( emp_info INOUT emp_rec_type ) IS-->本地过程用于增加雇员薪水,其参数为IN OUT 型记录类型
    BEGIN
    UPDATE emp
    SET    sal          = sal + sal * emp_info.esal
    WHERE  empno = emp_info.eno
    RETURNING ename, sal                                   -->使用returning 子句将ename以及更新后的薪水赋值给记录变量  


    INTO   emp_info.ename, emp_info.esal;
    END raise_salary;
    BEGIN-->主程序块
    emp_info.eno := 7788;                                     -->对记录变量赋值,此时emp_info.ename为NULL,由调用过程生成 
    emp_info.esal := 0.5;
    raise_salary( emp_info );
    DBMS_OUTPUT.put_line( 'User '   emp_info.ename   '''s new salary is '   emp_info.esal );
    END;


    5、嵌套记录  
            可以在记录类型中包含对象、集合和其他的记录(又叫嵌套记录)。但是对象类型中不能把RECORD 类型作为它的属性。  

    DECLARE
    TYPE name_type IS RECORD                  -->定义记录类型
    (
    first_name   VARCHAR2( 15 )
    ,last_name    VARCHAR2( 20 )
    );
    TYPE person_info_type IS RECORD           -->定义记录类型
    (
    id          NUMBER( 6 )
    ,name        name_type                  -->name的类型为name_type,即嵌套 
    ,job_title   jobs.job_title%TYPE
    );
    person_rec   person_info_type;            -->声明记录变量


    BEGIN
    SELECT employee_id
    ,first_name
    ,last_name
    ,job_title
    INTO   person_rec.id
    ,person_rec.name.first_name    -->注意此时嵌套记录中的引用方法
    ,person_rec.name.last_name     -->enclosing_record.(nested_record或者nested_collection).field_name
    ,person_rec.job_title
    FROM   employees e JOIN jobs j ON e.job_id = j.job_id AND ROWNUM < 2;
    DBMS_OUTPUT.put_line( 'First name is '   person_rec.name.first_name );
    DBMS_OUTPUT.put_line( 'Last name is '   person_rec.name.last_name );
    END;


    6、记录集合  
            所有基于记录的集合在此统统可以称之为记录集合,即该集合类型是基于记录类型之上的。  

    --下面的示例是一个使用了基于游标类型的联合数组的记录集合


    DECLARE
    CURSOR cur_emp IS-->声明一个游标
    SELECT empno, ename, hiredate
    FROM   emp
    WHERE  deptno = 20
    ORDERBY 1;
    TYPE emp_tab_type ISTABLEOF cur_emp%ROWTYPE    -->基于游标类型定义了一个联合数组
    INDEXBY BINARY_INTEGER;
    emp_tab     emp_tab_type;                -->声明复合变量


    v_counter   INTEGER := 0;
    BEGIN
    FOR emp_rec IN cur_emp
    LOOP
    v_counter   := v_counter + 1;        -->v_counter用于控制下标  


    emp_tab( v_counter ).empno := emp_rec.empno;   -->给复合变量赋值,注意引用方法


    emp_tab( v_counter ).ename := emp_rec.ename;
    emp_tab( v_counter ).hiredate := emp_rec.hiredate;
    DBMS_OUTPUT.put_line('Recored ' v_counter ' is ' emp_tab(v_counter).ename  ','   emp_tab( v_counter ).hiredate );
    END LOOP;
    END;
    --下面的示例是一个基于自定义记录类型的嵌条表,注意嵌套表需要扩展


    --我们知道,游标通常为单条多列的记录,而联合数组,嵌套表以及变长数组为单列多行


    --因此记录类型与集合类型的复合我们可以将其想象成一张二维表,因此对于这种类型的操作,更高效的是直接使用bulk collect子句来操纵


    --下面不再列出使用bulk collect 的示例,注,使用bulk collect 子句使,集合类型不需要手动扩展


    DECLARE
    TYPE rec_type IS RECORD                      -->定义记录类型
    (
    ename      emp.ename%TYPE
    ,empno      emp.empno%TYPE
    ,hiredate   emp.hiredate%TYPE
    );
    TYPE emp_tab_type ISTABLEOF rec_type;      -->定义基于记录类型的嵌套表     
    emp_tab     emp_tab_type := emp_tab_type( ); -->初始化嵌套表


    v_counter   INTEGER := 0;
    BEGIN
    FOR emp_rec IN (SELECT *
    FROM   emp
    WHERE  deptno = 20 )
    LOOP
    v_counter   := v_counter + 1;
    emp_tab.EXTEND;                           -->需要使用extend方式来扩展 


    emp_tab( v_counter ).empno := emp_rec.empno;
    emp_tab( v_counter ).ename := emp_rec.ename;
    emp_tab( v_counter ).hiredate := emp_rec.hiredate;
    DBMS_OUTPUT.put_line('Recored ' v_counter ' is ' emp_tab(v_counter).ename ',' emp_tab( v_counter ).hiredate );
    END LOOP;
    END;


    7、几点注意事项:  
    a、不能测试记录是否为NULL、是否相等或不等,下面的操作都是非法的。  

     IF dept_rec ISNULLTHEN ...
    IF dept_rec1 = dept_rec2 THEN ...


    b、记录类型不同于变长数组与嵌套表,不能存储在数据库中  



--转自 北京联动北方科技有限公司




赞(0)    操作        顶端 
总帖数
1
每页帖数
101/1页1
返回列表
发新帖子
请输入验证码: 点击刷新验证码
您需要登录后才可以回帖 登录 | 注册
技术讨论