PL/SQL 记录与集合

一。记录类型简介


不使用记录的PLSQL语句块

declare

v_empno NUMBER;

v_ename varchar2(20);

v_job varchar2(9);

v_mgr NUMBER;

v_hiredate DATE;

v_sal NUMBER(7,2);

v_comm NUMBER(7,2);

v_deptno NUMBER(2);

begin

select empno,ename,job,mgr,hiredate,sal,comm,deptno

into

v_empno,v_ename,v_job,v_mgr,v_hiredate,v_sal,v_comm,v_deptno

from emp where empno = :empno;

insert into emp_copy

(empno,ename,job,mgr,hiredate,sal,comm,deptno)

values

(v_empno,v_ename,v_job,v_mgr,v_hiredate,v_sal,v_comm,v_deptno);

exception

when others

then

null;

end; 


使用记录的PLSQL语句块

declare

type t_emp is record (

v_empno NUMBER;

v_ename varchar2(20);

v_job varchar2(9);

v_mgr NUMBER;

v_hiredate DATE;

v_sal NUMBER(7,2);

v_comm NUMBER(7,2);

v_deptno NUMBER(2);

);

emp_info t_emp;

begin

select * into emp_info from emp where empno=:empno;

insert into emp_copy values emp_info;

exception

when others

then

null;

end;


使用%ROWTYPE


declare

type emp_rec is record (

dept_row dept%ROWTYPE,

empno NUMBER.

ename varchar(20),

job varchar(10),

sal NUMBER(7,2)

);

emp_info emp_rec;

begin

null;

end;


初始化操作

declare

type emp_rec is record (

empname varchar(12) := '李斯特',

empno NUMBER NOT NULL DEFAULT 7369,

hiredate DATE DEFAULT SYSDATE,

sal NUMBER(7,2)

);

empinfo emp_rec;

begin

null;

end;



为记录赋值并读取记录内容

declare

type emp_rec is record(

empname varchar(12) :='李斯特',

empno NUMBER NOT NULL default 7369,

hiredate DATE default sysdate,

sal NUMBER(7,2)

);

empinfo emp_rec;

begin

empinfo.empname:='史密斯';

empinfo.empno:=7010;

empinfo.hiredate:=TO_DATE('1982-01-01','YYYY-MM-DD');

empinfo.sal:=5000;

dbms_output.put_line('员工名称:'|| empinfo.empname);

dbms_output.put_line('员工编号:'|| empinfo.empno);

dbms_output.put_line('雇佣日期:'|| TO_CHAR(empinfo.hiredate,'YYYY-MM-DD'));

dbms_output.put_line('员工薪资:'|| empinfo.sal);

end;


为记录类型附记录类型的值

declare

type emp_rec is record(

empno NUMBER,

ename varchar2(20)

);

type emp_rec_dept is record(

empno NUMBER,

ename varchar2(20)

);

emp_info1 emp_rec;

emp_info2 emp_rec;

emp_info3 emp_rec_dept;

procedure printrec(empinfo emp_rec)

as

begin

dbms_output.put_line('员工编号:'|| empinfo.empno);

dbms_output.put_line('员工名称:'|| empinfo.ename);

end;

begin

emp_info1.empno:=7890;

emp_info1.ename:='张大千';

dbms_output.put_line('emp_info1的信息如下:');

printrec(emp_info1);

emp_info2:=emp_info1;

dbms_output_put_line('emp_info2的信息如下:');

printrec(emp_info2);

end;


如果在上面添加emp_info3:=emp_info1; 则会报错

如果一个记录类型的变量赋给另一个记录类型,两个记录的类型必须完全一致



%ROWTYPE定义的记录赋给标准记录类型

declare

type dept_rec is record(

deptno NUMBER(10),

dname varchar2(30),

loc varchar2(30)

);

dept_rec_db dept%ROWTYPE;

dept_info dept_rec;

begin

select * into dept_rec_db from dept where deptno=20;

dept_info:=dept_rec_db;

end;


尽管dept_info 与 dept_rec_db 并不是相同的dept_rec类型 但是因为%ROETYPE的运行机制及dept_rec中的记录成员与dept表相同,因此赋值是成功的


