• Oracle_PL/SQL(7) 集合


    pl/sql集合
    处理单行单列数据,可以使用标量变量;
    处理单行多列的数据,可以使用pl/sql记录(%rowtype,record);
    处理单列多行数据,可以使用pl/sql集合。

    pl/sql集合类型是类似于高级语言数组的一种复合数据类型。
    包括:嵌套表(table),数组(varray)两种。

    一、嵌套表
    1.定义:
    嵌套表用于处理相同类型的多个数值,其中每个数值称为一个元素。
    元素的个数从1开始,元素个数的多少没有限制
    1.2 语法:
    type type_name is table of element_type;
    identifier type_name;
    说明:
    type_name 是用户定义类型名
    element_type 是元素类型
    identifier 是用户使用自定义类型定义的变量
    1.3 举例:
    第一个例子:1个元素的例子
    declare
    type type_varchar2 is table of varchar2(20);
    v_type type_varchar2;
    begin
    v_type:=type_varchar2('A');
    dbms_output.put_line('输出元素:'||v_type(1));
    end;
    多个元素的例子
    declare
    type type_varchar2 is table of varchar2(20);
    v_type type_varchar2;
    begin
    v_type:=type_varchar2('A','adsvad','svadfvadv');
    dbms_output.put_line('输出元素:'||v_type(2));
    end;
    总结:
    给嵌套表变量赋值时必须在嵌套表类型内添加元素,元素可以是1个或者多个。
    不能将元素直接赋值给嵌套表变量。
    嵌套表变量只有在赋值后才能被使用,通过下标来使用嵌套表变量内的元素。
    下标是元素添加到嵌套表变量内的顺序。

    二、数组(varray)
    1.定义
    数组用于处理相同类型的多个数值,其中每个数值称为一个元素。
    元素的个数从1开始,元素的最大个数是有限制的。
    2.语法:
    type type_name is varray(size_limite) of element_type [not null];
    identifier type_name;
    说明:
    type_name 是用户定义类型名
    varray() 是数组的关键字
    size_limite 是数组的长度
    element_type 是元素类型
    identifier 是用户使用自定义类型定义的变量
    数组和嵌套表的区别:
    关键字不同:table、varray
    长度限制不同:table没有长度限制、varray有长度限制
    3.举例
    declare
    type type_arr_varchar2 is varray(10) of varchar2(20);
    v_arr type_arr_varchar2;
    begin
    v_arr:=type_arr_varchar2('张三','李四');
    dbms_output.put_line('输出元素:'||v_arr(1));
    dbms_output.put_line('输出元素:'||v_arr(2));
    end;
    用查询赋值:
    declare
    type type_arr_ename is varray(20) of emp.ename%type;
    v_arr type_arr_ename:=type_arr_ename('');
    begin
    select ename into v_arr(1) from emp where empno=&no;
    dbms_output.put_line('雇员名:'||v_arr(1));
    end;
    说明:
    table和varray的功能是相同的,都可以用来存储相同类型的多个数值;
    table和varray的使用方法是相同的,都需要先定义类型,再定义变量,
    再将元素添加的变量中,最后通过下标来使用元素。
    table和varray的属性是相同的。

    三、集合属性
    集合属性是数据库提供给用户的操作集合的方法(函数和过程),
    过程包括:extend,trim,delete
    函数包括:exists,count,limit,first,last,prior,next。
    集合方法只能在pl/sql语句中使用,不能在sql语句中使用。
    1.extend:
    用于扩展集合变量的尺寸,并为它们增加元素。
    集合变量的初始化:
    通过集合类型构造函数可以给集合变量的初始化(给集合变量分配了大块的内存空间)。
    extend是在给集合变量分配的大块内存空间内给元素分配小块的内存空间。
    三种调用格式:
    extend 分配一个元素的内存空间
    extend(n) 分配n个元素的内存空间
    extend(n,i) 分配n个元素的内存空间,并且用第i个元素给这n个元素赋初始值

    第一个例子可以改写为下面的通用方式。
    declare
    type type_varchar2 is table of varchar2(20);
    v_type type_varchar2:=type_varchar2();
    begin
    v_type.extend;
    v_type(1):='A';
    dbms_output.put_line('输出元素:'||v_type(1));
    end;

    table语法改良:
    type type_name is table of element_type;
    identifier type_name:=type_name();
    varray语法改良:
    type type_name is varray(size_limite) of element_type [not null];
    identifier type_name:=type_name();

    例1:extend用于table
    declare
    type type_tab_ename is table of emp.ename%type;
    v_arr type_tab_ename:=type_tab_ename();
    v_cnt number:=1;
    begin
    for rs in (select ename from emp) loop
    v_arr.extend;
    v_arr(v_cnt):=rs.ename;
    dbms_output.put_line('雇员名:'||v_arr(v_cnt));
    v_cnt:=v_cnt+1;
    end loop;
    end;

    例2:extend(n)用于varray
    select count(1) from emp;
    declare
    type type_arr_ename is varray(16) of emp.ename%type;
    v_arr type_arr_ename:=type_arr_ename();
    v_cnt number:=1;
    begin
    v_arr.extend(16);
    for rs in (select ename from emp) loop
    v_arr(v_cnt):=rs.ename;
    dbms_output.put_line('雇员名:'||v_arr(v_cnt));
    v_cnt:=v_cnt+1;
    end loop;
    end;
    例3:extend(n,i)用于varray,且i元素必须已经存在
    declare
    type ename_table_type is varray(20) of varchar2(10);
    ename_table ename_table_type;
    begin
    ename_table:=ename_table_type('mary');
    ename_table.extend(5,1);
    dbms_output.put_line('元素个数:'||ename_table.count);
    for i in 1..ename_table.count loop
    dbms_output.put_line('元素'||i||':'||ename_table(i));
    end loop;
    end;

    2.trim:用于从集合尾部删除元素,
    有两种调用格式:
    trim :删除最后一个元素
    trim(n):删除最后n个元素
    适用于嵌套表和varray
    declare
    type ename_table_type is table of varchar2(10);
    ename_table ename_table_type;
    begin
    ename_table:=ename_table_type('a','b','c','d','e');
    ename_table.trim(2);
    dbms_output.put_line('元素个数:'||ename_table.count);
    end;

    3.delete:删除指定元素,
    有三种调用方式:
    delete 删除全部元素
    delete(n) 删除第n个元素(删除1个元素)
    delete(m,n) 删除集合变量从m到n之间的所有元素
    只适用于嵌套表,delete(n)delete(m,n)不适用于varray。
    例1:delete 删除第n个元素
    declare
    type type_tab_ename is table of emp.ename%type;
    v_arr type_tab_ename:=type_tab_ename();
    v_cnt number:=1;
    begin
    for rs in (select ename from emp) loop
    v_arr.extend;
    v_arr(v_cnt):=rs.ename;
    dbms_output.put_line('雇员名:'||v_arr(v_cnt));
    v_cnt:=v_cnt+1;
    end loop;
    dbms_output.put_line('元素个数:'||v_arr.count);
    v_arr.delete;
    dbms_output.put_line('元素个数:'||v_arr.count);
    end;
    例1-2:varray
    declare
    type type_tab_ename is varray(16) of emp.ename%type;
    v_arr type_tab_ename:=type_tab_ename();
    v_cnt number:=1;
    begin
    for rs in (select ename from emp) loop
    v_arr.extend;
    v_arr(v_cnt):=rs.ename;
    dbms_output.put_line('雇员名:'||v_arr(v_cnt));
    v_cnt:=v_cnt+1;
    end loop;
    dbms_output.put_line('元素个数:'||v_arr.count);
    v_arr.delete;
    dbms_output.put_line('元素个数:'||v_arr.count);
    end;
    例2:delete(n) 删除第n个元素
    declare
    type type_tab_ename is table of emp.ename%type;
    v_arr type_tab_ename:=type_tab_ename();
    v_cnt number:=1;
    begin
    for rs in (select ename from emp) loop
    v_arr.extend;
    v_arr(v_cnt):=rs.ename;
    dbms_output.put_line('雇员名:'||v_arr(v_cnt));
    v_cnt:=v_cnt+1;
    end loop;
    dbms_output.put_line('元素个数:'||v_arr.count);
    v_cnt:=v_arr.count;
    v_arr.delete(5);
    dbms_output.put_line('元素个数:'||v_arr.count);
    for i in 1..v_cnt loop
    if i=5 then
    continue;
    end if;
    dbms_output.put_line('元素'||i||':'||v_arr(i));
    end loop;
    end;

    例3:delete(m,n) 删除集合变量从m到n之间的所有元素
    declare
    type type_tab_ename is table of emp.ename%type;
    v_arr type_tab_ename:=type_tab_ename();
    v_cnt number:=1;
    begin
    for rs in (select ename from emp) loop
    v_arr.extend;
    v_arr(v_cnt):=rs.ename;
    dbms_output.put_line('雇员名:'||v_arr(v_cnt));
    v_cnt:=v_cnt+1;
    end loop;
    dbms_output.put_line('元素个数:'||v_arr.count);
    v_cnt:=v_arr.count;
    v_arr.delete(5,10);
    dbms_output.put_line('元素个数:'||v_arr.count);
    for i in 1..v_cnt loop
    if i>=5 and i<=10 then
    continue;
    end if;
    dbms_output.put_line('元素'||i||':'||v_arr(i));
    end loop;
    end;

    4.exists:用于确定集合元素是否存在
    declare
    type ename_table_type is table of emp.ename%type;
    ename_table ename_table_type:=ename_table_type();
    begin
    if ename_table.exists(1) then
    ename_table(1):='scott';
    dbms_output.put_line('元素:'||ename_table(1));
    else
    dbms_output.put_line('必须初始化集合元素');
    end if;
    end;

    5.count:用于返回当前集合变量中的元素总个数.

    6.limit:用于返回集合元素的最大个数.
    嵌套表元素个数没有限制,无返回值
    varray元素个数在定义时设置,返回varray所允许的最大元素个数
    declare
    type ename_table_type is varray(20) of emp.ename%type;
    ename_table ename_table_type:=ename_table_type();
    begin
    dbms_output.put_line('集合元素的最大个数:'||ename_table.limit);
    end;
    declare
    type ename_table_type is table of emp.ename%type;
    ename_table ename_table_type:=ename_table_type();
    begin
    dbms_output.put_line('集合元素的最大个数:'||ename_table.limit);
    end;

    7.first和last:
    first 用于返回集合变量第一个元素的下标,
    last 用于返回集合变量最后一个元素的下标
    declare
    type ename_table_type is varray(10) of emp.ename%type;
    ename_table ename_table_type:=ename_table_type('scott','smith','mary','blake');
    begin
    dbms_output.put_line('第一个元素的下标:'||ename_table.first);
    dbms_output.put_line('最后一个元素的下标:'||ename_table.last);
    dbms_output.put_line('第一个元素:'||ename_table(ename_table.first));
    dbms_output.put_line('最后一个元素:'||ename_table(ename_table.last));
    end;

    8.prior和next:
    prior 用于返回当前集合元素的前一个元素的下标,
    next 用于返回当前集合元素的后一个元素的下标
    declare
    type ename_table_type is varray(10) of emp.ename%type;
    ename_table ename_table_type:=ename_table_type('scott','smith','mary','blake');
    begin
    dbms_output.put_line('当前元素:'||ename_table(2));
    dbms_output.put_line('当前元素的前一个元素的下标:'||ename_table.prior(2));
    dbms_output.put_line('当前元素的后一个元素的下标:'||ename_table.next(2));
    dbms_output.put_line('当前元素的前一个元素:'||ename_table(ename_table.prior(2)));
    dbms_output.put_line('当前元素的后一个元素:'||ename_table(ename_table.next(2)));
    end;


    处理单行单列数据,可以使用标量变量(varchar2、number、date、boolean);
    处理单行多列的数据,可以使用pl/sql记录(%rowtype,record);
    处理单列多行数据,可以使用pl/sql集合(table、varray);
    那么处理多列多行数据,怎么办呢?

    四、集合类型的嵌套(联合)
    1.table和%rowtype的联合
    declare
    type type_tab_ename is table of emp%rowtype;
    v_arr type_tab_ename:=type_tab_ename();
    v_cnt number:=1;
    begin
    for rs in (select * from emp) loop
    v_arr.extend;
    v_arr(v_cnt):=rs;
    dbms_output.put_line('雇员名:'||v_arr(v_cnt).ename);
    v_cnt:=v_cnt+1;
    end loop;
    end;

    2.二维数组 varray和varray的嵌套
    declare
    type d1_varray_type is varray(10) of number;--定义一维VARRAY
    type nd1_varray_type is varray(5) of d1_varray_type;--定义二维VARRAY集合
    --初始化二维集合变量
    v_arr nd1_varray_type:=nd1_varray_type(
    d1_varray_type(2,4),
    d1_varray_type(5,73));
    begin
    dbms_output.put_line('显示二维数组所有元素');
    for i in 1..v_arr.count loop
    for j in 1..v_arr(i).count loop
    dbms_output.put_line('v_arr('||i||','||j||')='||v_arr(i)(j));
    end loop;
    end loop;
    end;

    (2,4)
    (5,73)

    如果多维集合的元素个数没有限制,那么可以在嵌套表类型中嵌套另一个嵌套表类型
    3.二维嵌套表 table和table的嵌套
    declare
    type d1_table_type is table of number;--定义一维嵌套表
    type nd1_table_type is table of d1_table_type;--定义二维嵌套表集合
    --初始化二维集合变量
    v_tab nd1_table_type:=nd1_table_type(
    d1_table_type(58,100,102),
    d1_table_type(55,6),
    d1_table_type(2));
    begin
    dbms_output.put_line('显示二维数组所有元素');
    for i in 1..v_tab.count loop
    for j in 1..v_tab(i).count loop
    dbms_output.put_line('v_tab('||i||','||j||')='||v_tab(i)(j));
    end loop;
    end loop;
    end;

    五、集合间的赋值:=
    1.赋值符:=
    将一个集合的数据赋值个另一个集合
    源集合和目标集合的数据类型必须完全一致.
    declare
    type name_varray_type is varray(4) of varchar2(10);
    name_array1 name_varray_type;
    name_array2 name_varray_type;
    begin
    name_array1:=name_varray_type('scott','smith');
    name_array2:=name_varray_type('a','a','a','a');
    dbms_output.put_line('name_array2的原数据:');
    for i in 1..name_array2.count loop
    dbms_output.put(' '||name_array2(i));
    end loop;
    dbms_output.new_line;
    name_array2:=name_array1; --用:=符号赋值
    dbms_output.put_line('name_array2的新数据:');
    for i in 1..name_array2.count loop
    dbms_output.put(' '||name_array2(i));
    end loop;
    dbms_output.new_line;
    end;

    2.给集合赋NULL值:
    清空集合变量的所有数据(集合方法DETELE,TRIM也可以)
    declare
    type name_varray_type is varray(4) of varchar2(10);
    name_array name_varray_type;
    name_empty name_varray_type;
    begin
    name_array:=name_varray_type('scott','smith');
    dbms_output.put_line('name_array的原有元素个数:'||name_array.count);
    name_array:=name_empty;
    if name_array is null then
    dbms_output.put_line('name_array的现有元素个数:0');
    end if;
    end;

    六、嵌套表特有操作:
    set:用于取消嵌套表中的重复值.
    multiset union:用于取得两个嵌套表的并集(可重)
    multiset union distinct:用于取得两个嵌套表的并集(distinct)。
    multiset intersect:用于取得两个嵌套表的交集.
    nultiset except:用于取得两个嵌套表的差集
    1.set:
    用于取消特定嵌套表中的重复值.
    declare
    type nt_table_type is table of number;
    v_tab nt_table_type:=nt_table_type(2,4,3,1,2);
    r_tab nt_table_type;
    begin
    r_tab:=set(v_tab);
    for i in 1..r_tab.count loop
    dbms_output.put_line('r_tab'||i||':'||r_tab(i));
    end loop;
    end;

    2.multiset union:
    用于获取两个嵌套表的并集。
    两个嵌套表都有的元素在结果集中会重复。
    declare
    type nt_table_type is table of number;
    nt1 nt_table_type:=nt_table_type(1,2,3);
    nt2 nt_table_type:=nt_table_type(3,4,5);
    result nt_table_type;
    begin
    result:=nt1 multiset union nt2;
    for i in 1..result.count loop
    dbms_output.put_line('result'||i||':'||result(i));
    end loop;
    end;
    3.multiset union distinct:
    用于获取两个嵌套表的并集。
    两个嵌套表都有的元素在结果集中不会重复。
    declare
    type nt_table_type is table of number;
    nt1 nt_table_type:=nt_table_type(1,2,3);
    nt2 nt_table_type:=nt_table_type(3,4,5);
    result nt_table_type;
    begin
    result:=nt1 multiset union distinct nt2;
    for i in 1..result.count loop
    dbms_output.put_line('result'||i||':'||result(i));
    end loop;
    end;
    4.multiset intersect
    用于获取两个嵌套表的交集
    declare
    type nt_table_type is table of number;
    nt1 nt_table_type:=nt_table_type(1,2,3);
    nt2 nt_table_type:=nt_table_type(3,4,5);
    result nt_table_type;
    begin
    result:=nt1 multiset intersect nt2;
    for i in 1..result.count loop
    dbms_output.put_line('result'||i||':'||result(i));
    end loop;
    end;
    5.multiset except
    用于获取两个嵌套表的差集。
    即在第一个嵌套表中存在,但在第二个嵌套表不存在的元素。
    declare
    type nt_table_type is table of number;
    nt1 nt_table_type:=nt_table_type(1,2,3);
    nt2 nt_table_type:=nt_table_type(3,4,5);
    result nt_table_type;
    begin
    result:=nt1 multiset except nt2;
    for i in 1..result.count loop
    dbms_output.put_line('result'||i||':'||result(i));
    end loop;
    end;

    操作符is empty: 用于检测嵌套表是否为null。
    操作符=和!=: 用于检测两个嵌套表是否相同。
    函数cardinality:用于返回嵌套表变量的元素个数
    submultiset of: 用于确定一个嵌套表是否为另一个嵌套表的子集
    操作符member of:用于检测特定数据是否为嵌套表元素
    操作符is a set: 用于检测嵌套表是否包含重复的元素值
    6.is empty:
    用于检测嵌套表是否为null。
    即检测嵌套表是否没有元素。
    declare
    type name_table_type is table of varchar2(10);
    name_table name_table_type:=name_table_type();
    begin
    if name_table is empty then
    dbms_output.put_line('嵌套表为空');
    else
    dbms_output.put_line('嵌套表中有元素');
    end if;
    end;
    7.=和!=
    用于检测两个嵌套表是否相同。
    declare
    type name_table_type is table of varchar2(10);
    name_table1 name_table_type;
    name_table2 name_table_type;
    begin
    name_table1:=name_table_type('scott');
    name_table2:=name_table_type('smith');
    if name_table1=name_table2 then
    dbms_output.put_line('两个嵌套表完全相同');
    else
    dbms_output.put_line('两个嵌套表数值不同');
    end if;
    end;
    8.cardinality
    用于返回嵌套表中的元素个数。
    declare
    type nt_table_type is table of number;
    nt1 nt_table_type:=nt_table_type(1,2,3,1);
    begin
    dbms_output.put_line('元素个数:'||cardinality(nt1));
    end;
    9.submultiset of
    用于确定一个嵌套表是否为另一个嵌套表的子集.
    declare
    type nt_table_type is table of number;
    nt1 nt_table_type:=nt_table_type(1,2,3);
    nt2 nt_table_type:=nt_table_type(1,2,3,4);
    begin
    if nt1 submultiset of nt2 then
    dbms_output.put_line('nt1是nt2的子集');
    end if;
    end;
    10.member of
    用于检测特定数据是否为嵌套表的元素.
    declare
    type nt_table_type is table of number;
    nt1 nt_table_type:=nt_table_type(1,2,3,4);
    v1 number:=&v1;
    begin
    if v1 member of nt1 then
    dbms_output.put_line(v1||'是嵌套表nt1的元素');
    else
    dbms_output.put_line(v1||'不是嵌套表nt1的元素');
    end if;
    end;
    11.is a set
    用于检测嵌套表是否包含重复的元素值
    declare
    type nt_table_type is table of number;
    nt1 nt_table_type:=nt_table_type(1,2,3,5);
    begin
    if nt1 is a set then
    dbms_output.put_line('嵌套表无重复值');
    else
    dbms_output.put_line('嵌套表有重复值');
    end if;
    end;


    七、作业
    1.做一个split函数,功能如下:
    输入'张三、李四、王五'
    调用函数时输出多行,显示如下:
    create or replace type type_table_varchar2 is table of varchar2(20);
    create or replace function split(p_var varchar2,p_fengefu varchar2) return type_table_varchar2
    is
    v_rs type_table_varchar2:=type_table_varchar2();
    begin
    XXXX
    return v_rs;
    end;

    select column_value from table(split('张三、李四、王五','、'));
    张三
    李四
    王五
    2.做一个匿名块,对数组进行排序,并显示排序后的元素。比如:
    排序前数组元素顺序为:13 25 7 18 2 6 9 12
    排序后数组元素顺序为:2 6 7 9 12 13 18 25

  • 相关阅读:
    [FAQ] jsoneditor 如何切换 mode 或者选择 modes
    IDA动态调试快捷键
    [FAQ] PHP Warning: json_encode(): double INF does not conform to the JSON spec
    Git 工具下载慢问题 & 图像化界面工具
    Windows 查看端口是被什么程序占用
    什么是 objdump 命令
    什么是 IDA 工具
    什么是 ELF 文件(文件格式)
    ARM 反汇编速成
    [Mobi] Android Studio NDK 安装
  • 原文地址:https://www.cnblogs.com/BradMiller/p/9279605.html
Copyright © 2020-2023  润新知