一、簡(jiǎn)介
1、游標(biāo)的概念
游標(biāo)(Cursor) 就是一個(gè)變動(dòng)的光標(biāo),它本質(zhì)上是一個(gè)指針,指向從數(shù)據(jù)庫(kù)查詢出來的結(jié)果集任何一條記錄,初始的時(shí)候指向第一條記錄。
2、游標(biāo)的分類
Oracle中游標(biāo)分為兩類:普通游標(biāo)、REF游標(biāo),普通游標(biāo)又可以分為兩種類型:顯式游標(biāo)、隱式游標(biāo).
二、顯式游標(biāo)
顯式游標(biāo)是指在使用前必須有著明確的游標(biāo)聲明和定義,顯式游標(biāo)的定義會(huì)關(guān)聯(lián)查詢語(yǔ)句,返回一條或多條記錄,顯示游標(biāo)的使用由開發(fā)人員控制。
1、使用步驟
1)、聲明游標(biāo)
CURSOR cursor_name --聲明游標(biāo),cursor_name是游標(biāo)名稱
is select_statement; --游標(biāo)關(guān)聯(lián)的select語(yǔ)句,注意:不能是select ... into 語(yǔ)句
2)、打開游標(biāo)
游標(biāo)中想要讀取數(shù)據(jù)都是建立在游標(biāo)已打開的前提下
OPEN cursor_name;
3)、讀取數(shù)據(jù)
讀取數(shù)據(jù)是使用 FETCH語(yǔ)句,它可以把游標(biāo)指向的行記錄數(shù)據(jù)提取出來賦值給聲明的變量,注意:FETCH語(yǔ)句只能取出當(dāng)前行的記錄,一般情況下, FETCH語(yǔ)句 都是搭配 循環(huán)語(yǔ)句 一起使用,直到某個(gè)條件不符合退出循環(huán).
FETCH cursor_name INTO v_name;
4)、關(guān)閉游標(biāo)
CLOSE cursor_name;
2、示例
示例1:
declare
CURSOR cur_product --1、聲明游標(biāo)
is select * from product;
v_row_product product%rowtype; --聲明product表的行變量
begin
OPEN cur_product; --2、打開游標(biāo)
LOOP
FETCH cur_product INTO v_row_product; --3、讀取數(shù)據(jù)放入行變量
EXIT WHEN cur_product%NOTFOUND;
DBMS_OUTPUT.PUT_LINE('商品名:' || v_row_product.name || '價(jià)格:' || v_row_product.price);
END LOOP;
CLOSE cur_product; --4、關(guān)閉游標(biāo)
end;
示例2:
declare
CURSOR cur_product
is select name, price from product;
v_name product.name%type;
v_price product.price%type;
begin
OPEN cur_product;
LOOP
FETCH cur_product INTO v_name, v_price;
EXIT WHEN cur_product%NOTFOUND;
DBMS_OUTPUT.PUT_LINE('商品名:' || v_name || '價(jià)格:' || v_price);
END LOOP;
CLOSE cur_product;
end;
3、顯示游標(biāo)的屬性
顯示游標(biāo)的屬性用于返回其執(zhí)行信息,包括:
1)ISOPEN:獲取游標(biāo)是否打開,已打開返回true,沒有打開返回false
IF cur_product%ISOPEN THEN
... --游標(biāo)已打開執(zhí)行的語(yǔ)句
ELSE
OPEN cur_product; --游標(biāo)未打開則打開游標(biāo)
END IF;
2)FOUND:檢查是否從結(jié)果集中提取到了數(shù)據(jù),提取到返回true,否則返回false
LOOP
FETCH cur_product INTO v_name, v_price;
IF cur_product%FOUND;
DBMS_OUTPUT.PUT_LINE('商品名:' || v_name || '價(jià)格:' || v_price);
ELSE
EXIT;
END IF;
END LOOP;
3)NOTFOUND:和FOUND相反,提取到數(shù)據(jù)返回false,未提取到數(shù)據(jù)返回true
4)ROWCOUNT:返回當(dāng)前已經(jīng)提取了多少行數(shù)據(jù)
4、使用 FETCH ... BULK COLLECT INTO 語(yǔ)句提取全部數(shù)據(jù)
declare
CURSOR cur_product
is select * from product;
TYPE product_tab_type IS TABLE OF product%rowtype;
product_tab product_tab_type;
begin
OPEN cur_product;
FETCH cur_product BULK COLLECT INTO product_tab; --將數(shù)據(jù)全部提取出來放入product_tab
FOR i in 1..product_tab.count LOOP --循環(huán)遍歷product_tab
DBMS_OUTPUT.PUT_LINE('商品名:' || product_tab(i).name || '價(jià)格:' || product_tab(i).price);
END LOOP;
CLOSE cur_product;
end;
5、使用 FETCH ... BULK COLLECT INTO LIMIT語(yǔ)句提取部分?jǐn)?shù)據(jù)
declare
CURSOR cur_product
is select * from product;
TYPE product_tab_type IS TABLE OF product%rowtype;
product_tab product_tab_type;
begin
OPEN cur_product;
LOOP --循環(huán)1:每次提取3行數(shù)據(jù)放入product_tab
FETCH cur_product BULK COLLECT INTO product_tab LIMIT 3;
FOR i in 1..product_tab.count LOOP --循環(huán)2:遍歷輸出product_tab中的3行數(shù)據(jù)
DBMS_OUTPUT.PUT_LINE('商品名:' || product_tab(i).name || '價(jià)格:' || product_tab(i).price);
END LOOP;
DBMS_OUTPUT.PUT_LINE('-------');
EXIT WHEN cur_product%NOTFOUND;
END LOOP;
CLOSE cur_product;
end;
6、游標(biāo)FOR循環(huán)
游標(biāo)的使用大部分是為了迭代結(jié)果集,在PL/SQL中有一種更方便的循環(huán)游標(biāo)的方式實(shí)現(xiàn)
declare
CURSOR cur_product
is select * from product;
begin
FOR cur_info in cur_product --將游標(biāo)返回的數(shù)據(jù)放入cur_info ,該變量是%rowtype類型,并且無需聲明
LOOP
DBMS_OUTPUT.PUT_LINE('商品名:' || cur_info.name || '價(jià)格:' || cur_info.price);
END LOOP;
end;
這種方式簡(jiǎn)化了對(duì)游標(biāo)的處理,使用這種情況時(shí),Oracle會(huì)隱式地打開游標(biāo)、提取數(shù)據(jù)、關(guān)閉游標(biāo).
7、帶參數(shù)的游標(biāo)
使用顯示游標(biāo)時(shí)可以指定參數(shù),參數(shù)可以傳遞給游標(biāo)在查詢語(yǔ)句中使用.
參數(shù)游標(biāo)的定義:
cursor cursor_name
(param_name datatype, ...)
is select_statement;
示例:
declare
v_cid product.cid%type := '1';
CURSOR cur_product
(param_id varchar2) --指定參數(shù)
is select * from product where cid = param_id; --使用參數(shù)
v_row_product product%rowtype;
begin
OPEN cur_product(v_cid); --打開游標(biāo)時(shí)傳入?yún)?shù)
LOOP
FETCH cur_product INTO v_row_product;
EXIT WHEN cur_product%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(v_row_product.name);
END LOOP;
CLOSE cur_product;
end;
三、隱式游標(biāo)
1、隱式游標(biāo)的特點(diǎn)
隱式游標(biāo)是PL/SQL自動(dòng)管理的,有以下特點(diǎn):
1)隱式游標(biāo)有默認(rèn)名稱:SQL
2)每當(dāng)運(yùn)行SELECT語(yǔ)句或者DML語(yǔ)句時(shí),PL/SQL會(huì)打開一個(gè)隱式游標(biāo)
3)隱式游標(biāo)屬性值始終是最新執(zhí)行的SQL語(yǔ)句的
declare
v_name product.name%type;
begin
select p.name into v_name from product p where p.pid = '1';
IF SQL%FOUND THEN
DBMS_OUTPUT.PUT_LINE('pid為666的商品名稱為:' || v_name);
END IF;
end;
2、隱式游標(biāo)的屬性
隱式游標(biāo)屬性名稱和顯式游標(biāo)一樣,不過其含義有區(qū)別
1)ISOPEN:由Oracle控制,永遠(yuǎn)返回false
2)FOUND:反應(yīng)DML語(yǔ)句是否影響了數(shù)據(jù),有影響時(shí)返回true,否則返回false;也可以反應(yīng)SELECT INTO語(yǔ)句是否返回了數(shù)據(jù),返回了數(shù)據(jù)則該屬性值為true
3)NOTFOUND:和FOUND相反,DML語(yǔ)句沒有影響數(shù)據(jù)或SELECT INTO語(yǔ)句沒有返回?cái)?shù)據(jù)時(shí)值為true,其它false
4)ROWCOUNT:反應(yīng)DML語(yǔ)句影響數(shù)據(jù)的數(shù)量
四、REF游標(biāo)
REF CURSOR是一個(gè)游標(biāo)變量,當(dāng)使用顯式游標(biāo)時(shí),必須在定義部分指定其對(duì)應(yīng)的select語(yǔ)句,而使用REF CURSOR時(shí),可以在打開游標(biāo)時(shí)指定其對(duì)應(yīng)的select語(yǔ)句.
1、使用步驟
1)、定義REF CURSOR類型、游標(biāo)變量
TYPE ref_type IS REF CURSOR [RETURN return_type]; --定義REF CURSOR類型
cur_name type_type; --聲明游標(biāo)變量
2)、打開游標(biāo)
OPEN cur_name FOR select_statement;
3)、提取數(shù)據(jù):和顯式游標(biāo)使用方法一樣
4)、關(guān)閉游標(biāo):和顯式游標(biāo)使用方法一樣
2、示例
declare
v_name product.name%type;
TYPE ref_type IS REF CURSOR;
cur_product ref_type;
begin
OPEN cur_product FOR select p.name from product p;
LOOP
FETCH cur_product INTO v_name;
EXIT WHEN cur_product%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(v_name);
END LOOP;
CLOSE cur_product;
end;
3、指定RETURN子句
如果在定義REF CURSOR類型時(shí)指定了RETURN 子句,那么在select_statement中返回的結(jié)果必須與RETURN 子句定義的記錄類型匹配.
declare
v_row_product product%rowtype;
TYPE ref_type IS REF CURSOR RETURN product%rowtype;
cur_product ref_type;
begin
OPEN cur_product FOR select * from product p; --必須是product%rowtype類型
LOOP
FETCH cur_product INTO v_row_product;
EXIT WHEN cur_product%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(v_row_product.name);
END LOOP;
CLOSE cur_product;
end;