如果要清空一个记录类型的变量,可以简单的为该变量赴一个空的或未初始化的记录类型,即可清空所有的记录成员值


操纵记录类型  insert数据

declare

type dept_rec is record(

deptno NUMBER(2),

dname varchar2(14),

loc varchar2(13)

);

dept_row dept%ROWTYPE;

dept_norow dept_rec;

begin

dept_row.deptno:=70;

dept_row.dname:='工程部';

dept_row.loc:='上海';

dept_norow.deptno:=80;

dept_norow.dname:='电脑部';

dept_no row.loc:='北京';

insert into dept values dept_row;

insert into dept values dept_norow;

commit;

end;


update数据

declare

type dept_rec is record(

deptno NUMBER(2),

dname VARCHAR(14),

loc varchar2(13)

);

dept_info dept_rec;

begin

select * into dept_info from dept where deptno = 80;

dept_info.dname:='信息管理部';

update dept set row = dept_info where deptno = dept_info.deptno;

end;


在returning子句中使用记录

declare

type dept_rec is record(

deptno NUMBER(2),

dname varchar2(14),

loc varchar2(13)

);

dept_info dept_rec;

dept_returning dept%ROWTYPE;

begin

select * into dept_info from dept where deptno=20;

dept_info.dname:='信息管理部';

update dept set row = dept_info where deptno = dept_info.deptno returning deptno,dname,loc into dept_returning;

dept_info.deptno:=12;

dept_info.dname:='维修部';

insert into dept values dept_info returning deptno,dname,loc into dept_returning;

delete from dept where deptno = dept_info.deptno returning deptno,dname,loc into dept_returning;

end;


1.在update语句中set子句的右边可以使用记录变量

2.在insert语句中values子句的后面,可以使用记录插入数据,values后面不需要使用括号

3.在returning语句中into子句的后面,可以将受影响的行插入到记录变量

4.记录变量是不允许出现在select列表,where子句,group by子句或order by子句中



使用嵌套记录

declare

type dept_rec is record(

deptno NUMBER(2),

dname varchar2(14),

loc varchar2(13)

);

type emp_rec is record(

v_empno NUMBER,

v_ename varchar2(20),

v_job varchar2(9),

v_mgr NUMBER(4),

v_hiredate DATE,

v_sal NUMBER(7,2),

v_comm NUMBER(7,2),

v_dept_rec dept_rec              定义嵌套的

);

emp_info emp_rec;

dept_info dept_rec;

begin

select * into dept_info from dept where deptno = (select deptno from emp where empno=7369);

emp_info.v_dept_rec:=dept_info;

select empno,ename,job,mgr,hiredate,sal,comm into emp_info.v_empno,emp_info.v_ename,emp_info.v_job,emp_info.v_mgr,emp_info.v_hiredate,emp_info.v_sal,emp_info.v_comm  from emp where empno=7369;

dbms_output.put_line('员工所属部门为:'||emp_info.v_dept_rec.dname);

end;


集合简介


集合类似于高级语言中的列表或一维数组,主要用来存储具有相同类型的元素的有序集合,每一个元素都有唯一的下标来标识当前元素在集合中的位置


在PLSQL提供3种类型的集合

1.索引表:也称为关联数组,这种类型的集合可以通过数字或字符串作为下标来查找其中的元素,类似于其他语言中的哈希表,索引表是一种仅在PLSQL中使用的数据结构

2.嵌套表:使用有序数字作为嵌套表的下标,可以容纳任意个数的元素,嵌套表与索引表最大的区别在于可以定义嵌套表类型,把嵌套表存储到数据库中,并能通过sql语句进行操作

3.变长数组:在定义时保存固定数量的元素,但可以在运行时改变其容量,变长数组与嵌套表一样,使用有序数字作为下标,也可以保存到数据库中,但是不如嵌套表灵活。


索引表只能在PLSQL中使用,如果需要在内存中保存和维护列表,则优先选择索引表

如果集合的内容还要存储到数据库中,那么可以在嵌套表和变长数组之间进行选择。

