PL/SQL developer基礎語法學習(三)之遊標
阿新 • • 發佈:2019-02-05
一、遊標分為:隱式遊標和顯示遊標
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、 先建立遊標型別 再宣告遊標變數。