Oracle 原理:遊標,顯示遊標、隱式遊標、參照遊標

Oracle 遊標有三種:顯示遊標、隱式遊標、參照遊標。

fetch...bulk collect into

 

select 語句會把結果集全部返回給用戶,而無法對結果集中的每行數據進行單獨的操作。因此遊標可以解決此問題。

隱式遊標是在執行DML SQL語句時,Oracle自動創建的,名字固定叫sql

顯示遊標由用戶自行創建

REF遊標:REF遊標用於處理運行時才能確定的動態SQL查詢的結果

一、隱式遊標

隱式遊標包含的屬性有:

%FOUND  :SQL語句影響了一行或者多行時爲ture

%NOTFOUND :SQL語句沒有影響任何行時爲ture

%ROWCOUNT :SQL語句影響的行數

%ISOPEN : 遊標是否打開

 

新建表:

declare
 sql_command varchar2(500);
 isExsit number ;
begin
  select count(1) into isExsit from user_tables where table_name ='SALARY_TBL'; 
  if isExsit <> 0  then 
    sql_command :='truncate table salary_tbl';
    execute immediate sql_command;
    sql_command :='drop table salary_tbl';
    execute immediate sql_command;
  end if;  
  sql_command := '  
create  table salary_tbl(
   employer_nm varchar(20) ,
   department varchar(20) not null,
   salary number not null,
   leader_nm varchar(20)
)';
 execute immediate sql_command;
 for i in  1..13000
     loop
     insert into salary_tbl values('僱傭者'||i,'部門'||Mod(i,50),100+sqrt(i),'僱傭者'||Mod(i,20)); 
     if Mod(i,1000)=0 then 
       commit;
     end if;
   end loop;
 commit;
end; 
/

 

--隱式遊標示例
begin
  update   salary_tbl set DEPARTMENT ='部門3' where DEPARTMENT ='部門3';
  if sql%found then
    dbms_output.put_line('修改了'||sql%ROWCOUNT||'行');
  end if;
  rollback;
end;
/

 

二、顯示遊標

首先需要定義遊標,然後打開遊標,此時遊標就指向了某個結果集。此時一行一行地讀取,讀完之後再關閉遊標。

cursor curname (參數集) is SQLstatement;

----把領導者的薪資變成99999----
declare
 sal  salary_tbl.employer_nm%type;
 cursor mycur is select distinct LEADER_NM from salary_tbl ;
begin
  open mycur;
  fetch mycur into sal;
  while mycur%found loop
    update salary_tbl set salary=99999 where employer_nm = sal;
    fetch mycur into sal;
  end loop;
  close mycur;
end;
/

傳參的顯示遊標示例:


----把除了部門9的領導者的薪資變成8888----
declare
 sal  salary_tbl.employer_nm%type;
 cursor mycur(depnum number) is select distinct LEADER_NM from salary_tbl where 
                     employer_nm in (select distinct LEADER_NM from salary_tbl)and department <>'部門'||depnum;
begin
  open mycur(9);
  fetch mycur into sal;
  while mycur%found loop
    update salary_tbl set salary=8888 where employer_nm = sal;
    fetch mycur into sal;
  end loop;
  close mycur;
end;
/

上面都是利用遊標來查詢,遊標還可以用來更新刪除操作。

cursor curname (參數集) is SQLstatement for update;

current of curname

 


----把除了部門8的領導者薪資變成7777----
declare
 sal  salary_tbl%rowtype;
 cursor mycur(depnum number) is select * from salary_tbl where 
                     employer_nm in (select distinct LEADER_NM from salary_tbl)and department <>'部門'||depnum for update;
begin
  open mycur(8);
  fetch mycur into sal;
  while mycur%found loop
    update salary_tbl set salary=7777 where current of mycur;
    fetch mycur into sal;
  end loop;
  close mycur;
end;
/

循環遊標只能用於查詢但是大大簡化代碼:

----把除了部門7的領導者薪資變成6666----
declare
 sal  salary_tbl%rowtype;
 cursor mycur(depnum number) is select * from salary_tbl where 
                     employer_nm in (select distinct LEADER_NM from salary_tbl)and department <>'部門'||depnum for update;
begin
  for c1  in mycur(7) loop
   update salary_tbl set salary=6666 where current of mycur;
  end loop;
end;
/

練習:利用遊標來初始化表,新建部門表(部門號,員工總薪資,領導人員)

declare
 sql_command varchar2(500);
 isExsit number ;
 cursor dep_cur is select department,sum(salary) as allsalary from salary_tbl group by department;
 depdata dep_cur%rowtype;
begin
  select count(1) into isExsit from user_tables where table_name ='DEPARTMENT_TBL'; 
  if isExsit <> 0  then 
    sql_command :='truncate table DEPARTMENT_TBL';
    execute immediate sql_command;
    sql_command :='drop table DEPARTMENT_TBL';
    execute immediate sql_command;
  end if;  
  sql_command := '  
create  table DEPARTMENT_TBL(
   department varchar(20) not null,
   all_salary number not null,
   leaders    varchar(100)
)';
 execute immediate sql_command;
 open dep_cur;
 fetch dep_cur into depdata;
 while dep_cur%found loop 
   insert into DEPARTMENT_TBL(department,all_salary) values(depdata.department,depdata.allsalary);
   fetch dep_cur into depdata;

   commit;
 end loop;
 close dep_cur;
end; 
/

三、參照遊標

當無法直接確定遊標的定義時可以使用參考遊標;

定義:TYPE  typename  IS REF CURSOR;
typename refcursorname;

賦值: OPEN refcursorname   FOR   sqlstatement;

例如:初始化 DEPARTMENT_TBL.leaders    獲取部門下的所有領導者.;

---初始化部門中的leader----
declare
cursor cur is select distinct department from salary_tbl ;   --所有的部門
leadernm DEPARTMENT_TBL.LEADERS%type;            --某個部門下的所有領導者,待賦值
type refcursor is ref cursor;       
refcur refcursor;                                --參照遊標
refdata salary_tbl.leader_nm%type;               --某個部門下的某個領導者,待賦值
begin 
  for curdata in cur loop
    --遍歷部門集cur,確定部門curdata下的所有領導者集合
    open refcur for select distinct leader_nm from salary_tbl where department=curdata.department;
    leadernm :='';
    fetch refcur into refdata;
    while refcur%found loop
      --遍歷領導者集合,字符串拼接
      if leadernm is null  then 
       leadernm := leadernm ||refdata;
      else
        leadernm := leadernm ||','||refdata; 
      end if;
      fetch refcur into refdata;
    end loop; ---/refcur 
  dbms_output.put_line(curdata.department || '    '||leadernm);
  update DEPARTMENT_TBL set LEADERS=leadernm where department=curdata.department;
  end loop;  --/cur
  --commit;
 close refcur;
end;
/



新表的結果如圖:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章