嵌套表和索引表统称为PL/SQL 表



  非连续存储

索引表    7356   3432  4234 4235   8924

  5  -4    7    13    jasd

下标可以是正数  负数  字符  元素个数不确定


索引表不需要进行初始化,没有构造方法,在为其赋值之前不需要分配初始空间,因此不需要动态地扩展其容量

索引表不仅可以使用数字作为索引下标,而且可以使用变长的字符串来索引其中的元素

当使用数字类型作为索引下标时,索引键可以为正数,负数或0,并且数字可以不连续


type type_name as table of element_type[not null] index by [PLS_INTEGER | BINARY_INTEGER | VARCHAR2(SIZE)];


雇佣日期索引表集合

type hiredate_idxt is table of date index by pls_integer;


部门编号集合

type deptno_idxt is table of dept.deotno%TYPE NOT NULL index by pls_integer;

由部门名称标识的部门记录的集合

type deptname_idxt is table of dept%ROWTYPE index by dept.dname%TYPE;

定义集合的集合

type private_collection_tt is table of deptname_idxt index by varchar2(100);


操纵索引表


declare

TYPE idx_table IS table of varchar(12)

index by PLS_INTEGER;

v_emp idx_table;

begin

v_emp(1) := 'a';

v_emo(20):='b';

v_emp(40):='c';

v_emp(-10):='d';

end;


dbms_output.put_line(v_emp(8));

访问一个未分配内存的元素,将抛出异常


由于未分配的元素会触发异常,因此可以使用exists语句检查索引表是否存在值

IF v_emp.exists(8) THEN

dbms_output.put_line(v_emp(8));

end if;


运用字符串作为索引表的下标类型,类似于高级语言中的哈希表,通过健来寻找值

declare

type idx_deptno_table is table of number(2)

index by varchar2(20);

v_deptno idx_deptno_table;

begin

v_deptno('a'):=10;

v_deptno('b'):=20;

v_deptno('c'):=30;

dbms_output.put_line('a编号为:'|| v_deptno('a'));

end;


a b c 可以是中文 例如 财务部  研究部


在使用varchar2作为索引键时,必须为varchar2指定一个大小,以便存放合适的索引键。也可以在索引表的定义中使用%TYPE或%ROWTYPE

declare

type idx_dept_table is table of dept%ROWTYPE

index by dept.dname%TYPE;

v_dept idx_dept_table;

cursor dept_cur

is

select * from dept;

begin

for deptrow in dept_cur

loop

v_dept (deptrow.dname) :=deptrow;

dbms_output.put_line(v_dept(deptrow.dname).loc);

end loop;

end; 

将游标行数据检索并赋给索引表,这相当于对dept表进行了一次复制,创建了dept表的一个副本。



定义嵌套表

嵌套表是对索引表的扩展,与索引表最大的不同在于嵌套表可以存储到oracle数据库表中,而索引表仅仅是内存表,除此之外,使用嵌套表时必须使用其构造语法对嵌套表进行初始化。嵌套表没有index by 子句,这是与索引表之间最明显的区别,因为嵌套表必须有序的关键字创建,而且关键字不能为负数。


嵌套表

3123 null 3124 7879 6783

1     2    3    4    5


元素个数不确定 下标必须是有序的 不能为负数 只能从1开始 


declare

type dept_table is table of dept%ROWTYPE; 部门信息嵌套表

type emp_name_table is table of varchar2(20);  员工名称嵌套表

type deptno_table is table of number(2);     部门编号嵌套表

dept_info dept_table; 声明嵌套表变量   声明并初始化嵌套表变量

emp_name_info emp_name_table := emp_name_table('张小','李斯特');

deptno_info   deptno_table := deptno_table(20,30,40);

begin

null;

end;


操纵嵌套表

由于在嵌套表使用之前必须进行构造,未构造的嵌套表被自动地赋初始值NULL。

嵌套表的初始化与访问


declare

type emp_name_table is table of varchar2(20);      员工名称嵌套表

type deptno_table is table of number(2);           部门编号嵌套表

deptno_info deptno_table;

emp_name_info emp_name_table:=emp_name_table('张小','李斯特');

