一、游标分为:隐式游标和显示游标
1.隐式游标:发生与操作的DML语句中 sql游标
例子(实例中的表都是使用的oracle中的初始表):
declare
--拷贝emp的结构+记录
v_sql varchar2(100) :='create table emp_copy2 as select * from emp where 1=1';
--更新记录
v_update_sql varchar2(100) :='update emp_copy2 set sal =sal+1000 where empno=&empno';
begin
--创建表 (存在记录的cud 就存在sql游标)
execute immediate v_sql;
dbms_output.put_line('更新了'||sql%rowcount||'条记录');
--更新记录 (隐式存在SQL游标)
execute immediate v_update_sql;
dbms_output.put_line('更新了'||sql%rowcount||'条记录');
commit;
--查看状态
if not sql%isopen then
dbms_output.put_line('隐式游标自动关闭');
end if;
--删除表
execute immediate 'drop table emp_copy2 cascade constraints';
exception
when no_data_found then
dbms_output.put_line('数据未找到'||sqlcode||'-->'||sqlerrm);
rollback;
when too_many_rows then
dbms_output.put_line('数据超出'||sqlcode||'-->'||sqlerrm);
rollback;
when others then
dbms_output.put_line('其他异常'||sqlcode||'-->'||sqlerrm);
rollback;
end;
2.显示游标:可分为静态游标和动态游标(ref游标)
(1)静态游标:可分为有参和无参
1)实例(无参)
declare
--创建并声明
cursor cur_emp is select ename,sal,dname,loc from emp_copy e join dept d on e.deptno=d.deptno where e.deptno=20;
begin
--不用打开 不用声明变量 不用抓取 不用关闭
for v_emp in cur_emp loop
dbms_output.put_line(v_emp.ename||'-->'||v_emp.sal||'-->'||v_emp.dname||'-->'||v_emp.loc);
end loop;
exception
when no_data_found then
dbms_output.put_line('数据未找到'||sqlcode||'-->'||sqlerrm);
rollback;
when too_many_rows then
dbms_output.put_line('数据超出'||sqlcode||'-->'||sqlerrm);
rollback;
when others then
dbms_output.put_line('其他异常'||sqlcode||'-->'||sqlerrm);
rollback;
end;
2)实例(有参):
declare
--创建并声明
cursor cur_emp(v_deptno dept.deptno%type) is select ename,sal,dname,loc from emp_copy e join dept d on e.deptno=d.deptno where e.deptno=v_deptno;
begin
--不用打开 不用声明变量 不用抓取 不用关闭
for v_emp in cur_emp(&部门编号) loop
dbms_output.put_line(v_emp.ename||'-->'||v_emp.sal||'-->'||v_emp.dname||'-->'||v_emp.loc);
end loop;
exception
when no_data_found then
dbms_output.put_line('数据未找到'||sqlcode||'-->'||sqlerrm);
rollback;
when too_many_rows then
dbms_output.put_line('数据超出'||sqlcode||'-->'||sqlerrm);
rollback;
when others then
dbms_output.put_line('其他异常'||sqlcode||'-->'||sqlerrm);
rollback;
end;
3)更新(操作数据)
更新(update和delete)游标 :
a)、游标声明时加入: for update
b)、操作记录指向当前行: where current of 游标
实例:
--更新游标操作
declare
--创建并声明
cursor cur_emp(v_deptno emp.deptno%type) is select * from emp_copy e where e.deptno=v_deptno for update;
begin
--不用打开 不用声明变量 不用抓取 不用关闭
for v_emp in cur_emp(&部门编号) loop
update emp_copy set sal=sal+500 where current of cur_emp;
end loop;
commit;
exception
when no_data_found then
dbms_output.put_line('数据未找到'||sqlcode||'-->'||sqlerrm);
rollback;
when too_many_rows then
dbms_output.put_line('数据超出'||sqlcode||'-->'||sqlerrm);
rollback;
when others then
dbms_output.put_line('其他异常'||sqlcode||'-->'||sqlerrm);
rollback;
end;
(2).动态游标ref:又分为强类型和弱类型
动态游标: 在使用过程中,动态关联结果集1.弱类型和强类型的区别:
弱类型: 随意关联结果集
强类型: 同一个范围内的 结果集
实例(弱类型)
declare
--1、创建游标类型
type ref_emp is ref cursor;
--2、声明变量
v_cur_emp ref_emp;
v_emp emp%rowtype;
v_dept dept%rowtype;
v_flag number(5) :=&选择请输入1或0;
begin
if v_flag=1 then
--3、打开游标 关联结果集
open v_cur_emp for select * from emp where sal>1000;
--4、操作
loop
fetch v_cur_emp into v_emp;
exit when v_cur_emp%notfound;
dbms_output.put_line(v_emp.ename);
end loop;
else
--再次使用游标
open v_cur_emp for select * from dept;
--4、操作
loop
fetch v_cur_emp into v_dept;
exit when v_cur_emp%notfound;
dbms_output.put_line(v_dept.dname);
end loop;
end if;
--5、关闭游标
close v_cur_emp;
exception
when no_data_found then
dbms_output.put_line('数据未找到'||sqlcode||'-->'||sqlerrm);
rollback;
when too_many_rows then
dbms_output.put_line('数据超出'||sqlcode||'-->'||sqlerrm);
rollback;
when others then
dbms_output.put_line('其他异常'||sqlcode||'-->'||sqlerrm);
rollback;
end;
实例(强类型)
declare
--1、创建强类型ref游标
type ref_emp is ref cursor return emp%rowtype;
--2、声明变量
v_cur_emp ref_emp;
v_emp emp%rowtype;
v_flag number(5) :=&选择请输入1或0;
begin
if v_flag=1 then
--3、打开游标 关联结果集
open v_cur_emp for select * from emp where sal>3000;
dbms_output.put_line('--------工资大于3000的员工名称----------');
else
--再次使用游标 (同类型结果集)
open v_cur_emp for select * from emp where comm is not null;
dbms_output.put_line('--------存在佣金的员工名称----------');
end if;
--4、操作
loop
fetch v_cur_emp into v_emp;
exit when v_cur_emp%notfound;
dbms_output.put_line(v_emp.ename||'-->'||v_emp.comm);
end loop;
--5、关闭游标
close v_cur_emp;
exception
when no_data_found then
dbms_output.put_line('数据未找到'||sqlcode||'-->'||sqlerrm);
rollback;
when too_many_rows then
dbms_output.put_line('数据超出'||sqlcode||'-->'||sqlerrm);
rollback;
when others then
dbms_output.put_line('其他异常'||sqlcode||'-->'||sqlerrm);
rollback;
end;
静态游标和动态游标的区别:
1、 不是创建时关联结果集,打开时关联结果集 。不能使用for
2、 先创建游标类型 再声明游标变量。