一.使用游标
1.当在PL/SQL块中执行查询语句SELECT和数据操纵语句DML时,ORACLE会为其分配上下文区(CONTEXTAREA),游标指上下文区指针
对于数据操纵语句和单行SELECTINTO语句来说,ORACLE会为他们分配隐含游标.
使用显示游标处理多行数据,也可使用SELECT..BULK COLLECT INTO语句处理多行数据.
1.显示游标
定义游标
cursorcursor_name is select_statement;
2.打开游标:执行对应的SELECT语句并将SELECT语句的结果暂时存放到结果集中.
opencursor_name;
3.提取数据
打开游标后,SELECT语句的结果被临时存放到游标结果集中,使用FETCH语句只能提取一行数据
通过使用FETCH..BULK COLLECT INTO语句每次可以提取多行数据
fetchcursor_name into variable1,varibale2,...;
fetchcursor_name bulk collect into collect1,collect2,...[limitrows];
4.关闭游标
closecursor_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;
endloop;
3.%notfound
loop
fetch c1 into var1,var2;
exit when c2%notfound;
...
endloop;
4.%rowcount:返回当前行为止已经提取到的实际行数
loop
fetch c1 into my_ename,my_deptno;
if c1%rowcount>10 then
...
end if;
...
endloop;
9.3显示游标使用示例
1.在显示游标中使用fetch..into语句:只能处理一行数据,除非用循环语句
declare
cursoremp_cursor is select ename,sal from emp where deptno=10;
v_enameemp.ename%type;
v_salemp.sal%type;
begin
openemp_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 selectename from emp where deptno=10;
typeename_table_type is table of varchar2(10);
ename_tableename_table_type;
begin
openemp_cursor;
fetchemp_cursor bulk collect into ename_table;
for i in1..ename_table.count loop
dbms_output.put_line(ename_table(i));
endloop;
closeemp_cursor;
end;
3.在显示游标中使用FETCH..BULK COLLECT INTO ..LIMIT语句提取部分数据
declare
typename_array_type is varray(5) of varchar2(10);
name_arrayname_array_type;
cursoremp_cursor is select ename from emp;
rowsint:=5;
v_countint:=0;
begin
openemp_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;
endloop;
closeemp_cursor;
end;
4.使用游标属性
declare
cursoremp_cursor is select ename from emp where deptno=10;
typeename_table_type is table ofvarchar2(10);
ename_tableename_table_type;
begin
if notemp_cursor%isopen then
open emp_cursor;
end if;
fetchemp_cursor bulk collect into ename_table;
dbms_output.put_line('提取的总计行数:'||emp_cursor%rowcount);
closeemp_cursor;
end;
5.基于游标定义记录变量
declare
cursoremp_cursor is select ename,sal from emp;
emp_recordemp_cursor%rowtype;
begin
openemp_cursor;
loop
fetch emp_cursor into emp_record;
exit when emp_cursor%notfound;
dbms_output.put_line('雇员名:'||emp_record.ename||',雇员工资:'||emp_record.sal);
endloop;
end;
9.4参数游标
定义参数游标时,游标参数只能指定数据类型,而不能指定长度.
cursorcursor_name(parameter_name datatype) is select_statment;
declare
cursoremp_cursor(no number) is select ename from emp where deptno=no;
v_enameemp.ename%type;
begin
openemp_cursor(10);
loop
fetch emp_cursor into v_ename;
exit when emp_cursor%notfound;
dbms_output.put_line(v_ename);
endloop;
closeemp_cursor;
end;
9.5使用游标更新或删除数据
要通过游标更新或删除数据,在定义游标时必须要带有FOR UPDATE子句
cursorcursor_name(parameter_name datetype) is select_statement for update[of column_reference] [nowait];
forupdate子句用于在游标结果集数据上家行共享锁,防止其他用户在相应行执行DML操作
of子句确定哪些表要加锁,没有OF子句,则在所引用的全部表上加锁
nowait子句用于指定不等待锁
必须在UPDATE后DELETE语句中引用WHERE CURRENT OF子句
update table_nameset column=.. where current of cursor_name;
delete table_namewhere current of cursor_name;
1.使用游标更新数据
declare
cursoremp_cursor is select ename,sal from emp for update;
v_enameemp.ename%type;
v_salemp.sal%tyep;
begin
openemp_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;
closeemp_cursor;
end;
2.使用游标删除数据
declare
cursoremp_cursor is select ename,sal,deptno from emp for update;
v_enameemp.ename%type;
v_oldsalemp.sal%type;
v_deptnoemp.deptno%type;
begin
openemp_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;
endloop;
closeemp_cursor;
end;
3.使用OF子句在特定表上加行共享锁
declare
cursoremp_cursor is select ename,sal,dname,emp.deptno from emp,dept whereemp.deptno=dept.deptno
for updateof emp.deptno;
emp_recordemp_cursor%type;
begin
openemp_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);
endloop;
closeemp_cursor;
end;
4.使用nowait子句
通过在FORUPDATE子句中指定NOWAIT语句,可以避免等待锁.若已经被作用行加锁,则提示错误信息
declare
cursoremp_cursor is select ename,sal from emp for update nowait;
v_enameemp.ename%type;
v_oldsalemp.sal%type;
begin
openemp_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;
endloop;
closeemp_cursor;
end;
9.6游标FOR循环
使用FOR循环时,ORACLE会隐含的打开游标,提取游标数据并关闭游标
for record_name incursor_name loop
statement1;
statement2;
...
end loop;
每循环一次提取一次数据,在提取了所有数据后,自动退出循环并隐含的关闭游标
1.使用游标FOR循环
declare
cursoremp_cursor is select ename,sal from emp;
begin
foremp_record in emp_cursor loop
dbms_output.put_line('第'||emp_curosr%rowcount||'个雇员:'||emp_record.ename);
endloop;
end;
2.在游标FOR循环中直接使用子查询
begin
foremp_record in (select ename,sal from emp) loop
dbms_output.put_line(emp_record.ename);
endloop;
end;
9.7使用游标变量
PL/SQL的游标变量中存放着指向内存地址的指针.
1.游标变量使用步骤
包括定义游标变量,打开游标,提取游标数据,关闭游标等四个阶段
1.1定义refcursor类型和游标变量
type ref_type_nameis ref cursor [return return_type];
cursor_varibaleref_type_name;
当指定RETURN子句时,其数据类型必须是记录类型,不能在包内定义游标变量
1.2打开游标
open cursor_variablefor select_statement;
1.3提取游标数据
fetchcursor_varibale into variable1,variable2,...;
fetchcursor_varibale bulk collect into collect1,collect2,...[limitrows]
1.4关闭游标变量
closecursor_varibale;
2.游标变量使用示例
2.1在定义FEFCURSOR类型时不指定RETURN子句
在打开游标时可以指定任何的SELECT语句
declare
typeemp_cursor_type is ref cursor;
emp_cursoremp_cursor_type;
emp_recordemp%rowtype;
begin
openemp_cursor for select * from emp where deptno=10;
loop
fetch emp_cursor into emp_record;
exit when emp_cursor%notfound;
dbms_output.put_line('第'||emp_curosr%rowcount||'个雇员:'||emp_record.ename);
endloop;
closeemp_cursor;
end;
2.2在定义REFCURSOR类型时指定RETURN子句
在打开游标时SELECT语句的返回结果必须与RETURN子句所指定的记录类型相匹配.
declare
typeemp_record_type is record(name varchar2(10),salarynumber(6,2));
typeemp_cursor_type is ref cursor return emp_record_type;
emp_cursoremp_cursor_type;
emp_recordemp_record_type;
begin
openemp_cursor for select ename,sal from emp where deptno=20;
loop
fetch emp_cursor into emp_record;
exit when emp_cursor%notfound;
dbms_output.put_line('第'||emp_curosr%rowcount||'个雇员:'||emp_record.ename);
endloop;
closeemp_cursor;
end;
9.7使用CURSOR表达式
CURSOR表达式用于返回嵌套游标
结果集不仅可以包含普通数据,而且允许包含嵌套游标的数据
cursor(subquery)
declare
typerefcursor is ref cursor;
cursordept_cursor(no number) is select a.dname,cursor(select ename,salfrom emp where deptno=a.deptno)
from dept awhere a.deptno=no;
empcurrefcursor;
v_dnamedept.dname%type;
v_enameemp.ename%type;
v_salemp.sal%type;
begin
opendept_cursor(&no);
loop
fetch dept_cursor into v_danme,empcur;
exit when dept_cursor%notfound;
dbms_output.put_line('部门名:'||v_dname);
loop
fetch empcur into v_ename,v_sal;
exit when empcur%notfound;
dbms_output.put_line('雇员名:'||v_ename||',工资:'||v_sal);
end loop;
endloop;
closedept_cursor;
end;