begin

dbms_output.put_line('员工1:'||emp_name_info(1));      访问嵌套表元素

dbms_output.put_line('员工2:'||emp_name_info(2));

if deptno_info is null                     判断嵌套表是否被初始化

then

deptno_info:=deptno_table();     

end if;

deptno_info.EXTEND(5);

for i IN 1 .. 5                    扩充元素的个数

loop                               循环遍历嵌套表元素个数

deptno_info(i):= i*10;

end loop;                           显示部门个数

dbms_output.put_line('部门个数:'||deptno_info.COUNT);

end;


为了向deptno_info嵌套表中插入元素,必须首先使用嵌套表的EXTEND方法扩充指定的元素个数,然后才能通过下标进行访问。



下面介绍EXTEND具有相同的效果

IF deptno_info is null

then

deptno_info:=deptno_table(NULL,NULL,NULL,NULL,NULL);

end if;

与索引表一样,嵌套表也可以是不连续的,可以通过delete来删除嵌套表中的元素。


数据库中的嵌套表

为了让嵌套表类型能在数据表中使用,要求嵌套表类型必须保存到数据字典中,因此需要使用create type 语句创建一个持久的嵌套表类型。

create or replace type type_name

as table of element_type[NOT NULL];



在数据表中使用嵌套表示例

创建嵌套表类型

create type empname_type is table of varchar(20);

创建数据表时指定嵌套表列,同时要使用STORE AS 指定嵌套表的存储表

create table dept_nested

(

deptno number(2),

dname varchar2(20),

emplist empname_type

)NESTED TABLE emplist STORE AS empname_table;


1.使用create type定义一个嵌套表类型,在定义了类型之后,类型被保存到oracle数据字典中,以便像对待普通的列一样来使用表类型


2.在数据表定义的末尾要使用NESTED TABLE语句给嵌套表指明一个存储表的名字,用来存储嵌套表里的数据。


表中嵌套表列的内容是单独进行存放的,oracle将嵌套表列的内容存储到创建表时指定的存储表中。数据库表中的列实际上是指向对存储表的一个引用,类似于一个REF变量。



操纵嵌套表列数据


declare


       emp_list  empname_type

:= empname_type('史密斯','杰克','马丁','斯大林','布什','小平');

begin

insert into dept_nested

values(10,'国务院',emp_list);

insert into dept_nested

values(20,'财务司',empname_type('李林','张杰','马新','蔡文'));

select emplist into emp_list from dept_nested where deptno=10;

emp_list(1):='少校';

emp_list(2):='大校';

emp_list(3):='中校';

emp_list(4):='学校';

emp_list(5):='无效';

emp_list(6):='药效';

updata dept_nested

set emplist=emp_list

where deptno=10;

end;


要向数据库表中插入嵌套表列数据,有以下2种方式

(1)定义一个嵌套表变量,为嵌套表变量赋值,然后在insert语句中使用嵌套表变量插入一条记录

(2) 直接在数据表中使用嵌套表结构构造语法构造一个嵌套表实例进行插入。

不能再where子句中使用嵌套表,以及其他一些隐含需要比较的地方,比如order by,group by,distinct子句中都不能使用嵌套表。

当使用sql*plus 查询包含嵌套表列的数据表时,sql*plus 将列出嵌套表列中的内容。

select * from dept_nested;

为了正确删除类型empname_type,必须使用drop table 语句先把dept_nested删除,然后在调用drop type语句删除empname_type类型。


定义变长数组,是指数组长度可变化的数组,变长数组与C或Java数组的数据类型非常相似。

变长数组在声明时会具有一个上界值,元素插入到变长数组中时,以索引1开始,直到在变长数组中声明的最大长度。而且变长数组的元素在内存中是连续存储的,变长数组中的元素顺序相对较固定,变长数组与高级语言数组的比较。


变长数组

7345  7845 8932  2342  5364   元素个数固定

1      2    3    4     5  

下标必须为有序类型,不可以为负数,只能从1开始


定义

type projectlist is varray(50) of varchar2(16);

