一、遊標分爲:隱式遊標和顯示遊標
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、 先創建遊標類型 再聲明遊標變量。