1. 程式人生 > >PL/SQL developer基礎語法學習(三)之遊標

PL/SQL developer基礎語法學習(三)之遊標

一、遊標分為:隱式遊標和顯示遊標

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) :=&選擇請輸入10;
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) :=&選擇請輸入10;
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、 先建立遊標型別 再宣告遊標變數。