与嵌套表一样,变长数组在未初始化之前,其本身为null,如果访问一个未被初始化的变长数组,将触发ORA-06531这样的异常。因此必须使用构造函数进行初始化,当初始化一个变长数组时,在构造函数中传入的参数个数是变长数组实际具有的元素个数,可以使用COUNT返回当前变长数组已分配空间的元素个数,或者是使用EXTEND扩展元素的个数。


操纵变长数组

初始化示例

declare

type projectlist is varray(50) of varchar2(16);

type empno_type is varray(10) of number(4);

project_list projectlist:=projectlist('网站','ERP','CRM','CMS');

empno_list empno_type;

begin

dbms_output.put_line(project_list(3));

project_list.EXTEND;

project_list(5):='WORKFLOW';

empno_list:=empno_type(7011,7012,7013,7014,NULL,NULL,NULL,NULL,NULL,NULL);

empno_list(9):=8011;

dbms_OUTPUT.put_line(empno_list(9));

end;


数据库中的变长数组

和嵌套表一样,变长数组也可以作为数据库表的列数据被存储到数据库中,在使用前,必须先使用create type语句在数据字典中创建一个变长数组的类型。


创建并使用变长数组类型

create or replace type empname_varray_type is varray(20) of varchar2(20);

create table dept_varray

{

deptno number(2),

dname varchar2(20),

emplist empname_varray_type

};


操纵变长数组列

declare

emp_list empname_varray_type:=empname_varray_type('史密斯','杰克','汤姆','丽莎','简','史泰龙');

begin

insert into dept_varray values(20,'维修组',emp_list);

insert into dept_varray values(30,'机加工',empname_varray_type('张3','刘七','赵五','阿4','阿5','阿六'));

select emplist

into emp_list

from dept_varray

where deptno=20;

emp_list(1):='杰克张';

update dept_varray set emplist=emp_list where deptno=20;

delete from dept_varray where deptno =30;

end;

select * from dept_varray;



选择集合类型

嵌套表与索引表,这两种类型统称为PL/SQL

嵌套表自索引表扩展而来,因此嵌套表包含索引表的所有表属性

嵌套表与索引表都是使用下标对集合中的元素进行访问

嵌套表与索引表的数据类型具有相同的结构

两种表的不同点


1.嵌套表可以存储到数据库中,而索引表不能,因此如果表类型需要保存到数据库中,应该考虑使用嵌套表

2.嵌套表合法的下标范围是1~214748361,下标不能为负数;而索引表可以为负下标,范围为-2147483647~2147483647 因此如果考虑带负数的下标,应该使用索引表

3.索引表在每次调用语句块或在包初始化时在内存中自动构建,能够保存容量不固定的信息,因为它的长度是大小可变的,其值不能为NULL;而嵌套表是一种对象类型,如果不显式使用构造函数,则其值为NULL,可以使用IS NULL进行检查。

4.嵌套表可以使用其他的方法,比如EXTEND和TRIM等方法进行操作,而索引表不需要.

5.PL/SQL会自动在主机数组和索引表之间进行转换,而嵌套表不能再主机数组之间进行转换。


如果需要将集合类型保存到数据库中,可以再变长数组与嵌套表之间进行选择,这两种类型的相同之处


1.变长数组与嵌套表都使用下标符号对单个元素进行访问,在使用前都必须使用构造函数进行初始化

2.都可以存储在数据库表中,都可以应用集合方法


区别决定了是否选择此种类型

1.变长数组一旦声明,元素数目就被固定,而嵌套表没有一个明确的大小上限

2.当存储到数据库中时,变长数组保持了元素的排序和下标的值,而嵌套表则不同

因此基本的结论:如果是只需要在PL/SQL中使用的集合。且元素个数较少,则优先考虑索引表,而如果要存储到数据库中,则需要选择嵌套表。如果数据元素可以固定,则优先考虑使用变长数组。



使用集合方法

集合方法只能在PL/SQL使用 不能再sql中使用

在PL/SQL提供的集合方法中,EXISTS,COUNT,LIMIT,FIRST,LAST,PRIOR和NEXT是函数;

