PL/SQL详细介绍,设置oracle相关
Posted dy9776
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PL/SQL详细介绍,设置oracle相关相关的知识,希望对你有一定的参考价值。
1. 实现参照完整性
指若两个表之间具有主从关系(即主外键关系),当删除主表数据时,必须确保相关的从表数据已经被删除.
当修改主表的主键列数据时,必须确保相关从表数据已经被修改.为了实现级联删除,可在定义外部键约束时指定ON DELETE CASCADE关键字
alter table emp add constraint fk_deptno foreign key (deptno) references dept(deptno) on delete cascade;
实现级联更新,可以使用触发器
create or replace trigger tr_update_cascade
after update of deptno on dept
for each row
begin
update emp set deptno=:new.deptno where deptno=:old.deptno;
end;
2. 维护对象类型
显示对象类型信息 执行CREATE TYPE 命令建立对象类型时,ORACLE会将对象类型的信息存放到数据字典中(USER_TYPES)
select type_name,attributes,final from user_types;
desc person_typ1
增加和删除对象类型属性
如果已经基于对象类型建立了对象类型或对象表,那么在对象类型增加或删除属性时必须要带有CASCADE关键字
alter type preson_typ1 add attribute address varchar2(50) cascade
alter type person_typ1 drop attrbute birthdate cascade;
增加和删除对象类型方法
alter type person_typ1 add member function get_info return varchar2 cascade;
create or replace type body person_typ1 as
member function get_info return varchar2 is
begin
return ‘雇员名:‘||name||‘,家庭住址:‘||address;
end;
end;
PL/SQL块中只能直接嵌入SELECT,DML(INSERT,UPDATE,DELETE)以及事务控制语句(COMMIT,ROLLBACK,SAVEPOINT),而不能直接嵌入DDL语句(CREATE,ALTER,DROP)和DCL语句(GRANT,REVOKE)
1.检索单行数据
1.1使用标量变量接受数据
v_ename emp.ename%type;
v_sal emp.sal%type;
select ename,sal into v_ename,v_sal from emp where empno=&no;
1.2使用记录变量接受数据
type emp_record_type is record(
ename emp.ename%type,sal emp.sal%type);
emp_record emp_record_type;
select ename,sal into emp_record from emp where empno=&no;
1.3嵌入SELECT语句注意事项:
使用SELECT INTO语句时,必须要返回一条数据,并且只能返回一条数据
no_date_found:
select into没有返回数据
too_many_rows:
select into返回多条数据
where子句使用注意事项:
使用的变量名不能与列名相同,否则触发TOO_MANY_ROWS例外.
2.操纵数据
2.1使用VALUES子句插入数据
v_deptno dept.deptno%type;
v_dname dept.dname%type;
v_deptno:=no;
v_dname:=‘&name‘;
insert into dept (deptno,dname) values(v_deptno,v_dname);
2.2使用子查询插入数据
v_deptno emp.deptno%type:=&no;
insert into employee select * from emp where deptno=v_deptno;
2.3更新数据
使用表达式更新列值
v_deptno dept.deptno%type:=no;
v_loc dept.loc%type:=‘&loc‘;
update dept set loc=v_loc where deptno=v_deptno;
2.4使用子查询更新列值
v_ename emp.ename%type:=‘&name‘;
update emp set (sal,comm) = (select sal,comm from emp where ename=v_ename) where job = (select job from emp where ename=v_ename)
2.5删除数据
使用变量删除数据
v_deptno dept.deptno%type:=&no;
delete from dept where deptno=v_deptno;
2.6使用子查询删除数据
v_ename emp.ename%type:=‘&name‘;
delete from emp where deptno=(select deptno from emp where ename=v_ename);
3.SQL游标
游标是指向上下文区的指针,包括隐含游标(SQL游标)和显式游标两种类型
SQL游标用于处理SELECT INTO ,INSERT,UPDATE以及DELETE语句.
显式游标用于处理多行的SELECT语句
SQL游标包括:SQL%FOUND,SQL%NOTFOUND,SQL%ROWCOUNT,SQL%ISOPEN等四种属性
3.1 SQL%ISOPEN:执行时,会隐含的打开和关闭游标.因此该属性的值永远都是FALSE
3.2 SQL%FOUND:用于确定SQL语句执行是否成功.当SQL有作用行时,为TRUE,否则为FALSE
v_deptno emp.deptno%type:=&no;
update emp set sal=sal*1.1 where deptno=v_deptno;
if sql%found then dbms_output.put_line(‘执行成功‘); else dbms_output.putline(‘失败‘); endif
3.3 sql%notfound:确定SQL语句执行是否成功,当SQL有作用行时,为false,否则为true
3.4 sql%rowcount:返回SQL语句所作用的总计行数
v_deptno emp.deptno%type:=&no;
update emp set sal=sal*1.1 where deptno=v_deptno;
dbms_output.put_line(‘修改了‘||sql%rowcount||‘行‘);
4.事务控制语句
事务控制语句包括COMMIT,ROLLBACK以及SAVEPOINT等三种语句
v_sal emp.sal%type:=&salary;
v_ename emp.ename%type:=‘&name‘;
update emp set sal=v_sal where ename=v_ename;
commit;
exception
when others then
rollback;
insert into temp values(1);
savepoint a1;
insert into temp values(2);
savepoint a2;
insert into temp values(3);
savepoint a3;
rollback to a2;
commit;
5.控制结构
条件分支语句
5.1简单条件判断
v_sal number(6,2);
select sal into v_sal from emp where lower(ename)=lowe(‘&&name‘);
if v_sal<2000 then update emp set sal=v_sal+200 where lower(ename)=lower(‘&name‘)
end if
5.2二重条件分支
v_comm number(6,2);
select comm into v_comm from emp where empno=&&no;
if v_comm<>0 then update emp set comm=v_comm+100 where empno=&no;
else update emp set comm=200 where empno=&no;
end if
5.3多重条件分支
v_job varchar2(10);
v_sal number(6,2);
select job,sal into v_job,v_sal from emp where empno=&&no;
if v_job=‘president‘ then update emp set sal=v_sal+1000 where empno=&no;
elseif v_job=‘manager‘ then update emp set sal=v_sal+500 where empno=&no;
else update emp set sal=v_sal+200 where empno=&no;
end if;
5.4 CASE语句:
在CASE语句中使用单一选择符进行等值比较
declare
v_deptno emp deptno%type;
begin
v_deptno:=&no;
case v_deptno
when 10 then update emp set comm=100 where deptno=v_deptno;
when 20 then update emp set comm=80 where deptno=v_deptno;
when 30 then update emp set comm=50 where deptno=v_deptno;
else
dbms_output.put_line("不存在‘);
end case;
end;
5.5 在CASE语句中使用多种条件比较
declare
v_sal emp.sal%type;
v_ename emp.ename%type;
begin
select ename,sal into v_ename,v_sal from emp where empno=&no;
case
when v_sal<1000 then update emp set comm=100 where ename=v_ename;
when v_sal<2000 then update emp set comm=80 where ename=v_ename;
when v_sal<6000 tehn update emp set comm=50 where ename=v_ename;
end case;
end;
5.6循环语句
有基本循环,WHILE循环,FOR循环
基本循环:一定要包含EXIT语句,定义循环控制变量
create table temp(cola int);
declare
i int:=1;
begin
loop
insert into temp values(i);
exit when i=10;
i:=i+1;
end loop;
end;
5.7 WHILE循环:定义循环控制变量,并在循环体内改变循环控制变量的值
declare
i int:=1;
begin
while i<=10 loop
insert into temp values(i);
i:=i+1;
end loop;
end;
5.8 for循环:使用FOR循环时,ORACLE会隐含定义循环控制变量.
for counter in[reverse]
lower_bound..upper_bound loop
statement1;
statement2;
.......
end loop;
5.9 counter是循环控制变量,并且该变量由ORACLE隐含定义,不需要显示定义;lower_bound和upper_bound分别对应循环控制变量的上下界值.默认情况下,FOR循环,每次会自动增一,指定REVERSE选项时,每次循环控制变量会减一
begin
for i in reverse 1..10 loop
insert into temp values(i);
end loop;
end;
5.10嵌套循环和标号:通过在嵌套循环中使用标号,可以区分内层循环和外层循环,并且可以在内层循环中直接退出外层循环
declare
result int;
begin
<<outer>>
for i in 1..100 loop
<<inter>>
for j in 1..100 loop
result:=i*j;
exit outer when result=1000;
exit when result=500;
end loop inner;
dbms_ouput.put_line(result);
end loop outer;
dbms_output.put_line(result);
end;
6.顺序控制语句
PL/SQL不仅提供了条件分支语句和循环控制语句,而且还提供了顺序控制语句GOTO和NULL.一般情况下不使用
6.1 GOTO:用于跳转到特定标号处去执行语句.
GOTO LABEL_NAME;
declare
i int :=1;
begin
loop
insert into temp values(i);
if i=10 then
goto end_loop
end if;
i:=i+1;
end loop;
<<end_loop>>
dbms_output.put_line(‘循环结束‘);
end;
6.2 null:不会执行任何操作,并且会直接将控制传递到下一条语句.
declare
v_sal emp.sal%type;
v_ename emp.ename%type;
begin
select ename,sal into v_ename,v_sal from emp where empno=&no;
if v_sal<3000 then update emp set comm=sal*0.1 where ename=v_ename;
else
null;
end if;
end;
7.复合数据类型
7.1定义PL/SQL记录
自定义PL/SQL记录:需要定义PL/SQL记录类型和记录变量,identifier用于指定记录变量名
type type_name is record(
field_declaration[,
field_declaration]...
);
identifier type_name;
declare
type emp_record_type is record(
name emp.ename%type,
salary em.sal%type,
dno emp.deptno%type);
emp_record emp_record_type;
使用%rowtype属性定义记录变量:可以基于表或视图定义记录变量
当使用%ROWTYPE属性定义记录变量时,记录成员个数,名称,类型与表或视图列的个数,名称,类型完全相同.
dept_record dept%rowtype;
emp_record emp%rowtype;
在select into 语句中使用PL/SQL 记录
在select into 语句中使用记录变量
set serveroutput on
declare
type emp_record_type is record(
name emp.ename%type,
salary em.sal%type,
dno emp.deptno%type);
emp_record emp_record_type;
begin
select ename,sal,deptno into emp_record from emp where empno=&no;
dbms_output.put_line(emp_record.name);
end;
7.2在select into 语句中使用记录成员
declare
type emp_record_type is record(
name emp.ename%type,
salary emp.sal%type,
dna emp.deptno%type);
emp_record emp_record_type;
begin
select ename,sal into emp_record.name,emp_record.salary from emp where empno=&no;
dbms_output.put_line(emp_record.name);
end;
7.3在insert语句中使用PL/SQL记录
在VALUES子句中使用记录变量
declare
dept_record dept%rowtype;
begin
dept_record.deptno:=50;
dept_record.dname:=‘administrator‘;
dept_record.loc:=‘beijing‘;
insert int dept values dept_record;
end;
在VALUES子句中使用记录成员
declare
dept_record dept%rowtype;
begin
dept_record.deptno:=60;
dept_record.dname:=‘sales‘;
insert into dept (deptno,dname) values (dept_record.deptno,dept_record.dname);
end;
7.4在UPDATE语句中使用PL/SQL记录
在SET子句中使用记录变量
declare
dept_record dept%rowtype;
begin
dept_record.deptno:=30;
dept_record.dnama:=‘sales‘;
dept_record.loc:=‘shanghai‘;
update dept set row=dept_record where deptno=30;
end;
在SET子句中使用记录成员
declare
dept_record dept%rowtype;
begin
dept_record.loc:=‘guangzhou‘;
update dept set loc=dept_record.loc where deptno=10;
end;
7.5在DELETE语句中使用PL/SQL记录:只能在DELETE语句中的WHERE子句中使用记录成员
declare
dept_record dept%rowtype;
begin
dept_record.deptno:=50;
delete from dept where deptno=dept_record.deptno;
end;
8.pl/sql集合
处理单行单列数据,可以使用标量变量,处理单行多列的数据,可以使用PL/SQL记录
处理单列多行数据,可以使用PL/SQL集合
PL/SQL集合类型类似于高级语言数组的一种复合数据类型
包括:索引表(PL/SQL表),嵌套表(NESTED TABLE),变长数组(VARRAY)三种
8.1 索引表:PL/SQL表 元素个数没有限制,并且下标可以是负值
定义索引表:
type type_name is table of element_type [not null] index by key_type;
identifier type_name;
在索引表中使用BINARY_INTEGER和PLS_INTEGER
set serveroutput on
declare
type ename_table_type is table of emp.ename%type index by binary_integer;
ename_table ename_table_type;
begin
select ename into ename_table(-1) from emp where empno=&no;
dbms_output.put_line(‘雇员名:‘||ename_table(-1));
end;
在索引表中使用VARCHAR2
set serveroutput on
declare
type area_table_type is table of number index by varchar2(10);
area_table area_table_type;
begin
area_table(‘北京‘):=1;
area_table(‘上海‘):=2;
area_table(‘广州‘):=3;
dbms_output.put_line(‘第一个元素:‘||area_table.first);
dbms_output.put_line(‘最后一个元素:‘||area_table.last);
end;
8.2 嵌套表:元素个数从1开始,并且元素个数没有限制
定义嵌套表:
type type_name is table of element_type;
identifier type_name;
declare
type ename_table_type is table of emp.ename%type;
ename_table ename_table_type:=ename_table_type(‘A‘,‘A‘);
在PL/SQL块中使用嵌套表:使用嵌套表变量时,必须首先使用构造方法初始化嵌套表变量,然后才能在块内引用嵌套表元素
declare
type ename_talbe_type is table of emp.ename%type;
ename_talbe ename_table_type;
begin
ename_table:=ename_table_type(‘mary‘,‘mary‘,‘mary‘);
select ename into ename_table(2) from emp where empno=&no;
dbms_output.put_line(‘雇员名:‘||ename_table(2));
end;
在表列中使用嵌套表:
在表列中使用嵌套表类型,必须首先使用CREATE TYPE命令建立嵌套表类型.
当使用嵌套表类型作为表列的数据类型时,必须要为嵌套表列指定专门的存储表
create type phone_type is table of varchar2(20);
/
create table employee(
id number(4),name varchar2(10),sal number(6,2),
phone phone_type
)nested table phone store as phone_table;
8.3 在PL/SQL块中为嵌套表列插入数据
当定义嵌套表类型时,ORACLE自动为该类型生成相应的构造方法.当为嵌套表列插入数据时,需要使用嵌套表的构造方法
begin
insert into employee values(1,‘scott‘,800,phone_type(‘0471-3456788‘,‘13804711111‘));
end;
在PL/SQL块中检索嵌套表列的数据
当在PL/SQL块中检索嵌套表列的数据时,需要定义嵌套表类型的变量接受其数据.
set serveroutput on
declare
phone_table phone_type;
begin
select phone into phone_table from employee where id=1;
for i in 1..phone_table.count loop
dbms_output.put_line(‘电话:‘||phone_table(i));
end loop;
end;
8.4 在pl/sql块中更新嵌套表列的数据
更新嵌套表列的数据时,首先需要定义嵌套表变量,并使用构造方法初始化变量,然后才可在执行部分使用UPDATE语句更新数据
declare
phone_table phone_type:=phone_type(‘0471-3456788‘,‘13804711111‘,‘0471-2233066‘,‘13056278568‘);
begin
update employee set phone=phone_talbe where id=1;
end;
8.5变长数组(varray)
VARRAY也是一种用于处理PL/SQL数组的数据类型, 它也可以做为表列的数据类型使用.
元素下标以1开始,并且元素的最大个数是有限制的
定义VARRAY的语法:
type type_name is varray(size_limite) of element_type [not mull];
identifier type_name;
当使用VARRAY元素时,必须要使用其构造方法初始化VARRAY元素.
declare
type ename_table_type is varrar(20) of emp.ename%type;
ename_talbe ename_table_type:=ename_table_type(‘A‘,‘A‘);
8.6 在PL/SQL块中使用VARRAY
必须首先使用其构造方法来初始化VARRAY变量,然后才能在PL/SQL块内引用VARRAY元素
declare
type ename_table_type is varray(20) of emp.ename%type;
ename_table ename_table_type:=ename_table_type(‘mary‘);
begin
select ename into ename_table(1) from emp where empno=&no;
dbms_output.put_line(‘雇员名:‘||ename_table(1));
end;
在表列中使用varray
要在表列中引用该数据类型,则必须使用CREATE TYPE命令建立VARRAY类型
create type phone_type is varray(20) of varchar2(20);
/
create table employee(
id number(4),name varchar2(10),
sal number(6,2),phone phone_type);
在PL/SQL块中操纵VARRAY列的方法与操纵嵌套表列的方法完全相同.嵌套表列元素个数没有限制,而VARRAY列的元素个数是有限制的.
PL/SQL记录表
PL/SQL变量处理单行单列数据
PL/SQL记录处理单行多列数据
PL/SQL集合处理多行单列数据
PL/SQL记录表处理多行多列数据
8.7 PL/SQL记录表结合了PL/SQL记录和PL/SQL集合的优点
declare
type emp_talbe_type is table of emp%rowtype index by binary_integer;
emp_table emp_table_type;
begin
select * into emp_table(1) from emp where empno=&no;
dbms_output.put_line(‘雇员姓名:‘||emp_table(1).ename);
dbms_output.put_line(‘雇员姓名:‘||emp_table(1).sal);
end;
8.8 多级集合
多级集合是指嵌套了集合类型的集合类型
在PL/SQL块中使用多级VARRAY:实现多维数组功能
定义二维VARRAY(10,10):
declare
type a1_varray_type is varray(10) of int;--定义一维VARRAY
type na1_varray_type is varray(10) of a1_varray_type;--定义二维VARRAY集合
--初始化二维集合变量
nv1 nal_varray_type:=nal_varray_type(
a1_varray_type(58,100,102),
a1_varray_type(55,6,73),
a1_varray_type(2,4);
begin
dbms_output.put_line(‘显示二维数组所有元素‘);
for i in 1..nv1.count loop
for j in 1..nv1(i).count loop
dbms_output.put_line(‘nvl(‘||i||‘,‘||j||‘)=‘||nvl(i)(j));
end loop;
end loop;
end;
在PL/SQL块中使用多级嵌套表
如果多维数组的元素个数没有限制,那么可以在嵌套表类型中嵌套另一个嵌套表类型
8.9 二维嵌套表
declare
type a1_table_type is table of int;--定义一维嵌套表
type nal_table_type is table of a1_table_type;--定义二维嵌套表集合
--初始化二维集合变量
nvl nal_table_type:=nal_table_type(
a1_table_type(2,4),
a1_table_type(5,73));
begin
dbms_output.put_line(‘显示二维数组所有元素‘);
for i in 1..nvl.count loop
for j in 1..nvl(i).count loop
dbms_output.put_line(‘nvl(‘||i||‘,‘||j||‘)=‘||nvl(i)(j));
end loop;
end loop;
end
在PL/SQL块中使用多级索引表
二维索引表:
declare
type a1_table_type is table of int index by binary_integer;
type nal_table_type is table of al_table_type index by binary_integer;
nvl nal_table_type;
begin
nvl(1)(1):=10;
nvl(1)(2):=5;
nvl(2)(1):=100;
nvl(2)(2):=50;
dbms_output.put_line(‘显示二维数组所有元素‘);
for i in 1..nvl.count loop
for j in 1..nvl(i).count loop
dbms_output.put_line(‘nvl(‘||i||‘,‘||j||‘)=‘||nvl(i)(j));
end loop;
end loop;
end;
8.10集合方法:ORACLE提供的用于操纵集合变量的内置函数或过程,其中EXISTS,COUNT,LIMIT,FIRST,NEXT,FRIOR和NEXT是函数
而EXTEND,TRIM和DELETE则是过程
集合方法只能在PL/SQL语句中使用,不能在SQL语句中使用.
集合方法EXTEND和TRIM只适用于嵌套表和VARRAY,而不适合于索引表
1.EXISTS:用于确定集合元素是否存在
declare
type ename_table_type is table of emp.ename%type;
ename_table ename_table_type;
begin
if ename_table.exists(1) then
ename_table(1):=‘SCOTT‘;
else
dbms_output.put_line(‘必须初始化集合元素‘);
end if;
end;
2.COUNT:用于返回当前集合变量中的元素总个数.
declare
type ename_table_type is table of emp.ename%type index by binary_integer;
ename_table ename_table_type;
begin
ename_table(-5):=‘scott‘;
ename_table(1):=‘smith‘;
ename_table(5):=‘mary‘;
ename_table(10):=‘blake‘;
dbms_output.put_line(‘集合元素总个数:‘||ename_table.count);
end;
3.LIMIT:用于返回集合元素的最大个数.因为嵌套表和索引表的余数个数没有限制,返回NULL
对于VARRAY来说,该方法返回VARRAY所允许的最大元素个数
declare
type ename_table_type is varray(20) of emp.ename%type;
ename_table ename_table_type:=ename_table_type(‘mary‘);
begin
dbms_output.put_line(‘集合元素的最大个数:‘||ename_table.limit);
end;
4.FIRST和LAST:FIRST用于返回集合变量第一个元素的下标,而LAST方法则用于返回集合变量最后一个元素的下标
declare
type ename_table_type is table of emp.ename%type index by binary_integer;
ename_table ename_table_type;
begin
ename_table(-5):=‘scott‘;
ename_table(1):=‘smith‘;
ename_table(5):=‘mary‘;
ename_table(10):=‘blake‘;
dbms_output.put_line(‘第一个元素:‘||ename_table.first);
dbms_output.put_line(‘最后一个元素:‘||ename_table.last);
end;
5.FRIOR和NEXT:PRIOR返回当前集合元素的前一个元素的下标,而NEXT方法则用于返回当前集合元素的后一个元素的下标
declare
type ename_table_type is table of emp.ename%type index by binary_integer;
ename_table ename_table_type;
begin
ename_table(-5):=‘scott‘;
ename_table(1):=‘smith‘;
ename_table(5):=‘mary‘;
ename_table(10):=‘blake‘;
dbms_output.put_line(‘元素5的前一个元素:‘||ename_table.prior(5));
dbms_output.put_line(‘元素5的后一个元素:‘||ename_table.next(5));
end;
6.EXTEND:用于扩展集合变量的尺寸,并为它们增加元素.只适用于嵌套表和VARRAY.
三种调用格式:EXTEND,EXTEND(N),EXTEND(N,I):添加N个元素,值与第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);
end;
7.TRIM:用于从集合尾部删除元素,有TRIM和TRIM(N)两种调用格式.
只适用于嵌套表和VARRAY
declare
type ename_table_type is table of varchar2(10);
ename_table ename_table_type;
begin
ename_table:=ename_table_type(‘a‘,‘a‘,‘a‘,‘a‘,‘a‘);
ename_table.trim(2);
dbms_table.put_line(‘元素个数:‘||ename_table.count);
end;
8.DELETE:删除结合元素,但该方法只适用于嵌套表和索引表,不适用于VARRAY.
有DELETE,DELETE(N),DELETE(M,N)三种调用方式.
DETELE(M,N)删除集合变量从M到N之间的所有元素
declare
type ename_table_type is table of emp.ename%type index by binary_integer;
ename_table ename_table_type;
begin
ename_table(-5):=‘scott‘;
ename_table(1):=‘smith‘;
ename_table(5):=‘mary‘;
ename_table(10):=‘blake‘;
ename_table.delete(5);
dbms_output.put_line(‘元素总个数:‘||ename_table.count);
end;
8.11集合赋值
使用嵌套表和VARRAY时,通过执行INSERT,UPDATE,FETCH,SELECT赋值语句,可以将一个集合的数据赋值给另一个集合.
当给嵌套表赋值时,还可以使用SET,MULTISET UNION,MULTISET INTERSECT,MULTISET EXCEPT等集合操作符
SET:用于取消嵌套表中的重复值.
MULTISET UNION:取得两个嵌套表的并集(DISTINCT)
MULTISET INTERSECT:用于取得两个嵌套表的交集.
NULTISET EXCEPT:用于取得两个嵌套表的差集
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_line(‘ ‘||name_array2(i));
end loop;
dbms_output.new_line;
name_array2:=name_array1;
dbms_output.put(‘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;
3.使用集合操作符给嵌套表赋值
1.使用SET操作符:用于取消特定嵌套表中的重复值.
declare
type nt_table_type is table of number;
nt_table nt_table_type:=nt_table_type(2,4,3,1,2);
result nt_table_type;
begin
result:=set(nt_table);
dbms_output.put(‘result:‘);
for i in 1..result.count loop
dbms_output.put(‘ ‘||result(i));
end loop;
dbms_output.new_line;
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;
dbms_output.put(‘result:‘);
for i in 1..result.count loop
dbms_output.put(‘ ‘||result(i));
end loop;
dbms_output.new_line;
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;
dbms_output.put(‘result:‘);
for i in 1..result.count loop
dbms_output.put(‘ ‘||result(i));
end loop;
dbms_output.new_line;
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;
dbms_output.put(‘result:‘);
for i in 1..result.count loop
dbms_output.put(‘ ‘||result(i));
end loop;
dbms_output.new_line;
end;
5.使用MULTISET EXCEPT操作符:取得两个嵌套表的差集.在NT1中存在,但在NT2中不存在
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;
dbms_output.put(‘result:‘);
for i in 1..result.count loop
dbms_output.put(‘ ‘||result(i));
end loop;
dbms_output.new_line;
end;
8.4比较集合
函数cardinality用于返回嵌套表变量的元素个数
操作符SUBMULTISET OF用于确定一个嵌套表是否为另一个嵌套表的子集
操作符MEMBER OF用于检测特定数据是否为嵌套表元素
操作符IS A SET用于检测嵌套表是否包含重复的元素值
操作符IS EMPTY用于检测嵌套表是否为NULL.
1.检测集合是否为NULL
declare
type name_table_type is table of varchar2(10);
name_table name_table_type;
begin
if name_table is empty then
dbms_output.put_line(‘name_table未初始化‘);
end if;
end;
2.比较嵌套表是否相同
使用比较符=和!=检测两个嵌套表是否相同.不能比较VARRAY和索引表
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;
3.在嵌套表上使用集合操作符
在嵌套表上使用ANSI集合操作符CARDINALITY,MEMBER OF, IS A SET.不适用于VARRAY和索引表
使用函数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;
使用操作符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;
使用操作符MEMBER OF :用于检测特定数据是否为嵌套表的元素.
declare
type nt_table_type is table of number;
nt1 nt_table_type:=nt_table_type(1,2,3,5);
v1 number:=&v1;
begin
if v1 MEMBER OF nt1 then
dbms_output.put_line(‘v1是nt1的元素‘);
end if;
end;
使用操作符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(‘嵌套表NT1无重复值‘);
end if;
end;
8.5批量绑定
当在select,insert,update,delete语句上处理批量数据时,通过批量绑定,可以极大的加快数据处理速度,提高应用程序性能
批量绑定是使用BULK COLLECT子句和FORALL语句来完成的
BULK COLLECT 子句用于取得批量数据,该子句只能用于SELECT语句,FETCH语句和DML返回子句
FORALL只适用于执行批量的DML操作
1.不使用批量绑定
declare
type id_table_type is table of number(6) index by binary_integer;
type name_table_type is table of varchar2(10) index by binary_integer;
id_table id_table_type;
name_table name_table_type;
start_time number(10);
end_time number(10);
begin
for i in 1..5000 loop
id_table(i):=i;
name_table(i);=‘name‘||to_char(i);
end loop;
start_time:=dbms_utility.get_time;
for i in 1..id_table.count loop
insert into demo values(id_table(i),name_table(i));
end loop;
end_time:=dbms_utility.get_time;
dbms_output.put_line(‘总计时间(秒):‘||to_char((end_time-start_time)/100));
end;
2.使用批量绑定
declare
type id_table_type is table of number(6) index by binary_integer;
type name_table_type is table of varchar2(10) index by binary_integer;
id_table id_table_type;
name_table name_table_type;
start_time number(10);
end_time number(10);
begin
for i in 1..5000 loop
id_table(i):=i;
name_table(i);=‘name‘||to_char(i);
end loop;
start_time:=dbms_utility.get_time;
forall i in 1..id_table.count
insert into demo values(id_table(i),name_table(i));
end_time:=dbms_utility.get_time;
dbms_output.put_line(‘总计时间(秒):‘||to_char((end_time-start_time)/100));
end;
8.6 FORALL语句
执行批量insert,update,delete操作时,使用forall语句,FORALL不是循环语句
oracle9i当使用FORALL语句时,必须具有连续的元素
oracle10g通过使用indices of和values of子句,可以使用不连续的集合元素.
forall三种执行语法:
forall index in lower_bound..upper_bound sql_statement;
forall index in indices of collection [between lower_bond.and.upper_bound] sql_statement;
forall index in values of index_collection sql_statement;
1.在insert语句上使用批量绑定
declare
type id_table_type is table of number(6) index by binary_integer;
type name_table_type is table of varchar2(10) index by binary_integer;
id_table id_table_type;
name_table name_table_type;
begin
for i in 1..10 loop
id_table(i):=i;
name_table(i):=‘name‘||to_char(i);
end loop;
forall i in 1..id_table.count
insert into demo values(id_table(i),name_table(i));
end;
2.在update语句上使用批量绑定
declare
type id_table_type is table of number(6) index by binary_integer;
type name_table_type is table of varchar2(10) index by binary_integer;
id_table id_table_type;
name_table name_table_type;
begin
for i in 1..5 loop
id_table(i):=i;
name_table(i):=‘n‘||to_char(i);
end loop;
forall i in 1..id_table.count
update demo set name=name_table(i) where id=id_table(i);
end;
3.在DELETE语句上使用批量绑定
declare
type id_table_type is table of number(6) index by binary_integer;
id_table id_table_type;
begin
for i in 1..3 loop
id_table(i):=i;
end loop;
forall i in 1..id_table.count
delete from demo where id=id_table(i);
end;
4.在FORALL语句中使用部分集合元素
declare
type id_table_type is table of number(6) index by binary_integer;
id_table id_table_type;
begin
for i in 1..10 loop
id_table(i):=11-i;
end loop;
forall i in 8..10
insert into demo (id) values (id_table(i));
end;
5.在FORALL语句上使用INDECES OF子句:用于跳过NULL集合元素
declare
type id_table_type is table of number(6);
id_table id_table_type;
begin
id_table:=id_table_type(1,null,3,null,5);
forall i in indices of id_table
delete from demo where id=id_table(i);
end;
6.在FORALL语句上使用VALUES OF子句
create table new_demo as select * from demo where 1=0
declare
type id_table_type is table of demp.id%type;
type name_table_type is table of demo.name%type;
id_table id_table_type;
name_table name_table_type;
type index_pointer_type is table of pls_integer;
index_pointer index_pointer_type;
begin
select * bulk collect into id_table,name_table from demo;
index_pointer:=index_pointer_type(6,8,10);
forall i in values of index_pointer
insert into new_demo values(id_table(i),name_table(i));
end;
7.使用SQL%BULK_ROWCOUNT属性:专门为FORALL语句提供,用于取得在执行批量绑定操作时第i个元素所作用的行数
declare
type dno_table_type is table of number(3);
dno_table dno_table_type:=dno_table_type(10,20);
begin
forall i in 1..dno_table.count
update emp set sal=sal*1.1 where deptno=dno_table(i);
dbms_output.put_line(‘第2个元素更新的行数:‘||sql%bulk_rowcount(2));
end;
8.7 BULK COLLECT子句
用于取得批量数据,只适用于select into 语句,fetch into 语句和DML返回子句
可将批量数据存放到PL/SQL集合变量中
1.在select into 语句中使用BULK COLLECT 子句:可以一次将SELECT语句的多行结果检索到集合变量中
declare
type emp_table_type is table of emp%rowtype index by binary_integer;
emp_table emp_table_type;
begin
select * bulk collect into emp_table from emp where deptno=&no;
for i in 1..emp_table.count loop
dbms_output.put_line(‘雇员姓名:‘||emp_table(i).ename);
end loop;
end;
2.在DML的返回语句中使用BULK COLLECT子句
为了取得DML操作所改变的数据,可以使用RETURNING子句.
declare
type ename_table_type is table of emp.ename%type;
ename_table ename_table_type;
begin
delete from emp where deptno=&no;
returning ename bulk collect into ename_table;
dbms_output.put(‘雇员名‘);
for i in 1..ename_table.count loop
dbms_output.put(ename_table(i)|| ‘ ‘);
end loop;
dbms_output.new_line;
end;
9.使用游标
9.1当在PL/SQL块中执行查询语句SELECT和数据操纵语句DML时,ORACLE会为其分配上下文区(CONTEXT AREA),游标指上下文区指针
对于数据操纵语句和单行SELECT INTO语句来说,ORACLE会为他们分配隐含游标.
使用显示游标处理多行数据,也可使用SELECT..BULK COLLECT INTO 语句处理多行数据.
1.显示游标
定义游标
cursor cursor_name is select_statement;
2.打开游标:执行对应的SELECT语句并将SELECT语句的结果暂时存放到结果集中.
open cursor_name;
3.提取数据
打开游标后,SELECT语句的结果被临时存放到游标结果集中,使用FETCH语句只能提取一行数据
通过使用FETCH..BULK COLLECT INTO语句每次可以提取多行数据
fetch cursor_name into variable1,varibale2,...;
fetch cursor_name bulk collect into collect1,collect2,...[limit rows];
4.关闭游标
close cursor_name;
9.2显示游标属性
用于返回显示游标的执行信息,包括%isopen,%found,%notfound,%rowcount
1.%isopen:确定游标是否打开 if cl%isopen then ... else open c1; end if;
2.%found:检查是否从结果集中提取到了数据
loop
fetch c1 into var1,var2;
if c2%found then ... else exit;
end loop;
3.%notfound
loop
fetch c1 into var1,var2;
exit when c2%notfound;
...
end loop;
4.%rowcount:返回当前行为止已经提取到的实际行数
loop
fetch c1 into my_ename,my_deptno;
if c1%rowcount>10 then
...
end if;
...
end loop;
9.3显示游标使用示例
1.在显示游标中使用fetch..into语句:只能处理一行数据,除非用循环语句
declare
cursor emp_cursor is select ename,sal from emp where deptno=10;
v_ename emp.ename%type;
v_sal emp.sal%type;
begin
open emp_cursor;
loop
fetch emp_cursor into v_ename,v_sal;
exit when emp_cursor%notfound;
dbms_output.put_line(v_ename||‘: ‘||v_sal);
end loop;
close emp_cursor;
end;
2.在显示游标中,使用FETCH..BALK COLLECT INTO语句提取所有数据
declare
cursor emp_cursor is select ename from emp where deptno=10;
type ename_table_type is table of varchar2(10);
ename_table ename_table_type;
begin
open emp_cursor;
fetch emp_cursor bulk collect into ename_table;
for i in 1..ename_table.count loop
dbms_output.put_line(ename_table(i));
end loop;
close emp_cursor;
end;
3.在显示游标中使用FETCH..BULK COLLECT INTO ..LIMIT语句提取部分数据
declare
type name_array_type is varray(5) of varchar2(10);
name_array name_array_type;
cursor emp_cursor is select ename from emp;
rows int:=5;
v_count int:=0;
begin
open emp_cursor;
loop
fetch emp_cursor bulk collect into name_array limit rows;
dbms_output.pur(‘雇员名‘);
for i in 1..(emp_currsor%rowcount-v_count) loop
dbms_output.put(name_array(i)||‘ ‘);
end loop;
dbms_output.new_line;
v_count:=emp_cursor%rowcount;
exit when emp_cursor%notfound;
end loop;
close emp_cursor;
end;
4.使用游标属性
declare
cursor emp_cursor is select ename from emp where deptno=10;
type ename_table_type is table of varchar2(10);
ename_table ename_table_type;
begin
if not emp_cursor%isopen then
open emp_cursor;
end if;
fetch emp_cursor bulk collect into ename_table;
dbms_output.put_line(‘提取的总计行数:‘||emp_cursor%rowcount);
close emp_cursor;
end;
5.基于游标定义记录变量
declare
cursor emp_cursor is select ename,sal from emp;
emp_record emp_cursor%rowtype;
begin
open emp_cursor;
loop
fetch emp_cursor into emp_record;
exit when emp_cursor%notfound;
dbms_output.put_line(‘雇员名:‘||emp_record.ename||‘,雇员工资:‘||emp_record.sal);
end loop;
end;
9.4参数游标
定义参数游标时,游标参数只能指定数据类型,而不能指定长度.
cursor cursor_name(parameter_name datatype) is select_statment;
declare
cursor emp_cursor(no number) is select ename from emp where deptno=no;
v_ename emp.ename%type;
begin
open emp_cursor(10);
loop
fetch emp_cursor into v_ename;
exit when emp_cursor%notfound;
dbms_output.put_line(v_ename);
end loop;
close emp_cursor;
end;
9.5使用游标更新或删除数据
要通过游标更新或删除数据,在定义游标时必须要带有FOR UPDATE子句
cursor cursor_name(parameter_name datetype) is select_statement for update [of column_reference] [nowait];
for update子句用于在游标结果集数据上家行共享锁,防止其他用户在相应行执行DML操作
of子句确定哪些表要加锁,没有OF子句,则在所引用的全部表上加锁
nowait子句用于指定不等待锁
必须在UPDATE后DELETE语句中引用WHERE CURRENT OF子句
update table_name set column=.. where current of cursor_name;
delete table_name where current of cursor_name;
1.使用游标更新数据
declare
cursor emp_cursor is select ename,sal from emp for update;
v_ename emp.ename%type;
v_sal emp.sal%tyep;
begin
open emp_cursor;
loop
fetch emp_cursor into v_ename,v_oldsal;
exit when emp_cursor%notfound;
if v_oldsal<2000 then
update emp set sal=sal+100 where current of emp_cursor;
end if;
end loop;
close emp_cursor;
end;
2.使用游标删除数据
declare
cursor emp_cursor is select ename,sal,deptno from emp for update;
v_ename emp.ename%type;
v_oldsal emp.sal%type;
v_deptno emp.deptno%type;
begin
open emp_cursor;
loop
fetch emp_cursor into v_ename,v_oldsal,v_deptno;
exit when emp_cursor%notfound;
if v_deptno=30 then
delete from emp where current of emp_cursor;
end if;
end loop;
close emp_cursor;
end;
3.使用OF子句在特定表上加行共享锁
declare
cursor emp_cursor is select ename,sal,dname,emp.deptno from emp,dept where emp.deptno=dept.deptno
for update of emp.deptno;
emp_record emp_cursor%type;
begin
open emp_cursor;
loop
fetch emp_cursor into emp_record;
exit when emp_cursor%notfound;
if emp_record.deptno=30 then
update emp set sal=sal+100 where current of emp_cursor;
end if;
dbms_output.put_line(‘雇员名:‘||emp_record.ename||‘,工资:‘||emp_record.sal||‘,部门名:‘||emp_record.dname);
end loop;
close emp_cursor;
end;
4.使用nowait子句
通过在FOR UPDATE子句中指定NOWAIT语句,可以避免等待锁.若已经被作用行加锁,则提示错误信息
declare
cursor emp_cursor is select ename,sal from emp for update nowait;
v_ename emp.ename%type;
v_oldsal emp.sal%type;
begin
open emp_cursor;
loop
fetch emp_cursor into v_ename,v_sal;
exit when emp_cursor%notfound;
if v_oldsal<2000 then
update emp set sal=sal+100 where current of emp_cursor;
end if;
end loop;
close emp_cursor;
end;
9.6游标FOR循环
以上是关于PL/SQL详细介绍,设置oracle相关的主要内容,如果未能解决你的问题,请参考以下文章
ORACLE PL/SQL:以最大执行时间调用外部 Oracle PL/SQL 过程