數據庫之【遊標使用詳解篇】

*****************************

數據庫之遊標使用詳解篇

*****************************

遊標(Cursor):用來查詢數據庫,獲取記錄集合(結果集)的指針,可以讓開發者一次訪問一行結果集,

                                在每條結果集上作操作。
遊標類型:隱式遊標,顯示遊標,REF遊標。
                 其中,隱式遊標和顯示遊標屬於靜態遊標(運行前將遊標與SQL語句關聯),
                 REF遊標屬於動態遊標(運行時將遊標與SQL語句關聯)。
隱式遊標:DML語句對應的遊標,由Oracle自動管理,也稱SQL遊標。

遊標變量的功能強大,可以簡化數據處理

遊標變量的優點有:
1.可從不同的 SELECT 語句中提取結果集
2.可以作爲過程的參數進行傳遞
3.可以引用遊標的所有屬性
4.可以進行賦值運算

使用遊標變量的限制:
1.不能在程序包中聲明遊標變量
2.FOR UPDATE子句不能與遊標變量一起使用
3.不能使用比較運算符

顯式和隱式遊標的區別:
儘量使用隱式遊標,避免編寫附加的遊標控制代碼(聲明,打開,獲取,關閉),

也不需要聲明變量來保存從遊標中獲取的數據。


--1.靜態遊標(隱式遊標和顯示遊標)
--1.1隱式遊標
--隱式遊標的屬性
%FOUND    --有記錄爲真
%NOTFOUND --沒記錄時爲真
%ROWCOUNT --引響到表裏記錄的行數
%ISOPEN   --遊標的狀態(OPEN,CLOSE)
SQL       --所有隱式遊標的名稱
--隱式遊標屬性%FOUND的用法
BEGIN
  UPDATE emp SET sal = 2000 WHERE empno = '7369';
  IF SQL%FOUND THEN
    --SQL%NOTFOUND
    DBMS_OUTPUT.PUT_LINE('表已更新');
  END IF;
END;
/

--未找到數據異常NO_DATA_FOUND
DECLARE
  empid VARCHAR2(10);
  desig VARCHAR2(10);
BEGIN
  empid := '&Employeeid';
  SELECT ename INTO desig FROM emp WHERE empno = empid;
EXCEPTION
  WHEN NO_DATA_FOUND THEN
    DBMS_OUTPUT.PUT_LINE('職員未找到');
END;
--隱式遊標屬性SQL%ROWCOUNT用法
BEGIN
  UPDATE vendor_master SET venname = 'Rob Mathew' WHERE vencode = 'V004';
  DBMS_OUTPUT.PUT_LINE(SQL%ROWCOUNT);
END;
/
--select into 時錯誤TOO_MANY_ROWS
DECLARE
  empid VARCHAR2(10);
BEGIN
  SELECT empno INTO empid FROM emp;
EXCEPTION
  WHEN TOO_MANY_ROWS THEN
    DBMS_OUTPUT.PUT_LINE('該查詢提取多行');
END;
/

--1.2.顯示遊標
顯示遊標操作:
(1)聲明遊標(關聯SQL語句) cursor+遊標名 is/as sql語句
(2)打開遊標(執行SQL語句,填充遊標) open+遊標名
(3)提取遊標的行 fetch 遊標名 into 行類型變量
(4)關閉遊標 close+遊標名

declare
  --定義存儲遊標變量
  rowresult emp%rowtype;
  --定義遊標
  cursor cur is
    select * from emp where sal > 2000;
begin
  open cur; --打開
  loop      --循環
    fetch cur
      into rowresult;       --提取
    exit when cur%notfound; --退出
    dbms_output.put_line('員工姓名:' || rowresult.ename); --從遊標變量中取某個字段值
  end loop;
  close cur; --關閉
end;

--帶參數的顯示遊標
declare
  rowresult emp%rowtype;
  cursor cur(eno number) is
    select * from emp where empno = eno;
begin
  open cur(&empno);
  loop
    fetch cur
      into rowresult;
    exit when cur%notfound;
    dbms_output.put_line('用戶名是:' || rowresult.ename);
  end loop;
  close cur;
end;

--使用顯示遊標更新記錄
declare
  new_sal number;
  cursor cur is
    select sal from emp where sal < 3000 for update of sal;
begin
  open cur;
  loop
    fetch cur
      into new_sal;
    exit when cur%notfound;
    update emp set sal = 1.1 * new_sal where current of cur;
    dbms_output.put_line('記錄已經更新' || 1.1 * new_sal);
  end loop;
  close cur;
end;

--循環遊標
declare
  cursor cur is
    select ename, sal from emp;
begin
  for new_cur in cur loop
    dbms_output.put_line('員工:' || new_cur.ename || '的工資是:' || new_cur.sal);
  end loop;
end;

--2.動態遊標(Ref遊標)
--2.1REF遊標
accept tab prompt '你想查看什麼信息? 員工信息(E)或部門信息(D):';--使用對話框輸入參數
declare
  --定義引用遊標類型
  type cur is ref cursor; --聲明遊標類型
  /*如果不指定返回類型爲弱類型遊標,如果指定了返回類型則爲強類型,如下所示:*/
  --return emp%rowtype;
  --根據定義的引用遊標類型聲明遊標變量
  new_cur   cur;
  p_id      number;
  p_name    varchar2(200);
  selection varchar2(1) := upper(substr('&tab', 1, 1)); --接收對話框輸入參數
begin
  if selection = 'E' then
    open new_cur for
      select empno id, ename name from emp;
    dbms_output.put_line('=====員工信息表=====');
  elsif selection = 'D' then
    open new_cur for
      select deptno id, dname name from dept;
    dbms_output.put_line('=====部門信息表=====');
  else
    dbms_output.put_line('請輸入員工信息(E)或部門信息(D)');
    return;
  end if;
  /*fetch new_cur into p_id,p_name;
  while new_cur%found loop
  dbms_output.put_line('#'||p_id||':'||p_name);
  fetch new_cur into p_id,p_name;
  end loop;*/ --遞歸提取遊標數據方法
  loop
    --循環提取遊標數據方法
    fetch new_cur
      into p_id, p_name;
    exit when new_cur%notfound;
    dbms_output.put_line('#' || p_id || ':' || p_name);
  end loop;
  close new_cur;
end;

--使用公用變量的動態查詢語句
set serveroutput on;
variable aa number; --定義公用變量
execute :empno :=7369;--公用變量賦值

declare
  sqlstr  varchar2(2000);
  emp_row emp%rowtype;
  emno    number;
begin
  emno   := :empno; --使用公用變量
  sqlstr := 'select * from emp where empno=:id';
  --執行動態SQL
  execute immediate sqlstr
    into emp_row
    using emno;
  dbms_output.put_line('編號爲:' || emno || '的工資爲:' || emp_row.sal);
end;

--使用遊標變量執行動態SQL
variable maxsal number;--在ORACLE中定義公用變量
execute :maxsal := 2500;--對公用變量賦值
declare
  r_emp   emp%rowtype;
  type    c_type is ref cursor;
  cur     c_type;
  p_salary number;
begin
  p_salary := :maxsal;
  open cur for 'select * from emp where sal >:1 order by sal desc'
    using p_salary; --引用公用變量,對WHERE條件的:1參數賦值
  dbms_output.put_line('薪水大於' || p_salary || '的員工有:');
  loop
    fetch cur
      into r_emp;
    exit when cur%notfound;
    dbms_output.put_line(':編號:' || r_emp.empno || '姓名' || r_emp.ename ||
                         '薪水:' || r_emp.sal);
  end loop;
  close cur;
end;





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