EXTEND,TRIM和DELETE是过程。EXISTS,PRIOR,NEXT,TRIM,EXTEND和DELETE对应的参数是集合的下标索引,通常是整数,但对于关联数组来说也可能是字符串。

只有EXISTS能用于空集合,如果在空集合上调用其他方法,会抛出异常。



使用EXISTS方法:

用于判断集合中指定的元素是否存在,如果指定的元素存在,返回true否则false。使用这个方法主要用于在访问一个未分配值的下标元素时,避免oracle弹出NO DATA FOUND 这样的错误

declare

type projectlist is varray(50) of varchar(16);

project_list projectlist := projectlist('网站','ERP','CRM','CMS');

begin

if project_list.EXISTS(5);

then

dbms_output.put_line('元素存在,其值为:'|| project_list(5));

else

dbms_output.put_line('元素不存在');

end if;

end;


输出是:元素不存在    因为没有分配第五个元素


使用COUNT方法

count方法能够返回集合中包含的元素个数,该函数在判断集合的当前元素个数时非常有用,因为集合的当前大小并不总是能够确定,特别是对于嵌套表和索引表这类大小不固定的集合。对于变长数组来说,count值与LAST方法值恒等,但对于嵌套表来说,正常情况下count值会和last值相等,但是,当我们从嵌套表中间删除一个元素时,count值就会比last值小。

在计算元素的个数时,count方法会跳过已被删除的元素

declare

type emp_name_table is table of varchar2(20);

type deptno_table is table of number(2);

deptno_info deptno_table;

emp_name_info emp_name_table := emp_name_table('张小','李斯特');

begin

deptno_info:=deptno_table();

deptno_info.EXTEND(5);

dbms_output.put_line('deptno_info的元素个数为:'||deptno_info.COUNT);

dbms_output.put_line('emp_name_info的元素个数为:'|| emp_name_info.COUNT);

end;


deptno_info的元素个数为:5

emp_name_info的元素个数为:2




使用LIMIT方法

用于返回集合元素的最大个数,对于变长数组来说,因为其元素个数固定,可以返回变长数组所允许的最大元素个数。而对于嵌套表和索引表来说,由于其元素个数没有限制,因此调用该方法将总是返回NULL。在PL/SQL 编程过程中,LIMIT 方法一般用在条件表达式中用来比较当前的最大值

declare

type projectlist is varray(50) of varchar2(16);

project_list projectlist := projectlist('网站','ERP','CRM','CMS');

begin

dbms_output.put_line('变长数组的上限值为:'|| project_list.LIMIT);

project_list.EXTEND(8);

dbms_output.put_line('变长数组的当前个数为:'||project_list.COUNT);

end;

最大长度为50个元素,构造函数中加入了4个元素,又使用EXTEND扩展了8个元素

输出:

变长数组的上限值为:50

变长数组的当前个数为:12



FIRST和LAST方法

分别返回集合第一个和最后一个元素的索引数字。而不是元素的值。如果集合为空则返回NULL。如果集合仅包含1个元素,那么将返回相同的数字。

对于索引表来说,如果是以varchar2类型作为索引表的键,那么将会基于字符串中的字符的二进制值来返回最高和最低的键值,

declare

type projectlist is varray(50) of varchar(16);

project_list projectlist:=projectlist('网站','ERP','CRM','CMS');

begin

dbms_output.put_line('peoject_list的第一个元素下标:'||project_list.FIRST);

project_list.EXTEND(8);

dbms_output.put_line('project_list的最后一个元素的下标:'||project_list.LAST);

end;

代码中构造了名为projectlist的变长数组,在声明project_list时,使用构造函数分配了4个元素,因为变长数组是从1开始的有序序列,因此FIRST返回1.因为EXTEND扩展了8个元素因此LAST返回是12个元素


输出:

project_list的第一个元素下标:1

project_list的最后一个元素的下标:12


对于变长数组来说 FIRST恒等于1,LAST恒等于COUNT。但对于嵌套表来说FIRST正常返回1,如果把第一个元素删了FIRST就会大于1,同样在中间删除一个LAST也会比COUNT大。



FRIOR和NEXT方法

