1. 游標的概念和作用
- 游標是 sql 的一個內存工作區,由系統或用戶以變量的形式定義
- 游標的作用就是用於臨時存儲從數據庫中提取的數據塊(結果集)。
- 它有一個
指針
,從上往下移動(fetch
),從而能夠遍歷每條記錄。 - 用
犧牲內存
來提升 SQL 執行效率,適用於 大數據處理。
(摘抄自https://blog.csdn.net/qq_34745941/java/article/details/81294166)。
2.游標結構圖
3.具體用法
游標有四大屬性,分別是
1. “SQL%ISOPEN” :布爾類型。判斷游標是否打開
2.“SQL%FOUND”:布爾類型。判斷上一條fetch語句是否有值,有則為true,否則為false;
3.“SQL%NOTFOUND”:布爾類型。與2相反,常用作退出循環的條件。
4.“SQL%ROWCOUNT”:整型。當前成功執行更改的數據行數。
3.1 靜態游標
3.1.1 隱式游標
使用DML操作(增刪改)或select……into……會自動創建隱式游標,名稱是“sql”,該游標會自動聲明,打開和關閉。無需人為開啟或關閉。
create or replace procedure ATest( O_Result Out VarChar2 )is v_id staff.id%type; begin insert into staff(id,name) values(1,'張三'); if sql%found then O_Result:='添加成功'; end if; update staff set name = '李四'where id = 1; if sql%found then O_Result:='更新成功'; end if; delete from staff where id = 1; if sql%found then O_Result:='刪除成功'; end if; select id into v_id from staff; if sql%found then O_Result:='查詢成功'; end if; if sql%isopen then O_Result:='游標為開啟狀態,但不可能走到這一步'; --游標只有在執行上述增刪改操作才會開啟並自動關閉 else O_Result:='游標為關閉狀態'; end if; exception when Others then begin O_Result:='N_SQLCODE is '||SQLCODE||' and SQLERRM is '||SQLERRM; rollback; end; end;
3.1.2 顯式游標
顯示游標又分為不帶參數和帶參數兩種
無參:
create or replace procedure ATest( O_Result Out VarChar2 )is v_cur_info staff%rowtype; cursor v_cur is --聲明游標 為staff表的數據集 select * from staff; begin open v_cur; --打開游標 fetch v_cur into v_cur_info; --賦值給游標 O_Result:='ID:'||v_cur_info.id||',Name:'||v_cur_info.name;--輸出值 close v_cur; --關閉游標 exception when Others then begin O_Result:='N_SQLCODE is '||SQLCODE||' and SQLERRM is '||SQLERRM; rollback; end; end;
輸出結果: ID:1,Name:張三
帶參:
create or replace procedure ATest( O_Result Out VarChar2 )is v_cur_info staff%rowtype; cursor v_cur(v_id staff.id%type) is --聲明游標 為staff表的數據集 select * from staff where id =v_id; --參數:v_id begin open v_cur(1); --打開游標 fetch v_cur into v_cur_info; --賦值給游標 O_Result:='ID:'||v_cur_info.id||',Name:'||v_cur_info.name; close v_cur; --關閉游標 exception when Others then begin O_Result:='N_SQLCODE is '||SQLCODE||' and SQLERRM is '||SQLERRM; rollback; end; end;
輸出結果: ID:1,Name:張三
3.2 動態游標
3.2.1 自定義類型游標
自定義游標類型聲明寫法:
TYPE ref_type_name IS REF CURSOR [RETURN return_type];
ref_type_name代表我們自定義類型的名稱,cursor是系統默認的
return_type代表數據庫表中的一行,或一個記錄類型,是一個返回類型;
返回值不是必要的,無返回值則稱為弱類型,更加靈活;有返回值稱為強類型,減少錯誤;
弱類型寫法:
create or replace procedure ATest( O_Result Out VarChar2 )is v_cur_info staff%rowtype; type v_cur_type is ref cursor; --自定義游標類型 v_cur v_cur_type; begin open v_cur for --打開游標並聲明 select * from staff where id<5; loop --開始循環 fetch v_cur into v_cur_info; -- 賦值 exit when v_cur%notfound; --判斷沒有值就退出循環 O_Result:= O_Result||chr(10)|| 'ID:'||v_cur_info.id||',Name:'||v_cur_info.name; end loop; close v_cur; exception when Others then begin O_Result:='N_SQLCODE is '||SQLCODE||' and SQLERRM is '||SQLERRM; rollback; end; end;
另一種寫法:
create or replace procedure ATest( O_Result Out VarChar2 )is v_sql varchar(1000); v_param staff.id%type:=5; v_cur_info staff%rowtype; type v_cur_type is ref cursor; --自定義游標類型 v_cur v_cur_type; begin v_sql:='select * from staff where id <:id'; open v_cur for v_sql --打開游標並聲明 using v_param; --綁定參數方法 loop --開始循環 fetch v_cur into v_cur_info; -- 賦值 exit when v_cur%notfound; --判斷沒有值就退出循環 O_Result:= O_Result||chr(10)|| 'ID:'||v_cur_info.id||',Name:'||v_cur_info.name; end loop; close v_cur; exception when Others then begin O_Result:='N_SQLCODE is '||SQLCODE||' and SQLERRM is '||SQLERRM; rollback; end; end;
強類型寫法:
三個注意事項:
1.強類型無法使用綁定參數方法
2.for后面必須是sql,不能是字符串,如上面的v_sql;
3.參數必須對應;
create or replace procedure ATest( O_Result Out VarChar2 )is v_cur_info staff%rowtype; type v_cur_type is ref cursor return staff%rowtype ; --自定義游標類型 v_cur v_cur_type; begin open v_cur for --打開游標並聲明 select * from staff where id <5; loop --開始循環 fetch v_cur into v_cur_info; -- 賦值 exit when v_cur%notfound; --判斷沒有值就退出循環 O_Result:= O_Result||chr(10)|| 'ID:'||v_cur_info.id||',Name:'||v_cur_info.name; end loop; close v_cur; exception when Others then begin O_Result:='N_SQLCODE is '||SQLCODE||' and SQLERRM is '||SQLERRM; rollback; end; end;
3.2.2 系統類型游標
簡寫手動聲明自定義游標的過程
type v_cur_type is ref cursor return staff%rowtype ; --自定義游標類型
v_cur v_cur_type;
等同於 v_cur sys_refcursor;
4.效率問題
沒有實際測試過,根據其他博客總結是這樣:一般來說批量處理的速度要最好,隱式游標的次之,單條處理的最差
以下是示例:
1、批量處理 open 游標; loop fetch 游標 bulk collect into 集合變量(也就是 table 類型哦) limit 數值; -- 一般 500 左右 exit when 條件 --(變量.count = 0,如果用 sql%notfound 不足 limit 的記錄就不會被執行哦) close 游標; 2、隱式游標 for x in (sql 語句) loop ... 邏輯處理 end loop; 3、單條處理 open 游標; loop fetch 游標 into 變量; exit when 條件 end loop; close 游標; ———————————————— 原文鏈接:https://blog.csdn.net/qq_34745941/java/article/details/81294166
批量處理的關鍵字不是很了解,下次學習下在記錄起來;
隱式游標寫法最簡潔明了,類似於程序中的for循環寫法;
單條處理大概就是上面那些范例的寫法。
(如果有錯誤,再回來改正)。
內容參考於https://blog.csdn.net/qq_34745941/article/details/81294166和
https://www.cnblogs.com/heshan664754022/archive/2013/05/22/3092437.html
------------恢復內容結束------------