PL/SQL中的记录

Posted by 道行尚浅 on March 6, 2008

记录

记录的概念

记录是一种复合数据类型.记录类似与一个一行多列的表.

当然我们也可以声明记录类型为一行一列,不过并没有实际意义,这种情况下我们应该使用变量.

我们可以通过三种方式定义记录

  • 基于表的记录
  • 基于游标的记录
  • 用户自定义记录

基于表的记录

我们使用表名%rowtype来定义基于表的记录

例程:使用变量接收数据

declare
  v_deptNo dept.deptno%type;
  v_dname  dept.dname%type;
  v_loc    dept.loc%type;
begin
  SELECT * INTO V_DEPTNO, V_DNAME, V_LOC FROM DEPT WHERE ROWNUM = 1;
  DBMS_OUTPUT.put_line(V_DEPTNO);
  DBMS_OUTPUT.put_line(V_DNAME);
  DBMS_OUTPUT.put_line(V_LOC);
end;

执行结果:


10
ACCOUNTING
NEW YORK

PL/SQL procedure successfully completed

例程: 使用基于表的记录类型接收数据

declare
 R_DEPT DEPT%ROWTYPE ;
begin
  SELECT * 
    INTO R_DEPT
    FROM DEPT 
   WHERE ROWNUM = 1;
 DBMS_OUTPUT.put_line(r_dept.deptno);   
 DBMS_OUTPUT.put_line(r_dept.dname);
 DBMS_OUTPUT.put_line(r_dept.loc);  
end;

执行结果:


10
ACCOUNTING
NEW YORK

PL/SQL procedure successfully completed

我们来讲解一下上面的例程

graph LR
发现表名rowtype关键字-->查找表结构
查找表结构-->根据表结构构造记录结构

查看表结构


SQL> desc dept ;
 Name            Null?    Type
 --------------- -------- ----------------------------
 DEPTNO          NOT NULL NUMBER(2)
 DNAME                    VARCHAR2(14)
 LOC                      VARCHAR2(13)

  • 记录结构
deptno dname loc
NUMBER(2) VARCHAR2(14) VARCHAR2(13)
NULL NULL NULL

基于游标的记录

graph LR
发现游标rowtype关键字-->查找游标引用的列
查找游标引用的列--> 根据列名查找数据类型
根据列名查找数据类型-->构造记录类型

例程:基于游标的记录

DECLARE
 CURSOR C1 IS  
  SELECT DEPTNO,DNAME FROM DEPT ;
 R_C1 C1%ROWTYPE ;
BEGIN
 OPEN  C1 ;
 FETCH C1 INTO R_C1 ;
 CLOSE C1 ;
  DBMS_OUTPUT.put_line(R_C1.DEPTNO) ;
  DBMS_OUTPUT.put_line(R_C1.DNAME) ;  
END ;
   

执行结果


10
ACCOUNTING

PL/SQL procedure successfully completed

用户自定义记录

这种记录类型多与动态SQL游标匹配使用

graph LR

定义数据类型RECORD_TYPE -->根据类型定义变量R_USER_DEFINE

例程:用户自定记录

DECLARE
  CURSOR C1 IS
    SELECT DEPTNO, DNAME FROM DEPT;
  TYPE RECORD_TYPE IS RECORD(
    DEPTNO NUMBER(2),
    DNAME  VARCHAR2(14));
  R_USER_DEFINE RECORD_TYPE;
BEGIN
  OPEN C1;
  FETCH C1
    INTO R_USER_DEFINE;
  CLOSE C1;
  DBMS_OUTPUT.put_line(R_USER_DEFINE.DEPTNO);
  DBMS_OUTPUT.put_line(R_USER_DEFINE.DNAME);
END;

记录的兼容性


DECLARE
  TYPE RECORD_TYPE1 IS RECORD(
    DEPTNO NUMBER(2),
    DNAME  VARCHAR2(14));
  TYPE RECORD_TYPE2 IS RECORD(
    DEPTNO NUMBER(2),
    DNAME  VARCHAR2(14));  
      
  R_USER_DEFINE_1 RECORD_TYPE1;
  R_USER_DEFINE_2 RECORD_TYPE2;