返回集合中特定索引值的元素的前一个索引值,NEXT会返回集合中特定索引值参数所指向的元素的下一个索引值,如果特定的元素没有前一个或后一个索引值,那么将返回NULL。

FRIOR和NEXT 通常用来循环便利所有的元素值,这种遍历方法比通过固定的下标索引更加可靠,因为在循环过程中,有些元素可能被插入或删除。特别是索引表,因为它的下标索引可能是不连续的,有可能是(1,2,4,6,7)或(A.V.G.H.J)这样的形式

declare

type idx_table is table of varchar(12)

index by PLS_INTEGER;

v_emp idx_table;

i PLS_INTEGER;

begin

v_emp(1):='史密斯';

v_emp(20) :='克拉克';

v_emp(40):='史瑞克';

v_emp(-10):='杰瑞';

dbms_output.put_line('第-10个元素的下一个值:'||v_emp(v_emp.NEXT(-10)));

dbms_output.put_line('第40个元素的上一个值:'||v_emp(v_emp.PRIOR(40)));

i:=v_emp.FIRST;

while i is not null

loop

dbms_output.put_line('v_emp('|| i || ')=' || v_emp(i));

i:=v_emp.NEXT(i);

end loop;

end;


输出:

第-10个元素的下一个值:史密斯

第40个元素的上一个值:克拉克

v_emp(-10)=杰瑞

v_emp(1)=史密斯

v_emp(20)=克拉克

v_emp(40)=史瑞克



EXTEND方法

为嵌套表和变长数组扩展元素,不能用于索引表。有三种形式

EXTEND:在集合末端添加一个空元素

EXTEND(n):在集合末端添加n个空元素

EXTEND(n,i):把第i个元素复制n份,并添加到集合的末端。

如果一个集合未使用构造语法进行初始化,是不能使用EXTEND进行扩展的,如果嵌套表或变长数组添加了NOT NULL约束,也不能使用EXTEND的前面两种形式。

declare

type courselist is table of varchar2(10);

courses courselist;

i PLS_INTEGER;

begin

courses:=courselist('生物','物理','化学');

courses.delete(3);

courses.EXTEND;

courses(4):='英语';

courses.EXTEND(5,1);

i:=courses.FIRST;

while i is not null loop

dbms_output.put_line('courses(' || i || ')=' || courses(i));

i:=courses.NEXT(i);

end loop;

end;


输出:

courses(1)=生物

courses(2)=物理

courses(3)=英语

courses(4)=生物

courses(5)=生物

courses(6)=生物

courses(7)=生物

courses(8)=生物

courses(9)=生物


假设初始化一个长度为5的嵌套表 然后删除了第2个第5个,这时内部长度是5,COUNT返回值是3,LAST返回是4,EXTEND方法会把所有被删除的元素都一样的对待。



TRIM方法

从嵌套表或变长数组的尾部删除元素,有2种方式

TRIM:从集合末端删除一个元素

TRIM:从集合末端删除n个元素


TRIM也不会忽略被删除的元素

declare

type courseslist is table of varchar2(10);

courses courselist;

i PLS_INTEGER;

begin

courses:=courselist('生物','物理','化学','音乐','数学','地理');

courses.TRIM(2);

dbms_output.put_line('当前的元素个数:'||courses.COUNT);

courses.EXTEND;

courses(courses.COUNT):='语文';

courses.TRIM;

while i is not null loop

