collection
相同类型元素的组合
使用唯一的下标来标识其中的每个元素
集合数据类型分类:
1.索引表(index by tables)==>关联数组(associative arrays)
2.嵌套表(nested table)
3.可变长度数组(varray:variable-size arrays) ==> 变长数组
集合名字.属性名
集合名字.方法名
1.first 取集合的第一元素的下标
2.last 最后一个
3.count 总长度
4.limit 最大值
索引表和嵌套表是不限个数的,所以返回null,
变长数组返回定义时的最大索引
5.delete([n]) 删除集合中的元素
加n表示下标,删除对应下标的值
不加删除所有
6.extend(n[,ind]):扩展集合元素
!!!无限大的集合不能扩展!!!
n表示扩展的元素个数,
ind是集合中的一个元素的下标,加上它表示扩展集合时,给扩展的元素加上值,值是ind这个下标对应的元素
7.next(下标) 取当前元素下一个元素的下标
8.prior(下标) 上一个
使用整数,可以为负
(pls_integer,binary_integer)
字符串来作为下标
下标可以不连续
元素个数无限制
只能在PLSQL中使用,不可以存储在数据库中.
定义索引表类型
type 类型名称 is table of 数据类型(是集合中值的数据类型)--单个元素的长度
index by 下标的数据类型;
(varchar2,pls_integer,binary_integer)
--type mytype is table of varchar2(200) index by pls_integer;
声名一个集合变量
变量名 类型名
--v mytype;
集合中数据的存取:
集合变量(下标)
--v(下标);
--v(下标):=值;
---------------------------------
declare
--声名一个索引表类型
type mytype is table of varchar2(20) index by binary_integer;
--声名变量 上面那个类型
a mytype;
--声名一个变量保存索引表的下标
b pls_integer;
begin
a(1):='张三';
a(-2):='李四';
a(0):='王五';
a(6):='老六';
--a.delete(); --全删
--a.delete(6); --删老六
--a.extend(100); --无限大集合不能扩展
--dbms_output.put_line(a(6));
dbms_output.put_line(a(1)); --张三
dbms_output.put_line(a.next(1)); --老六 没有就空
dbms_output.put_line(a.prior(1)); --老六 没有就空
dbms_output.put_line(a(a.first)); --李四
dbms_output.put_line(a(a.last)); --老六
dbms_output.put_line(a.count); --4
dbms_output.put_line(a.limit); --啥也没有
----------遍历集合------------------------
------loop遍历----------
--初始条件
b:=a.first; -- -2
loop
--打印集合元素
dbms_output.put_line(a(b));
--退出条件
exit when b:=a.last; --到最后一个就退出循环
b:=a.next(b); --迭代
end loop;
------while遍历----------
b:=a.first;
while b != a.last loop
dbms_output.put_line(a(b));
b:=a.next(b);
end loop;
------for遍历----------
必须是连续下标才可以
for循环自动迭代+1
for v in a.first..a.last loop;
dbms_output.put_line(a(v));
end loop
end;
declare
--声名记录类型
type recType is record(
name varchar2(30),
sex varchar2(3)
);
--声名一个索引表类型
type indType is table of recType index by pls_integer;
--声名一个变量
ind indType;
--声名一个记录类型变量
rec recType;
--声名一个记录类型变量
rec2 recType;
begin
--给记录类型赋值
rec.name:='张三';
rec.sex:='男';
--给集合中添加一个元素
ind(1):=rec;
--取集合中的值
rec2:=ind(1);---取出来的是一个记录类型数据
dbms_output.put_line(rec2.name||','||rec2.sex);
end;
使用整数(只能为正)作为下标
下标是连续的
元素个数无限制的
可以用在PLSQL中,也可以存储在数据库中
需要初始化
数据的存取和索引表相同
定义嵌套表类型
type 类型名称 is table of 数据类型(存储的数据的数据类型);
变量声名:
变量名 类型名称
!!!嵌套表在赋值之前必须初始化!!!
变量名:=集合类型名(值...);
declare
--声名一个嵌套表类型,存放字符串数据
type a is table of varchar2(20); --单个元素长度
--声名变量
b a;
c a;
--声名一个变量保存嵌套表的下标
ind pls_integer;
begin
--初始化嵌套表b
b:=a(); --空,自己扩展
dbms_output.put_line('b的长度'||tab1.count);
--初始化嵌套表tab2
c:=a('a','b','c','d');
c(1):='aa' --替换
--本来是a 现在被替换成aa
dbms_output.put_line('tab2的长度'||tab2.count);--4
--初始化只给了四个位置 需要扩展
c.extend(10); --扩展10个
--c.extend(10,1);
--扩展10个,里面的值为下标1的值
c(5):= 'e';
dbms_output.put_line(c(5)); --没扩展就报错
------遍历集合--------------------
------loop----------
i := 1;
loop
--打印集合元素
dbms_output.put_line(c(i));
--退出条件
exit when i=c.last;
i:=c.next(i);
end loop;
------while----------
while i <= c.last loop
dbms_output.put_line(c(i));
i:=c.next(i);
end loop;
------for----------
for i in c.first..c.last loop
dbms_output.put_line(c(i));
end loop;
end;
可以永久保存到数据库 ==> Types
嵌套表在数据库中的使用:
create type 类型名称 is table of 数据类型;
create type myt is table of varchar2(20);
declare
--声名一个tabType类型的嵌套表变量
a myt;
begin
--初始化
a := myt('1','2','3');
--遍历
for i in a.first..a.last loop
dbms_output.put_line(a(i));
end loop;
end;
-------------------------------------------------
建表时使用嵌套表类型 --先创建嵌套表类型再建表
create table 表名(
列名 数据类型,
...
列名 嵌套表类型
...
)nested table 嵌套表类型列名 store as 表名(是数据库中没有的表);
-------------------------
create table sb(
id number(10),
name myt
)nested table name store as aaaaaa;
insert into sb values(1,myt('张三','李四','王五')); --嵌套到表
insert into sb values(2,myt('老六','老八'));
select * from aaaaaa;--插入一个集合,小三角点开看到刚刚插入的名字
select * from table(select name from aaaaaa);
--id2的数据
select * from table(select name from aaaaaa where id =2);
删除
drop type myt;
类型在使用的时候,必须先删除表
drop table sb;
drop type myt;
使用正整数作为下标
下标是连续的
元素个数有限制的
可以用在PLSQL中,也可以存储在数据库中
初始化
type 类型名称 is varray(长度)|varying (长度)
of 元素数据类型(保存的数据的数据类型);
变量名 类型名;
使用和嵌套表一样,使用前需要初始化
变量:=类型();
变量:=类型(值,值,值,值,值);
declare
--声名一个变长数组类型
type a is varray(666) of varchar2(20);
--声名一个数组变量
arr a;
begin
--初始化
arr:=arrType('a','b','c');
dbms_output.put_line('数组的长度'||arr.count); --3
arr.extend(7); --扩展
--不能扩展超过声明(varray(666))的长度
dbms_output.put_line('数组的长度'||arr.count); --10
end;
变长数组在数据库中的使用;
create type 类型名称a is varray(长度)|varying (长度) of 数据类型;
create table 表名c(
列名 数据类型,
数组列b 数组类型a
);
insert into 表名c(列名,数组列名b) values(值,数组类型a(值,值,值));
select * from table(select 数组列b from 表名c where 条件);
可以把一组数据取出来存入一个集合类型变量中
select … into 变量
只能查出一条数据保存到变量中
++++++++++++++++++++++++++++++++
select … bulk collect into
可以查出多条数据存入一个变量中
(集合类型变量)
查询所有的名字
declare
--声名一个集合类型
type t is table of a.name%type;
--声名一个嵌套表变量
aname t;
begin
--注意:这里是不需要初始化集合变量 namelist:=tabType();
select name bulk collect into aname from a;
for i in aname.first..aname.last loop
dbms_output.put_line(aname(i));
end loop;
end;
fetch 游标 bulk collect into 集合类型变量
查询a表的信息
declare
--声名一个游标变量
cursor cur is select * from a;
--声名一个集合类型
type ty is table of a%rowtype;
--声名一个变量
aaa ty;
begin
open cur; --打开游标
fetch cur bulk collect into aaa;
close cur; --关闭游标
for i in aaa.first..aaa.last loop
dbms_output.put_line(aaa(i).name||aaa(i).aga);
end loop;
end;
批量绑定
简约版for循环
forall 变量 in 集合
sql语句; --增、删、改
-- insert update delete
根据id删除name
declare
--声名一个集合类型
type ty is table of a.id%type;
--声名一个变量
typ ty;
begin
select id bulk collect into typ from a;
forall i in typ.first..typ.last
delete from b where id=id(i);
end;
在PL/SQL程序执行时生成的 SQL 语句
编译程序对动态 SQL 不做处理,而是在程序运行时动态构造语句、对语句进行语法分析并执行
DDL 语句命令和会话控制语句不能在 PL/SQL 中直接使用,但是可以通过动态 SQL 来执行
执行动态 SQL 的语法:
execute immediate
字符串类型的命令
字符串类型的sql语句,或字符串类型的plsql代码
--'select * from a'
execute immediate 字符串参数 [into] 变量 using 参数
using 参数:传给sql语句的参数
===================================================
按照id查询信息
declare
v_a a%rowtype;
v_sql varchar2(250); --声名一个字符串类型变量
b varchar(100);
begin
execute immediate 'select * from a where id=6' into v_a;
dbms_output.put_line(v_a.name||','||v_a.job||v_a.age);
execute immediate 'select * from a where id := a' into v_a usind 6;
--a占位符 不可以特殊符号
dbms_output.put_line(v_a.name||','||v_a.job||v_a.age);--按照顺序往里传值
----------------------------------------------------------
v_sql:='select * from a where id=6';
execute immediate v_sql into v_a;
dbms_output.put_line(v_emp.ename||','||v_emp.job);
v_sql:='select * from a where id=:a' ;
b:=' and age=:b'; --注意空格
execute immediate v_sql || b into v_a using 6,18;
dbms_output.put_line(v_a.name||','||v_.job||v_a.age);
end;
-----DDL----------------------------------------
declare
begin
execute immediate 'insert into a values (:1) using 799';
execute immediate 'update a set sal=:1 where id=:2' using n,799 ;
execute immediate 'delete from a where id=:1' using 99;
execute immediate 'create table t(id number(11),name varchar2(20))';
for v in 1..10 loop
execute immediate 'insert into a values (:1) using v';
end loop;
end;
在运行程序时出现的错误叫做异常
发生异常后,语句将停止执行,控制权转移到 PL/SQL 块的异常处理部分
系统异常
预定义异常和非预定义异常。
自定义异常
declare
声明部分;
begin
plsql代码块;
exception
异常处理部分;
end;
Oracle定义了它们的错误编号和异常名字,
常见的预定义异常处理如下:
ACCESS_INTO_NULL:对应ORA-06530为了引用对象属性,必须首先初始化对象。直接引用未初始化的对象属性时,会发生异常
CASE_NOT_FOUND:对应ORA-06592,当CASE语句的WHEN子句没有包含必须条件分支或者ELSE子句时,会触发
COLLECTION_IS_NULL:对应ORA-06531,在给嵌套表变量或者varrary变量赋值之前,必须首先初始化集合
CURSOR_ALREADY_OPEN:ORA-06511,当已打开游标上执行OPEN操作时会触发
INVALID_CURSOR:ORA-01001,当视图从未打开游标,提取数据,或者关闭未打开游标时会触发
INVALID_NUMBER:ORA-01722,当内嵌SQL语句不能将字符转变成数字时会触发
LOGIN_DENIED:ORA-01017,连接Oracle数据库时,如果提供了不正解的用户名和口令时会触发
NO_DATA_FOUND:ORA-01403执行SELECT INTO 未返回行或者引用了未初始化的PL/SQL表元素时会触发
NOT_LOGGED_ON:ORA-01012没有连接数据库执行SQL时会触发
PROGRAM_ERROR:ORA-06501存在PL/SQL内部问题,在这种情况下需要重新安装数据字典视图和PL/SQL包
ROWTYPE_MISMATCH:ORA-016504当执行赋值操作时,如果宿主变量和游标变量不兼容的返回类型时,会触发
SELF_IS_NULL: ORA-30625,当使用对象类型时,如果在null实例上调用成员方法时,会触发
STORAGE_ERROR:ORA-06500当执行PL/SQL块时,如果超出内存空间或者内存被破坏,会触发
SUBSCRIPT_BEYOND_COUNT:ORA-06533当使用嵌套或者varray元素的范围进会触发
SUBSCRIPT_OUTSIDE_LIMIT:ORA-06532,使用嵌套表或者varray元素时,如果元素下标为负值时,会触发
SYS-INVALID_ROWID:ORA-01410当字符串转变为ROWID时如果使用了无效字符串,会触发
TIMEOUT_ON_RESOURCE:ORA-00051当等待资源时如果出现超时会触发
TOO_MANY_ROWS:ORA-01422当执行SELECT INTO时,如果返回超过一行、会触发
VALUE_ERROR:ORA-06502,执行赋值时,如果变量长度不足,会触发
ZERO_DIVIDE:ORA-01476如果用数字值除0,会触发
begin
exception
when 异常名称 then
异常处理代码;
...
when others then
异常处理代码;
end;
exception:出现在end前面
others其他所有的异常
------------------------------
declare
v a.name%type;
begin
select name into v from a where 1=0;
exception
when no_data_found then --NO_DATA_FOUND:ORA-01403执行SELECT INTO 未返回行或者引用了未初始化的PL/SQL表元素时会触发
dbms_output.put_line('nono');
when others then
dbms_output.put_line('就是错了'||sqlcode); --就是错了-Oracle错误编码
dbms_output.put_line('就是错了'||sqlerrm); --就是错了-Oracle错误信息
end;
SQLCODE与SQLERRM为异常处理函数。
函数SQLCODE用于取得Oracle错误号,
函数SQLERRM用于取得与错误号对应的相关错误消息
ORACLE为它定义了错误编号,但没有定义异常名字。我们使用的时候,先声名一个异常名,通过伪过程PRAGMA EXCEPTION_INIT,将异常名与错误号关联起来。
pragma exception_init(自定义的异常,编号);
declare
myexc exception; --声名异常变量
pragma exception_init(myexc,-00001); --绑定异常
begin
--delete a where id =10;
--exeception
--when myexc then
--dbms_output.put_line('nonono');
begin
insert into a(id,age) values(799,20);
--commit;
exception
when myexc then
--rollback;
dbms_output.put_line('违反唯一约束');
end;
dbms_output.put_line('-----');
end;
程序员从业务角度出发,制定的一些规则和限制。
异常名称 exception;
抛出异常:
raise 异常名称;
exception 捕获异常 处理异常
declare
myexcp exception; --定义一个自己的异常
m number(10):=&m;
n number(10):=&n;
--声名两个变量接收两个数
begin
if n=0 then
dbms_output.put_line('除数不能为零');
raise myexcp;--抛出异常 需要处理异常
end if;
dbms_output.put_line(m/n);
end;
引发应用程序错误
RAISE_APPLICATION_ERROR 过程
用于创建用户定义的错误信息
可以在可执行部分和异常处理部分使用
错误编号必须介于 –20000 和 –20999 之间
RAISE_APPLICATION_ERROR(error_number, error_message);
declare
myexc exception;
pragma exception_init(myexc,-20001);
begin
dbms_standard.raise_application_error(-20001,'我的异常');
exception
when myexc then
dbms_output.put_line('1111111111');
end;