BEGIN
  R_USER_DEFINE_1.deptno :=10;
  R_USER_DEFINE_1.DNAME  :='AAA';
  -- 此处引发报错
  R_USER_DEFINE_2 :=R_USER_DEFINE_1 ;
  
END;

由于 R_USER_DEFINE_1 数据类型为RECORD_TYPE1 R_USER_DEFINE_2 数据类型为RECORD_TYPE2

虽然数据类型RECORD_TYPE1与RECORD_TYPE2 结构一致,但是Oracle并不会判定由两个类型构造出来的记录变量类型一致.

当然这种情况我们很少遇到,更多的时候我们只会定义一个类型,然后根据这个数据类型构造两个记录变量. 参见例程:记录间赋值

执行结果

ORA-06550: line 15, column 21:
PLS-00382: expression is of wrong type
ORA-06550: line 15, column 3:
PL/SQL: Statement ignored

例程:记录间赋值1

DECLARE
  TYPE RECORD_TYPE1 IS RECORD(
    DEPTNO NUMBER(2),
    DNAME  VARCHAR2(14));

  R_USER_DEFINE_1 RECORD_TYPE1;
  R_USER_DEFINE_2 RECORD_TYPE1;
BEGIN
  R_USER_DEFINE_1.deptno :=10;
  R_USER_DEFINE_1.DNAME  :='AAA';
  
  --此处直接使用记录赋值
  R_USER_DEFINE_2 :=R_USER_DEFINE_1;
  
  DBMS_OUTPUT.put_line(R_USER_DEFINE_2.DEPTNO);
  DBMS_OUTPUT.put_line(R_USER_DEFINE_2.DNAME);  
END;

执行结果

10
AAA

PL/SQL procedure successfully completed

例程:记录间赋值2

下面这种方法适用于不同类型的记录类型.

DECLARE
  TYPE RECORD_TYPE1 IS RECORD(
    DEPTNO NUMBER(2),
    DNAME  VARCHAR2(14));
  TYPE RECORD_TYPE2 IS RECORD(
    DEPTNO NUMBER(2),
    DNAME  VARCHAR2(14));  
      
  R_USER_DEFINE_1 RECORD_TYPE1;
  R_USER_DEFINE_2 RECORD_TYPE2;
BEGIN
  R_USER_DEFINE_1.deptno :=10;
  R_USER_DEFINE_1.DNAME  :='AAA';
  
  R_USER_DEFINE_2.DEPTNO :=R_USER_DEFINE_1.DEPTNO ;
  R_USER_DEFINE_2.DNAME :=R_USER_DEFINE_1.DNAME ;
  
  DBMS_OUTPUT.put_line(R_USER_DEFINE_2.DEPTNO);
  DBMS_OUTPUT.put_line(R_USER_DEFINE_2.DNAME);  
END;

执行结果

10
AAA

PL/SQL procedure successfully completed

嵌套记录

将一种记录类型嵌套另一个记录类型的定义部分,可以构造出嵌套记录


DECLARE
  TYPE RECORD_TYPE1 IS RECORD(
    DEPTNO NUMBER(2),
    DNAME  VARCHAR2(14));
  TYPE RECORD_TYPE2 IS RECORD(
    COL1 RECORD_TYPE1 ,  --将类型1的记录放入到类型2的定义部分
    LOC  VARCHAR2(13));  
  R_USER_DEFINE_1 RECORD_TYPE2;
BEGIN
  R_USER_DEFINE_1.COL1.deptno :=10;
  R_USER_DEFINE_1.COL1.DNAME  :='AAA';
  R_USER_DEFINE_1.LOC  :='CCCC';
  
  DBMS_OUTPUT.put_line(R_USER_DEFINE_1.COL1.deptno );
  DBMS_OUTPUT.put_line(R_USER_DEFINE_1.COL1.DNAME );
  DBMS_OUTPUT.put_line(R_USER_DEFINE_1.LOC );
END;

执行结果 ```sql

10 AAA CCCC

PL/SQL procedure successfully completed `