dbms_output.put_line('courses('|| i || ')=’ || courses(i));

i:=courses.NEXT(i);

end loop;

end;


当前的元素个数:4

courses(1)=生物

courses(2)=物理

courses(3)=化学

courses(4)=音乐



DELETE方法

用于从索引表和嵌套表中删除一个或多个元素,有3种方式

DELETE:删除集合中所有元素

DELETE(n):从以数字做主键的关联数组或者嵌套表中删除第n个元素。如果关联数组有一个字符串键,对应该键值的元素就会被删除。如果n为空,DELETE(n)不会做任何事情

DELETE(m,n):从关联数组或嵌套表中,把索引范围m到n的所有元素删除,如果m值大于n或m和n中有一个空,那么DELETE(m,n)就不做任何事情。

由于变长数组的元素个数是固定的,因此在变长数组上使用DELETE是非法的

如果DELETE方法发现被删除的元素不存在,将只是简单地忽略它,并不抛出异常

declare

type courselist is table of varchar2(10);

courses courselist;

i PLS_INTEGER;

begin

courses:=courselist('生物','物理','化学','音乐','数学','地理');

courses.DELETE(2);

dbms_output.put_line('当前的元素个数:'|| courses.COUNT);

courses.EXTEND;

dbms_output.put_line('当前的元素个数:'||courses.COUNT);

courses(courses.LAST):='语文';

courses.DELETE(4,courses.COUNT);

i:=courses.FIRST;

while i is not null loop

dbms_output.put_line('courses('|| i || ')=’ || courses(i));

i:=courses.NEXT(i);

end loop;

end;

当前的元素个数:5

当前的元素个数:6

courses(1)=生物

courses(3)=化学

courses(7)=语文



集合的异常处理

1.COLLECTION_IS_NULL:调用一个空集合的方法

2.NO_DATA_FOUNT:下标索引指向一个被删除的元素或索引表在中不存在的元素

3.SUBSCRIPT_BEYOND_COUNT:下标索引值超过集合中的元素个数

4.SUBSCRIPT_OUTSIDE_LIMIT:下标索引超过允许范围

5.VALUE_ERROR:下标索引值为空,或不能转换成正确的键类型。当键被定义在PLS_INTEGER的范围内,而下标索引值超过这个范围时,就可能抛出这个异常。



使用批量绑定

PL/SQL和SQL  频繁的交互造成性能下降。例如要删除emp表中特定部门编号的记录。代码通过循环依次向SQL引擎发送SQL语句。

如果使用批量绑定特性,将一次性向SQL引擎发送所有的sql语句,会显著提高执行的性能。批量传递集合中元素来执行,这个过程称为批量绑定。

declare

type dept_type is varray(20) of number;

depts dept_type:=dept_type(10,30,70);

begin

forall i in depts.FIRST .. depts.LAST

DELETE from emp

where deptno=depts(i);

for i IN 1 .. depts.COUNT LOOP

dbms_output.put_line('部门编号'

||depts(i)

||'的删除操作受影响的行为:'

||SQL%BULK_ROWCOUNT(i)

);

end loop;

end;


在操纵sql数据操纵语句时,sql引擎会隐式地打开一个名为SQL的游标,这个游标的标量属性%FOUND,%ISOPEN.%NOTFOUND和%ROWCOUNT,能够提供最近一次执行的sql数据操作语句信息。


由于批量绑定是一次性对多个SQL语句进行操作,因此要获取当前哪个sql语句执行后受影响的行数信息,可以使用%BULK_ROWCOUNT,该变量接收一个集合元素的索引值,


部门编号10的删除操作受影响的行为:2

部门编号30的删除操作受影响的行为:6

部门编号70的删除操作受影响的行为:0



使用BULK COLLECT

与forall 相反,BULK COLLECT关键字则可以批量地从SQL引擎中批量接收数据到一个集合,可以在select-into   fetch-into  returning-into 子句中使用BULK COLLECT

declare

type numtab is table of emp.empno%TYPE;

type nametab is table of emp.ename%TYPE;

nums numtab;

names nametab;

begin

select empno,ename BULK COLLECT into nums,names from emp;

for i in 1 .. nums.COUNT

loop

dbms_output.put_line('num('|| i || ')=' || nums(i) ||'  ');

dbms_output.put_line('names(' || i ||')=' || names(i));

end loop;

end;


num(1)=7369 names(1)=史密斯

。。。。。。。。。。。

。。。。。。。。。。。

。。。。。。。。。。。



BULK COLLECT一些限制

1.不能对字符串类型作为键的索引表使用BULK COLLECT子句

2.只能在服务器端的程序中使用BULK COLLECT,如果在客户端使用,就会产生一个不支持这种特性的错误

3.BULK COLLECT INTO 的目标对象必须是集合类型。


你可能感兴趣的:(集合,plsql,记录)