PL/SQL自定义类型

ORACLE中自定义数据类型的方式一般是三种:RECORD、VARRAY、TABLE

RECORD

    定义记录数据类型。它类似于JAVA语言中的对象,PL/SQL提供了将几个相关的、分离的、基本数据类型的变量组成一个整体的方法,即RECORD复合数据类型。在使用记录数据类型变量时,需要在声明部分先定义记录的组成、记录的变量,然后在执行部分引用该记录变量本身或其中的成员。
    定义记录型数据类型的语法:

TYPE RECORD_NAME IS RECORD(
         V1  DATA_TYPE1 [NOT NULL][:=DEFAULT_VALUE],
         V2  DATA_TYPE2 [NOT NULL][:=DEFAULT_VALUE],
         VN  DATA_TYPEN [NOT NULL][:=DEFAULT_VALUE]);

    定义记录型数据类型实例:

      declare 
            type typeOfRecord is record( -- 使用RECORD方式创建一个自定义数据类型
                  v_name    testKD.Username%type,-- 自定义类型中的变量
                  v_curtime testKD.Curtime%type
             );
            v_record typeOfRecord;-- 在pl/sql程序中声明自定义类型
      begin
            -- 查询数据并设置到自定义类型中
            select username,curtime into v_record from testKD where serviceno = '2017112800015';
            dbms_output.put_line('name : ' || v_record.v_name);
            dbms_output.put_line('curtime : ' || v_record.v_curtime);

      end;

    执行结果如下:

    
《PL/SQL自定义类型》 aa.jpg

    注意事项:record方式不能接受查出来是有多个值的。如,将where条件取消,将会报如下错误:

    
《PL/SQL自定义类型》 a.jpg

VARRAY

    定义数组类型。数组是具有相同数据类型的一组成员的集合。每个成员都有一个唯一的下标,它取决于成员在数组中的位置。在PL/SQL中,数组数据类型是VARRAY(variable array,即可变数组)。
    定义VARRAY数据类型的语法:

  TYPE VARRAY_NAMEIS IS VARRAY(SIZE) OF ELEMENT_TYPE [NOT NULL];
   其中,varray_name是VARRAY数据类型的名称,size是正整数,表示可以容纳的成员的最大数量,
   每个成员的数据类型是element_typeo默认时,成员可以取空值,否则需要使用NOT NULL加以限制。

    定义VARRAY数据类型实例:

declare
    -- 自定义一个数组类型,数组的长度是5,
    -- 数组中元素的类型是varchar2且取值范围是25
    type typeOfVarray is varray(5) of varchar2(25);
    
    v_varray    typeOfVarray; -- 声明自定义数组变量
    
begin
  -- 给自定义数组变量赋值
  v_varray := typeOfVarray('1','2','3','4','5');

  -- 注意:该VARRAY数组类型下标从1开始,而不是从0开始
  dbms_output.put_line(v_varray(1));
  dbms_output.put_line(v_varray(2));
  dbms_output.put_line(v_varray(3));
  dbms_output.put_line(v_varray(4));
  dbms_output.put_line(v_varray(5));
end;   

TABLE

    定义记录表(或索引表)数据类型。它与记录类型相似,但它是对记录类型的扩展。它可以处理多行记录,类似于C语言中的二维数组,使得可以在PL/SQL中模仿数据库中的表。
    定义TABLE类型语法:

    TYPE TABLE NAME IS TABLE OF ELEMENT_TYPE [NOT NULL]
                 INDEX BY [BINARY_INTEGER|PLS_INTEGER|VARRAY2];

    关键字INDEX BY表示创建一个主键索引,以便引用记录表变量中的特定行。
    BINARY_INTEGER的说明:如语句,TYPE NUMBERS IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;其作用是,加了”INDEX BY BINARY_INTEGER ”后,NUMBERS类型的下标就是自增长,NUMBERS类型在插入元素时,不需要初始化,不需要每次EXTEND增加一个空间。而如果没有这句话“INDEX BY BINARY_INTEGER”,那就得要显示对初始化,且每插入一个元素到NUMBERS类型的TABLE中时,都需要先EXTEND。
    定义TABLE类型实例1–存储单列多行:

-- 这个和VARRAY类似。但是赋值方式稍微有点不同,
-- 不能使用同名的构造函数进行赋值。如下:
declare 
    -- 自定义类型
    type typeOfTable is table of varchar2(25) index by binary_integer;
    v_table typeOfTable;-- 声明变量

begin
    v_table(1) := '1';
    v_table(2) := '2';
    v_table(3) := '3';
    v_table(4) := '4';
    v_table(5) := '5';
    -- 可见这种类型是支持任意个类型为varchar2的元素,
    -- 也可以说它是一个可变长度的数组
    dbms_output.put_line(v_tablle(1));
    dbms_output.put_line(v_tablle(2));
    dbms_output.put_line(v_tablle(3));
    dbms_output.put_line(v_tablle(4));
    dbms_output.put_line(v_tablle(5));
            
end;

    定义TABLE类型实例1–存储多列多行和ROWTYPE结合使用:

-- 采用bulk collect可以将查询结果一次性加载到collections中。
-- 而不是通过cursor一条一条地处理
declare
    -- 自定义一个table类型,
    -- 这里就相当于创建了一个跟testkd表结构一样的多个临时表“容器”
    type t_type is table of testkd%rowtype;
    v_type t_type;-- 声明变量
begin
    -- 查询并给v_type赋值
    select testkd.id,testkd.name,testkd.flag bulk collect into v_type
        from testkd
        where testkd.id <= 5;
    
    /*while v_type.count > 5 --此处不能使用count,是无效的
    loop
        dbms_output.put_line('id : ' || v_type.id 
                        || '  name : ' || v_type.name
                        || '  flag : ' || v_type.flag);
        --而且这种循环会报错:说id等属性没有声明 
        -- 从下面的测试中也可以看出,
        -- 这种循环根本无法获取到数组的下标,
        -- 而v_type本身可以看做是一个数组确实没有其他的属性,
        -- 只是它里面的元素可以看做是个表结构,所以通过.xxx来获取值                           
    end loop; */
    dbms_output.put_line('id : ' || v_type(2).id 
                        || '  name : ' || v_type(2).name
                        || '  flag : ' || v_type(2).flag);
    
    dbms_output.put_line('--------------------------------');
                        
    for i in v_type.first .. v_type.last -- 这里留意一下first  last的用法
    loop
        dbms_output.put_line('id : ' || v_type(i).id 
                        || '  name : ' || v_type(i).name
                        || '  flag : ' || v_type(i).flag);
                                       
    end loop;  
    
    -- 由下面的测试可知 v_type(i)不用看做是一个真正临时表
    /*declare
        v_id   v_type(1).id%type;-- 声明变量就出错
        v_name v_type(1).name%type;
        v_flag v_type(1).flag%type;
    begin    
        select id,name,flag into v_id,v_name,v_flag from v_type(1);
        dbms_output.put_line('v_id : ' || v_id || 
                ' v_name : ' || v_name || '  v_flag : ' || v_flag);
    --insert into v_type(2)(id,name,flag) values(11,'kkk','3'); 
    --commit;     
    end;*/        
end;

    定义TABLE类型实例1–存储多列多行和RECORD结合使用:

declare
    -- 按照前面的record的认识,这里定义相当于定义一个对象
    type v_test is record(
        test_id testkd.id%type,
        test_name testkd.name%type,
        test_flag testkd.flag%type
    ); 
    -- 定义一个table类型(即表结构),它的列来自于v_test
    type t_type is table of v_test;
    -- 声明t_type类型的变量
    v_type t_type;
begin
    select id,name,flag bulk collect into v_type 
        from testkd
        where testkd.id <= 5;
    
    for i in v_type.first .. v_type.last loop
        dbms_output.put_line('id : ' || v_type(i).test_id
                                || ' name : ' || v_type(i).test_name
                                || ' flag : ' || v_type(i).test_flag);
    end loop;
end;

-- 显然这种方式比上面的rowtype方式麻烦些


注意事项:

    VARRAY和TABLE集合不能直接对其进行查询,除非写死下标,那样的话没有多大意义。最好对其进行遍历。

    原文作者:xiang205012
    原文地址: https://www.jianshu.com/p/0263aa8dc432
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