一、什麼是遊标
1、遊标的概念
可以将遊标(Cursor)形象地看成一個變動的光标。它實際上是一個指針,它在一段oracle存放資料查詢結果集或者資料操作結果集的記憶體中,這個指針可以指向結果集中的任何一條記錄。這樣就可以得到它所指向的資料了,但初始時它指向首記錄。這種模型很像程式設計中的數組。
2、遊标的類型
oracle遊标分為靜态遊标和REF遊标兩類。其中,靜态遊标就像一個資料快照,打開遊标後的結果集是對資料庫資料的一個備份,資料不随着對表執行DML操作後而改變。從這個特性來說,結果集是靜态的。
靜态遊标包含兩中類型:
(1)、顯式遊标
是指在使用之前必須有着明确的遊标聲明和定義,這樣的遊标定義會關聯資料查詢語句,通常會傳回一行或者多行。關閉遊标後就不能再對其進行操作了。顯示遊标由使用者自定義來完成,一切由使用者控制。
(2)、隐式遊标
和顯式遊标不同,它被PL/SQL自動管理,也被稱為SQL遊标,由oracle自動管理。該遊标使用者無法控制,但能得到它的屬性資訊。
二、顯式遊标
1、遊智語法
CURSOR cursor_name [ parameter_name datatype, ... ] IS select_statement;
2、遊标的使用步驟
(1)聲明遊标(并關聯一個查詢)
DECLARE CURSOR cursor_name IS select_statement;
(2)打開遊标(遊标一旦打開,結果集都是靜态的)
OPEN cursor_name;
(3)讀取遊标
讀取資料要利用FETCH語句完成,它可以把遊标指向位置的記錄放入到PL/SQL聲明的變量中。正常情況下,FETCH語句要和循環語句一起使用,這樣指針會不斷前進,直到某個條件不符合要求而退出。
FETCH cursor_name INTO Record_name;
(4)關閉遊标
CLOSE cursor_name;
3、遊标中的LOOP語句
declare
cursor info_cursor is select id,position,strain from CONSTANTINFO where id <11;
--使用%type可以取得表中的字段類型,使用%rowtype可以申明基于某個表的行類型
cur_id CONSTANTINFO.id%TYPE;
cur_pos CONSTANTINFO.position%TYPE;
cur_str CONSTANTINFO.strain%TYPE;
begin
--打開遊标
open info_cursor;
--循環擷取記錄集
loop
fetch info_cursor into cur_id,cur_pos,cur_str;
--使用遊标屬性:記錄集到尾,沒有記錄退出循環
exit when info_cursor%notfound;
--輸出遊标擷取的記錄集
dbms_output.put_line(cur_id ||'-----'|| cur_pos ||'-----'|| cur_str);
end loop;
--關閉遊标
close info_cursor;
--遊标中使用異常處理
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('沒有找到資料!');
WHEN TOO_MANY_ROWS THEN
DBMS_OUTPUT.PUT_LINE('資料過多!');
END;
4、使用BULK COLLECT和FOR語句的遊标——實作批量讀取資料
使用FETCH INTO語句提取資料,這種方式是單條資料提取,在資料量很大的情況下執行效率并不理想。而FETCH...BULK COLLECT INTO語句可以批量提取資料,在資料量大的情況下它的執行效率相當快。
declare
cursor info_cursor is select id,position,strain from CONSTANTINFO where id <11;
--定義和表STRACONSTANTINFO行對象一緻的集合類型constantinfo_rd,用于存放批量得到的資料
type constantinfo_tab is table of CONSTANTINFO%rowtype;
constantinfo_rd constantinfo_tab;
begin
--打開遊标
open info_cursor;
--循環擷取記錄集
loop
fetch info_cursor bulk collect into constantinfo_rd limit 2;
for i in 1..constantinfo_rd.count loop
dbms_output.put_line('資料ID:'||constantinfo_rd(i).id ||' 位置:'||
constantinfo_rd(i).position ||' 應變:'|| constantinfo_rd(i).strain);
end loop;
--記錄集到尾,沒有記錄退出循環
exit when info_cursor%notfound;
end loop;
--關閉遊标
close info_cursor;
--遊标中使用異常處理
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('沒有找到資料!');
WHEN TOO_MANY_ROWS THEN
DBMS_OUTPUT.PUT_LINE('資料過多!');
END;
5、使用CURSOR FOR LOOP——使用更加簡單
遊标有很多機會都是疊代結果集,在PL/SQL這個過程中可以使用更簡單的方式實作,CURSOR FOR LOOP不需要特别的聲明變量,它可以提出行對象類型的資料。這種方式在隐式遊标中使用更顯友善。
declare
--聲明遊标關聯查詢
CURSOR info_cursor IS select id,position,strain from CONSTANTINFO where id<11;
begin
--把遊标傳回資料放到curcfl中,該類型是個%ROWTYPE類型
FOR curcfl IN info_cursor
--疊代輸出資料
LOOP
DBMS_OUTPUT.PUT_LINE('資料ID:'||curcfl.id ||' 位置:'|| curcfl.position ||' 應變:'|| curcfl.strain);
END LOOP;
--遊标中使用異常處理
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('沒有找到資料!');
WHEN TOO_MANY_ROWS THEN
DBMS_OUTPUT.PUT_LINE('資料過多!');
end;
6、顯式遊标的屬性
(1)%ISOPEN:用于判斷遊标是否打開,打開則傳回TRUE,否則FALSE;
(2)%FOUND:用來檢測行資料是否有效。有效則傳回TRUE,否則反之;
(3)%NOTFOUND:與%FOUND正好相反,沒有提取出資料傳回TRUE,否則反之;
(4)%ROWCOUNT:累計到目前為止使用FETCH提取資料的行數。較為常用,使用它可以知道目前已經傳回多少行資料了
7、帶參數的遊标
在使用顯式遊标時是可以指定參數的,指定的參數包括參數的順序和參數的類型。參數可以傳遞給遊标在查詢中使用。這樣就友善了使用者根據不同的查詢條件進行查詢。也友善了遊标在存儲過程中的使用。
DECLARE
--使用%type可以取得表中的字段類型,并且聲明了變量賦了值;使用%rowtype可以申明基于某個表的行類型
cur_id CONSTANTINFO.id%TYPE := '100';
cur_pos CONSTANTINFO.position%TYPE := '10000';
cur_rcd CONSTANTINFO%ROWTYPE;
--聲明遊标,包括兩個參數和類型
CURSOR info_cursor(iid VARCHAR2,pos NUMBER) IS SELECT * FROM constantinfo WHERE id < iid AND position < pos;
BEGIN
--打開遊标,并且給參數賦予變量
OPEN info_cursor(cur_id,cur_pos);
--循環擷取記錄集
LOOP
FETCH info_cursor INTO cur_rcd;
--使用遊标屬性:記錄集到尾,沒有記錄退出循環
EXIT WHEN info_cursor%NOTFOUND;
--輸出遊标擷取的記錄集
DBMS_OUTPUT.PUT_LINE(cur_rcd.id ||'-----'|| cur_rcd.position ||'-----'|| cur_rcd.strain);
END LOOP;
--關閉遊标
CLOSE info_cursor;
--遊标中使用異常處理
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('沒有找到資料!');
WHEN TOO_MANY_ROWS THEN
DBMS_OUTPUT.PUT_LINE('資料過多!');
END;
三、隐式遊标
1、隐式遊标的特點
隐式遊标沒有像顯式遊标那樣聲明一個遊标名稱,而是直接使用了SQL名稱,這是隐式遊标的預設名稱,可直接使用。
(1)隐式遊标由PL/SQL自動管理;
(2)隐式遊标的預設名稱是SQL;
(3)SELECT語句或DML操作都會長産生隐式遊标的;
(4)隐式遊标的屬性始終是最新執行的SQL語句的。
declare
--使用%type可以取得表中的字段類型.
cur_id CONSTANTINFO.id%TYPE;
cur_pos CONSTANTINFO.position%TYPE;
cur_str CONSTANTINFO.strain%TYPE;
begin
select id,position,strain from CONSTANTINFO WHERE id < 11;
loop
--使用隐式遊标屬性,記錄集到尾,沒有記錄退出循環
IF SQL%FOUND;
--輸出遊标擷取的記錄集
dbms_output.put_line(cur_id ||'-----'|| cur_pos ||'-----'|| cur_str);
END IF;
EXIT WHEN SQL%NOTFOUND;
end loop;
--遊标中使用異常處理
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('沒有找到資料!');
WHEN TOO_MANY_ROWS THEN
DBMS_OUTPUT.PUT_LINE('資料過多!');
END;
2、遊标中使用異常處理
上述的所有SQL中都添加了異常處理的代碼。當資料庫中的記錄發生變化時使用SELECT INTO語句傳回的結果有可能不是單條記錄,這時候會出現腳本中斷并報錯的現象,是以需要使用異常處理:
--遊标中使用異常處理
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('沒有找到資料!');
WHEN TOO_MANY_ROWS THEN
DBMS_OUTPUT.PUT_LINE('資料過多!');
3、隐式遊标的屬性
(1)%ISOPEN:用于判斷遊标是否打開。HOWEVER,在隐式遊标中該屬性永遠傳回FALSE,它由ORACLE自己控制;
(2)%FOUND:當DML操作對資料有影響的時候傳回TRUE,SELECT INTO語句傳回資料時傳回TRUE,否則反之;
(3)%NOTFOUND:與%FOUND正好相反;
(4)%ROWCOUNT:該屬性反映出DML操作對資料影響的行數。