zoukankan      html  css  js  c++  java
  • Oracle Class10. 集合和成员函数(pl/sql表和记录,嵌套表和可变数组,成员函数和过程) 全新时代

    ------------------------2013-5-21------------------------
    定义表的类型
    type tablename is table of col_def index by binary_integer;
    声明表的类型
    Tablename tablename

    pl/sql表
    临时使用,像数组一样的对象。
    包含一列和一个主键
    不能对列和主键进行命名
    列可以是任何标量数据类型
    主键必须是binary_integer类型
    大小没有限制

    引用:tablename(key_value)
    赋值:tablename(key_value) := expression;

    记录 %rowtype来声明记录。

    定义记录类型
    type typename is record(列定义 ...);
    声明记录类型
    recordtype typename;
    引用记录
    recordtype.columnname
    赋值
    recordtype.columnname := expression;

    pl/sql的运行
    oracle使用两个引擎来运行pl/sql块和sql语句
    pl/sql引擎运行过程语句。
    sql引擎运行sql语句。

    声明嵌套表
    type tablename IS TABLE OF tabletype;

    嵌套表与索引表差异
    嵌套表    索引表
    使用sql来操纵并存储在数据库中 不可能
    下标范围:1到2147483647  下标范围:-2147483647到2147483647
    可用is null操作符来验证  不可验证
    可用extend和trim方法  不可用

    声明可变数组
    TYPE typename IS VARRAY(Maximum_size) OF element_type(not null);
    -typename是可变数组名
    -Maximum_size设置了元素的数目
    -element_type不能为boolean,ref游标,表或者另一种可变数组类型。

    -----------------------------------------------
    exists(n) 第n个元素存在,返回true
    count 总数
    limit 最大数目
    first 第一个元素   (下标值)
    last  最后一个元素   (下标值)
    prior(x)  第x个元素之前的元素      (下标值)
    next(x)  第x个元素之后的元素  (下标值)
    extend(x,y) 追加x个第y个元素的副本
    trim(x)  从集合的末尾处截断x个元素
    delete 删除部分或全部元素
    -----------------------------------------------

    ##forall应用举例##
    -- 采用ForAll对变量进行批量邦定,然后一次发送
    declare
      type tt is table of int index by binary_integer;
      lv_tt tt;
      t1 char(5);
      t2 char(5);
      t3 char(5);
      procedure get_time(t out number)
      is
      begin
        --取得当前时间
         select to_char(sysdate, 'sssss') into t from dual;
      end;
    begin

      for i in 1 .. 100000
      loop
        lv_tt(i) := i;
      end loop;
     
      get_time(t1);
     
      for i in 1 .. 100000
      loop
        insert into ttt2 values (lv_tt(i));   
      end loop;
       
      get_time(t2);
     
      forall i in 1 .. 100000
        insert into ttt2 values (lv_tt(i));   
     
      get_time(t3);
     
      dbms_output.put_line('未批量邦定耗时:');
      dbms_output.put_line(t2 - t1);
      dbms_output.put_line('批量邦定耗时:');
      dbms_output.put_line(t3 - t2);

    end;


    未批量邦定耗时:
    10
    批量邦定耗时:
    0


    ##bulk collect##
    declare
      -- PL/SQL表(索引表)
      type ttt is table of int index by binary_integer;
      lv_tt ttt;
    begin

      select a BULK Collect into lv_tt from tt;       --BULK Collect

      for i in 1 .. 3
      loop
        dbms_output.put_line(lv_tt(i));
      end loop;
       
    end;


    create table tt
    (
    a int,    -- 自动增长/在触发器中实现 ???
    b int
    )

    create or replace trigger triInsertTT
    before insert
    on tt
    for each row
    begin
      :New.a := 1;
    end;


    set serveroutput on;
    --动态sql
    declare
    i int;
    begin
    --execute immediate 'create table aqq(i int)';
    --execute immediate 'insert into aqq values(1) ';
    i := 13;
    execute immediate 'insert into aqq values('|| i ||') ';      --这样写才正确
    --execute immediate 'insert into aqq values(i) ';            --ORA-00984: 列在此处不允许
    --'insert into a values (i)';                                --PLS-00490: 非法语句
    end;

    select * from aqq;

    declare
    type tt is table of int index by binary_integer;
    lv_t tt;
    begin
      for i in 5 .. 10   --从哪个值开始都可以。
      loop
        lv_t(i) := i;
      end loop;
     
      for i in 5 .. 10   --从哪个值开始都可以。
      loop
        dbms_output.put_line(lv_t(i));
      end loop;
    end;

    declare
    type tr is record
    (
    a int,
    b int
    );
    type tt is table of tr index by binary_integer;
    lv_t tt;
    begin
      for i in 2 .. 10   --从哪个值开始都可以。
      loop
        lv_t(i).a := i * 2;
        lv_t(i).b := i * 3;
      end loop;
     
      for i in 2 .. 10   --从哪个值开始都可以。
      loop
        dbms_output.put(lv_t(i).a || ' --- ');    --输出不换行。
        dbms_output.put_line(lv_t(i).b);
      end loop;
    end;

    #type嵌套的情况#
    declare
    type tr1 is record
    (
    b int
    );
    type tr is record
    (
    a tr1
    );
    type tt is table of tr index by binary_integer;
    lv_t tt;
    begin
      for i in 4 .. 10   --从哪个值开始都可以。
      loop
        lv_t(i).a.b := i;
      end loop;
     
      for i in 4 .. 10   --从哪个值开始都可以。 如果索引值不对,报ORA-01403: 未找到数据。
      loop
        dbms_output.put_line(lv_t(i).a.b);
      end loop;
    end;

    ##存在问题??? ##
    declare
    type t is record
    (
    a int
    --b varchar2(10)
    );
    type tt is table of t index by binary_integer;
    lv_t2 tt;
    begin
      select a into lv_t2 from c6;   --bulk collect  --PLS-00597: INTO 列表中的表达式 'LV_T2'  类型错误
      for i in 1 .. lv_t2.count
      loop
        dbms_output.put(lv_t2(i).a || ' --- ');
        --dbms_output.put_line(lv_t2(i).b);
      end loop;
    end;

    ##存在问题??? ##
    declare
    type t is record
    (
    a int,
    b varchar2(10)
    );
    type tt is table of t index by binary_integer;
    lv_tt tt;
    begin
      select a,b bulk collect into lv_tt from c6;   --bulk collect  --PLS-00597: INTO 列表中的表达式 'LV_T2'  类型错误
      dbms_output.put_line(lv_tt.count || '~~~~~~' );
      for i in 1 .. lv_tt.count
      loop
        dbms_output.put(lv_tt(i).a || ' --- ');
        dbms_output.put_line(lv_tt(i).b);
      end loop;
    end;
       


    declare
    type tt is table of varchar2(24) index by binary_integer;
    lv_tt tt;
    begin
      select b bulk collect into lv_tt from c6;   --bulk collect可以--
      dbms_output.put_line(lv_tt.count || '~~~~~~' );
      for i in 1 .. lv_tt.count
      loop
        dbms_output.put(lv_tt(i) || ' --- ');
      end loop;
    end;

    --集合 记录 对象(抽象数据类型)
    declare
    type address_rec is record           --自定义类型
    (
    state varchar2(12),
    city varchar2(12),
    street_name varchar2(12),
    street_no varchar2(4)
    );
    lv_address_rec address_rec;
    begin
      lv_address_rec.state := 'HN';
      lv_address_rec.city := 'ZZ';
      dbms_output.put_line(lv_address_rec.state);
      dbms_output.put_line(lv_address_rec.city);
    end;


    --建立程序包,仅包含一个自定义数据类型。
    create or replace package pkg_school
    is
    type address_rec is record           --自定义类型
    (
    state varchar2(12),
    city varchar2(12),
    street_name varchar2(12),
    street_no varchar2(4)
    );
    end pkg_school;

    --简化以上的代码--
    declare
    lv_address_rec pkg_school.address_rec;      --使用程序包来取代
    begin
      lv_address_rec.state := 'HN';
      lv_address_rec.city := 'ZZ';
      dbms_output.put_line(lv_address_rec.state);
      dbms_output.put_line(lv_address_rec.city);
    end;


    --创建学生表,使用自定义类型。
    create table student
    (
    no char(4),
    name varchar2(8),
    address pkg_school.address_rec   --报错:ORA-00902: 无效数据类型
    );


    create table student10
    (
    no char(4),
    name varchar2(8),
    address address_rec5             --要使用永久性对象,自定义类型才可以。
    );

    --添加值
    insert into STUDENT10 values ('0001','ANiu',address_rec5('HN','ZZ','TL','0001'));


    select no,name,address.state from STUDENT10;    --这样写会报错。address.state  ORA-00904: 无效列名
    select * from STUDENT10;
    select no,name,address from STUDENT10;

    #这样写才可以,通过别名的方式。#
    select no,name,s.address.state from STUDENT10 s;


    --添加,通过pl/sql方式。
    declare
    lv_address address_rec5;
    begin
      lv_address := address_rec5('GD','ZZ','TL','0001');
      insert into STUDENT10 values ('0001','ANiu',lv_address);   --通过变量的方式,lv_address
    end;


    --通过点分法修改address_rec5
    update student10 s set s.address.state = 'HK' where s.no='0001';

    --删除
    delete student10 s where s.address.state = 'HK';


    --定义索引,在自定义抽象数据类型的字段上,优化查询性能。
    create index street_name_idx on student10(address.street_name);

    --查看用户定义的索引
    select index_name,index_type,table_name,table_type from user_indexes where table_name = 'STUDENT10';


    --#这样创建表会报错??#
    declare
    type address_rec is record           --自定义类型
    (
    state varchar2(12),
    city varchar2(12),
    street_name varchar2(12),
    street_no varchar2(4)
    );
    begin
      create table students
      (
      no char(4),
      name varchar2(8),
      address address_rec
      );
    end;

    --创建类型
    create type address_rec4 as record   --会报错  as object
    (
    state varchar2(12),
    city varchar2(12),
    street_name varchar2(12),
    street_no varchar2(4)
    );

    declare
    type address_rec4 is record  --暂态对象
    (
    state varchar2(12),
    city varchar2(12),
    street_name varchar2(12),
    street_no varchar2(4)
    );
    begin
    dbms_output.put_line('aaa');
    end;


    create type address_rec4 as object   --需要写成object,永久性对象。
    (
    state varchar2(12),
    city varchar2(12),
    street_name varchar2(12),
    street_no varchar2(4)
    );

    --删除自定义抽象数据类型
    drop type address_rec4;
    --强制删除
    drop type address_rec4 force;


    --使用自定义类型
    declare
    lv_address address_rec5;
    begin
    lv_address := address_rec5('HN','ZZ','TL','0001');
    dbms_output.put_line(lv_address.state);
    dbms_output.put_line(lv_address.city);
    dbms_output.put_line(lv_address.street_name);
    dbms_output.put_line(lv_address.street_no);
    end;

    select column_name,data_type from user_tab_columns where table_name = 'student10';  --查询不了结果。
    select column_name,data_type from user_tab_columns where table_name = 'STUDENT10';  --表名要大写才可以。

    --查询类型属性。
    select attr_name,length,attr_type_name from user_type_attrs where type_name = 'ADDRESS_REC5';

    --查看对象依赖性
    desc user_dependencies;

    select name,type from user_dependencies where referenced_name = 'ADDRESS_REC5';


    --##对象表的概念##
    create table Address of address_rec5;

    -- 查看
    desc Address;
    -- 添加
    insert into Address values(address_rec5('HN','ZZ','TL','0001'));
    insert into Address values('SH','PJ','XH','0005');               --也可以这样添加值。
    -- 查询
    select * from address;

    --通过value函数可以将查询结果作为一个对象的集合返回
    select value(a) from address a;   --有要求的,不是任何一个表都可以,而是要基于对象表创建的表才可以。

    --调用
    declare
    s1 address_rec5;  --类型,而不是Address,否则会报错。
    begin
    select value(s) into s1 from address s where s.state = 'SH';
    dbms_output.put_line(s1.state);
    dbms_output.put_line(s1.city);
    dbms_output.put_line(s1.street_name);
    dbms_output.put_line(s1.street_no);
    end;


    insert into Address values(address_rec5('GD','GZ','XA','0001'));
    insert into Address values(address_rec5('XX','XA','BJ','0004'));

    --oid
    --oracle自动分配给对象表中每一条对象记录的一个唯一标示号
    --通过ref来进行调用
    select ref(a) from address a;  --有几条记录就返回几条a地址值.如
    REF(A)
    --------------------------------------------------------------------------------
    00002802096D5EE0A11F2C4C828CE4DB0E4B9DBA51592BB9591600436887DFDE706F178DBC004086
    E60000

    00002802094F82C9267C2C4BE6B21E9851001E74B3592BB9591600436887DFDE706F178DBC004086
    E60001

    0000280209C955BEBAA7D04674995B5996900A6330592BB9591600436887DFDE706F178DBC004086
    E60002

    #OID应用#  deref()函数  Dangling

    ##可变数组varray##
    --可变数组
    declare
    -- 定义可变数组 varing array =>varray
    type authors_ary is varray(5) of varchar2(12);
    -- 声明数组变量,通过构造函数初始化
    lv_authors authors_ary := authors_ary('A','B','C');
    begin
      --通过索引下标来调用
      dbms_output.put_line(lv_authors(1));
      dbms_output.put_line(lv_authors(2));
      dbms_output.put_line(lv_authors(3));
    end;

    -- 创建可变类型
    create or replace type authors_ary is varray(5) of varchar2(12);

    create table bs(
      bid varchar2(4),
      authors authors_ary
    )

    insert into bs values('001',authors_ary('A','B','C'));
    insert into bs values('002',authors_ary('D','E','F'));
    insert into bs values('003',authors_ary('G','H','I'));
    insert into bs values('004',authors_ary('J','K','L'));


    -- select * from bs;

    select * from bs where bid = '001';
    select b.bid,b.authors_ary(1) from bs b where bid = '001';  --这样子是取不了的??

    --构造一个隐式的游标
    begin
      for lv_book_rec in (select * from bs)
      loop
        --dbms_output.put( ' ---- ');
        dbms_output.put_line (lv_book_rec.bid || '========');
        for lv_index in 1 .. lv_book_rec.authors.count
        loop
          dbms_output.put(lv_book_rec.authors(lv_index));        --这样子是可以取的。
        end loop;
        dbms_output.put_line ( '========');
      end loop;
    end;


    -- 可变数组的函数
    declare
    lv_authors authors_ary := authors_ary('A','B','C');
    begin
      dbms_output.put_line('Limit:' || lv_authors.limit);    --定义的数组大小
      dbms_output.put_line('Count:' || lv_authors.count);
      if lv_authors.exists(1) then
        dbms_output.put_line(lv_authors(1));
      end if;
      dbms_output.put_line(lv_authors(2));
      dbms_output.put_line(lv_authors(3));
      if lv_authors.exists(4) then
        dbms_output.put_line(lv_authors(4));
      else
        dbms_output.put_line('没有第4项');
      end if;
    end;

    Limit:5
    Count:3
    A
    B
    C
    没有第4项

    PL/SQL 过程已成功完成。

    #完善以上代码,加了大小超出报错异常及通过extend添加新项#
    declare
    lv_authors authors_ary := authors_ary('A','B','C');
    begin
      dbms_output.put_line('Limit:' || lv_authors.limit);    --定义的数组大小
      dbms_output.put_line('Count:' || lv_authors.count);
      if lv_authors.exists(1) then
        dbms_output.put_line(lv_authors(1));
      end if;
      dbms_output.put_line(lv_authors(2));
      dbms_output.put_line(lv_authors(3));
      lv_authors.extend;                            --扩充,延伸。
      lv_authors(4) := 'DDD';
      --通过extend添加新项。
      lv_authors.extend;    --lv_authors.extend(1); 与 lv_authors.extend; 等效。
          --lv_authors.extend(1,1); 第一个参数表示在4的基础上新加一个,第二个参数表示引用原来数组里面的第一个值。整体作为第5个元素。
      lv_authors(5) := 'e';
      --lv_authors.extend;
      --lv_authors(6) := 'f';
      --lv_authors(6) := 'f';                       --ORA-06533: 下标超出数量
      if lv_authors.exists(4) then
        dbms_output.put_line(lv_authors(4));
      else
        dbms_output.put_line('没有第4项');
      end if;
      if lv_authors.exists(5) then
        dbms_output.put_line(lv_authors(5));
      else
        dbms_output.put_line('没有第5项');
      end if;
    end;

    --循环可变数组的函数
    declare
    lv_authors authors_ary := authors_ary('A','B','C');
    begin
      for lv_index in 1 .. lv_authors.count
      loop
        dbms_output.put_line(lv_index);
      end loop;
    end;


    ##隐式游标##
    begin
     for lv_Title_type in (select cid, cname from class6)
     loop
      dbms_output.put_line ('========');
      --dbms_output.put_line (lv_Title_type.cid);
      --dbms_output.put_line (lv_Title_type.cname);
     end loop;
     -- 关闭游标
    end;
    ---------ORACLE6.1.txt


    Oracle集合分为两类
    -- 可变数组大小 type type_name is varray(limit) of datatype not null
    特点:固定大小,数据连续存储。
    -- 嵌套表 type table_name is table of data_type
    特点:可变大小,数据松散存储。


    declare
    type typ_authors is varray(3) of varchar2(12);    --容量大小是varray后面的值,而不是数据类型varchar2(12) 
    -- 调用构造函数初始化
    au_ary typ_authors := typ_authors();
    begin
      if au_ary is null then
        dbms_output.put_line('au_ary is null!');    --打印
      else
        dbms_output.put_line('au_ary is not null!');
      end if;

      dbms_output.put_line('Limit: ' || au_ary.limit);  --3
      dbms_output.put_line('Count: ' || au_ary.count);  --0
      au_ary.extend;
      au_ary(1) := 'A';
      au_ary.extend;
      au_ary(2) := 'B';
      dbms_output.put_line(au_ary(1));  --A
      dbms_output.put_line(au_ary(2));  --B
      -- 通过Extend添加新项
      au_ary.extend;
      au_ary(3) := 'C';
      dbms_output.put_line(au_ary(3));  --C
      dbms_output.put_line('Limit: ' || au_ary.limit);  --3
      dbms_output.put_line('Count: ' || au_ary.count);  --3
      au_ary.trim(1);  --截掉最后一个元素
      dbms_output.put_line('Limit: ' || au_ary.limit);  --3
      dbms_output.put_line('Count: ' || au_ary.count);  --2
      if au_ary.exists(3) then
        dbms_output.put_line('au_ary(3) 存在!');
      else
        dbms_output.put_line('au_ary(3) 不存在!');     --打印
      end if;
      dbms_output.put_line('1 -- > Next: ' || au_ary.Next(1)); --B  输出为2?
      dbms_output.put_line('Last: ' || au_ary.Last);           --B  输出为2?
    end;

    #通过以下实例发现:lv_authors.Next(1),lv_authors.Last返回的都是下标值。#
    declare
    lv_authors authors_ary := authors_ary('A','B','C');
    begin
      dbms_output.put_line('Limit:' || lv_authors.limit);    --定义的数组大小
      dbms_output.put_line('Count:' || lv_authors.count);
      if lv_authors.exists(1) then
        dbms_output.put_line(lv_authors(1));
      end if;
      dbms_output.put_line(lv_authors(2));
      dbms_output.put_line(lv_authors(3));
     
      dbms_output.put_line('First: ' || lv_authors.First);          
      dbms_output.put_line('First: ' || lv_authors(lv_authors.First));  
     
      --dbms_output.put_line('1 -- > Prior: ' || lv_authors.prior(1));             --ORA-06502: PL/SQL: 数字或值错误 :  NULL 索引表键值
      --dbms_output.put_line('1 -- > Prior: ' || lv_authors(lv_authors.prior(1)));
     
      dbms_output.put_line('1 -- > Prior: ' || lv_authors.prior(2));
      dbms_output.put_line('1 -- > Prior: ' || lv_authors(lv_authors.prior(2)));
     
      dbms_output.put_line('1 -- > Next: ' || lv_authors.Next(1));
      dbms_output.put_line('1 -- > Next: ' || lv_authors(lv_authors.Next(1)));
     
      dbms_output.put_line('Last: ' || lv_authors.Last);          
      dbms_output.put_line('Last: ' || lv_authors(lv_authors.Last));      
    end;

    #嵌套表#
    declare
    type student_typ_tbl is table of varchar2(12);
    stu_tbl student_typ_tbl;
    j number;
    begin
      if stu_tbl is null then
        dbms_output.put_line('stu_tbl is null!');  --打印
        stu_tbl := student_typ_tbl();              --初始化
      else
        dbms_output.put_line('stu_tbl is not null!');
      end if;
      dbms_output.put_line('Limit: ' || stu_tbl.limit); --没有值
      dbms_output.put_line('Count: ' || stu_tbl.count); --0
      for i in 1 .. 10
      loop
        stu_tbl.extend;    --附加值
        stu_tbl(i) := i;
      end loop;
      stu_tbl.delete(1);   --删除元素1
      stu_tbl.delete(4);   --删除元素4
      --for i in 1 .. 10
      --for i in 1 .. stu_tbl.count
      --for i in 1 .. stu_tbl.last
      j := stu_tbl.first;
      for i in 1 .. stu_tbl.count
      loop
        --if stu_tbl.exists(i) then
        --  dbms_output.put_line('stu_tbl(' || i || '): ' || stu_tbl(i));
        --end if;
        dbms_output.put_line('stu_tbl(' || j || '): ' || stu_tbl(j));
        j := stu_tbl.next(j);
      end loop;
      dbms_output.put_line('Limit: ' || stu_tbl.limit); --没有值
      dbms_output.put_line('Count: ' || stu_tbl.count); --8
    end;


    --索引表
    declare
    type teachers_type_tbl is table of varchar2(12) index by binary_integer;
    teacher_tbl teachers_type_tbl;
    begin
      teacher_tbl(1) := 'A';
      teacher_tbl(9) := 'B';
      dbms_output.put_line(teacher_tbl(1));
      dbms_output.put_line(teacher_tbl(9));
    end;


    ##对象命名规范和对象体##
    create or replace type rectangle is object
    (
    width number(5,2),
    height number(5,2),
    map member function area return number   --需要定义成map或者是order(编译报错?),对象间才可以比较大小。
    );

    create or replace type body rectangle is

      map member function area
      return number
      is
      begin
        return (width * height);
      end area;

    end;

    --调用
    declare
    lv_rect rectangle := rectangle(10,10);
    begin
        DBMS_OUTPUT.Put_Line( 'lv_rect.area' ); 
        DBMS_OUTPUT.Put_Line( lv_rect.area ); 
    end;

    --添加了map之后,才可以比较大小,否则会报错。
    declare
    lv_rect1 rectangle := rectangle(10, 10);
    lv_rect2 rectangle := rectangle(20, 20);
    begin
      if lv_rect1 > lv_rect2 then
        DBMS_OUTPUT.Put_Line( '1 > 2' ); 
      else
        DBMS_OUTPUT.Put_Line( '1 < 2' ); 
      end if;
    end;

    ##order方式## 注意function区别
    --类型规范
    create or replace type rectangle is object
    (
    width number(5,2),
    height number(5,2),
    order member function area(r rectangle) return int
    );
    --类型体
    create or replace type body rectangle is

      order member function area(r rectangle)
      return int
      is
      begin
        case
        when (width * height) < (r.width * r.height) then return -1;
        when (width * height) > (r.width * r.height) then return 1;
        when (width * height) = (r.width * r.height) then return 0;
        end case;
      end area;

    end;


    -- 实例          对象规范和对象体。???
    -- 堆栈(stack)

    http://hi.baidu.com/no20win/item/7a97825a4e2ef0a3acc857af 

  • 相关阅读:

    模块
    序列化模块
    time模块、os模块、sys模块
    re模块、collections模块、random模块
    正则表达式
    递归函数和二分查找
    匿名函数
    推推导式和内置函数
    Java引用类型与值类型——Java面向对象基础(7)
  • 原文地址:https://www.cnblogs.com/simpledev/p/3092937.html
Copyright © 2011-2022 走看看