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;

    执行结果如下:

    
aa.jpg

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

    
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集合不能直接对其进行查询,除非写死下标,那样的话没有多大意义。最好对其进行遍历。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,752评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,100评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,244评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,099评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,210评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,307评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,346评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,133评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,546评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,849评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,019评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,702评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,331评论 3 319
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,030评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,260评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,871评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,898评论 2 351

推荐阅读更多精彩内容