這篇文章是選取官方文檔的部分章節(jié)翻譯過(guò)來(lái)的,去除了原文中的例子,并在結(jié)尾補(bǔ)充了幾個(gè)例子。有興趣的朋友可以點(diǎn)擊文章末尾的連接去閱讀官方文檔。
創(chuàng)新互聯(lián)公司主營(yíng)太子河網(wǎng)站建設(shè)的網(wǎng)絡(luò)公司,主營(yíng)網(wǎng)站建設(shè)方案,重慶APP軟件開(kāi)發(fā),太子河h5重慶小程序開(kāi)發(fā)搭建,太子河網(wǎng)站營(yíng)銷(xiāo)推廣歡迎太子河等地區(qū)企業(yè)咨詢(xún)
一、游標(biāo)的定義
游標(biāo)是指向?qū)S肧QL區(qū)域的指針,該區(qū)域存儲(chǔ)有關(guān)處理特定SELECT或DML語(yǔ)句的信息。本章解釋的游標(biāo)是會(huì)話游標(biāo)。會(huì)話游標(biāo)存在于會(huì)話中直到會(huì)話結(jié)束。由PL/SQL創(chuàng)建和管理的游標(biāo)稱(chēng)為隱式游標(biāo),由用戶(hù)創(chuàng)建和管理的游標(biāo)稱(chēng)為顯式游標(biāo)。你可以通過(guò)游標(biāo)的屬性獲取任意會(huì)話游標(biāo)的相關(guān)信息。通過(guò)查詢(xún)動(dòng)態(tài)性能視圖V$OPEN_CURSOR,可以列出當(dāng)前已經(jīng)打開(kāi)和解析的游標(biāo)。
二、隱式游標(biāo)
每次執(zhí)行select 或DML操作時(shí),都會(huì)生成隱式游標(biāo)。用戶(hù)不能控制隱式游標(biāo),但可以通過(guò)游標(biāo)的屬性獲取游標(biāo)的信息。
隱式游標(biāo)屬性的語(yǔ)法是SQLattribute(因此隱式游標(biāo)也通常叫做SQL游標(biāo))。SQLattribute總是指向最近運(yùn)行的select或DML語(yǔ)句。如果最近沒(méi)有運(yùn)行這樣的語(yǔ)句,則屬性返回NULL。
當(dāng)語(yǔ)句運(yùn)行結(jié)束時(shí),隱式游標(biāo)關(guān)閉,但是它的屬性會(huì)被保留到另一條select或DML語(yǔ)句執(zhí)行。最近的語(yǔ)句運(yùn)行的結(jié)果可能屬于不同的值,如果要保留屬性值供以后使用,可以將其保存在本地變量中。另外,其他的操作,如子程序的調(diào)用,可能在你測(cè)試之前改變屬性值。
隱式游標(biāo)的屬性有以下幾種:
屬性 | 值 | 說(shuō)明 | 備注 |
SQL%ISOPEN | FALSE | 隱式游標(biāo)總是在與其相關(guān)聯(lián)的語(yǔ)句結(jié)束之后關(guān)閉,因此總是返回FALSE | |
SQL%FOUND | NULL | 沒(méi)有執(zhí)行select或DML操作 | |
TRUE | select語(yǔ)句返回一行或多行或者DML操作影響了一行或者多行 | ||
FALSE | 其他情況 | ||
SQL%NOTFOUND | NULL | 沒(méi)有執(zhí)行select或DML操作 | 在select into中無(wú)用,沒(méi)有值時(shí)會(huì)報(bào)no_data_found的錯(cuò)誤;有值時(shí)驗(yàn)證已經(jīng)沒(méi)有意義。 |
TRUE | select語(yǔ)句返回一行或多行或者DML操作影響了一行或者多行 | ||
FALSE | 其他情況 | ||
SQL%ROWCOUNT | NULL | 沒(méi)有執(zhí)行select或DML操作 | select into中返回多行時(shí)會(huì)報(bào)too_many_data的錯(cuò)誤,并且返回1. |
數(shù)值 | 返回的數(shù)值表示select返回了多少行以及DML操作影響了多少行 | ||
SQL%BULK_ROWCOUNT | 數(shù)值 | FORALL語(yǔ)句完成后,從隱式游標(biāo)屬性SQL%BULK_ROWCOUNT獲取每個(gè)DML語(yǔ)句影響的行數(shù)。 | |
SQL%BULK_EXCEPTIONS | FORALL語(yǔ)句完成后,如果執(zhí)行期間有異常生成,會(huì)將異常數(shù)據(jù)保存在SQL%BULK_EXCEPTIONS中。 |
三、顯式游標(biāo)
顯式游標(biāo)由用戶(hù)創(chuàng)建并管理。用戶(hù)在使用顯式游標(biāo)之前必須聲明和定義游標(biāo)名稱(chēng)并將其與查詢(xún)相關(guān)聯(lián)(通常,查詢(xún)會(huì)返回多行)。然后用戶(hù)可以通過(guò)以下方式處理查詢(xún)結(jié)果集:
使用open命令打開(kāi)游標(biāo),使用fetch獲取行,使用close關(guān)閉游標(biāo);
與隱式游標(biāo)不同,可以通過(guò)名稱(chēng)引用顯示游標(biāo)或游標(biāo)變量。因此,顯式游標(biāo)或游標(biāo)變量稱(chēng)為命名游標(biāo)。
3.1 聲明和定義顯式游標(biāo)
用戶(hù)可以首先聲明一個(gè)顯式游標(biāo),然后在同一個(gè)塊,子程序或包中定義它;或者同時(shí)聲明和定義它。
只聲明游標(biāo),具有如下的語(yǔ)法:
CURSOR cursor_name [ parameter_list ] RETURN return_type;
聲明游標(biāo)并定義游標(biāo)的語(yǔ)法:
CURSOR cursor_name [ parameter_list ] [ RETURN return_type ] IS select_statement;
聲明顯式游標(biāo)的例子:
DECLARE CURSOR c1 RETURN departments%ROWTYPE; -- 聲明C1
CURSOR c2 IS SELECT employee_id, job_id, salary -- 聲明并且定義 c2
FROM employees
WHERE salary > 2000;
CURSOR c1 RETURN departments%ROWTYPE IS -- 定義 c1,-- 重復(fù)return type
SELECT * FROM departments
WHERE department_id = 110;
CURSOR c3 RETURN locations%ROWTYPE; -- 聲明c3
CURSOR c3 IS -- 定義c3, -- 忽略 return type
SELECT * FROM locations
WHERE country_id = 'JP';
BEGIN NULL;
END; /
3.2 打開(kāi)和關(guān)閉游標(biāo)
聲明和定義顯式游標(biāo)后,可以使用OPEN語(yǔ)句打開(kāi)它;您使用CLOSE語(yǔ)句關(guān)閉一個(gè)打開(kāi)的顯式游標(biāo),從而允許重用其資源。關(guān)閉游標(biāo)后,無(wú)法從其結(jié)果集中提取記錄或引用其屬性。
用戶(hù)可以重新打開(kāi)一個(gè)已經(jīng)關(guān)閉的游標(biāo)。游標(biāo)在重新打開(kāi)之間必須要被關(guān)閉。否則,PL/SQL會(huì)引發(fā)預(yù)定義異常CURSOR_ALREADY_OPEN.
3.3 使用顯式游標(biāo)獲取數(shù)據(jù)
打開(kāi)一個(gè)顯式游標(biāo)后,可以使用FETCH語(yǔ)句獲取結(jié)果集。返回一行的FETCH語(yǔ)句的基本語(yǔ)法是:
FETCH cursor_name INTO into_clause
into_clause是一個(gè)變量列表或單個(gè)記錄變量。 對(duì)于查詢(xún)返回的每個(gè)列,變量列表或記錄必須具有對(duì)應(yīng)的類(lèi)型兼容變量或字段。%TYPE和%ROWTYPE屬性可用于聲明變量和記錄以在FETCH語(yǔ)句中使用。FETCH語(yǔ)句檢索結(jié)果集的當(dāng)前行,將該行的列值存儲(chǔ)到變量或記錄中,并將光標(biāo)前移到下一行。通常,在LOOP語(yǔ)句中使用FETCH語(yǔ)句,當(dāng)FETCH語(yǔ)句用完行時(shí)退出。 要檢測(cè)此退出條件,請(qǐng)使用游標(biāo)屬性%NOTFOUND。因?yàn)楫?dāng)FETCH語(yǔ)句不返回任何行時(shí),PL/SQL不會(huì)引發(fā)異常。
3.4 顯式游標(biāo)查詢(xún)中的變量
顯式游標(biāo)查詢(xún)可以引用其作用域中的任何變量。 當(dāng)打開(kāi)顯式游標(biāo)時(shí),PL / SQL將評(píng)估查詢(xún)中的任何變量,并在標(biāo)識(shí)結(jié)果集時(shí)使用這些值。 稍后更改變量的值不會(huì)更改結(jié)果集。【定義游標(biāo)時(shí),游標(biāo)中結(jié)果集就已經(jīng)確定,如要改變結(jié)果集,必須關(guān)閉游標(biāo)并重新打開(kāi)游標(biāo)】
3.5 當(dāng)顯式游標(biāo)列需要?jiǎng)e名時(shí)
當(dāng)顯式游標(biāo)查詢(xún)包含虛擬列(表達(dá)式)時(shí),如果滿(mǎn)足以下任一條件,則該列必須具有別名:
1、使用游標(biāo)讀取使用%ROWTYPE聲明的記錄。
2、需要引用虛擬列
3.6 接受參數(shù)的顯示游標(biāo)
用戶(hù)可以創(chuàng)建具有形式參數(shù)的顯式游標(biāo),然后在每次打開(kāi)游標(biāo)時(shí)將不同的實(shí)際參數(shù)傳遞到游標(biāo)。 在游標(biāo)查詢(xún)中,可以在可以使用常量的任何位置使用正式的光標(biāo)參數(shù)。在光標(biāo)查詢(xún)之外,用戶(hù)不能引用正式的光標(biāo)參數(shù)。
3.7 顯示游標(biāo)的屬性
%ISOPEN TRUE:游標(biāo)打開(kāi)狀態(tài);FALSE:其他狀態(tài)。
%FOUND NULL:顯示游標(biāo)打開(kāi)但是還沒(méi)有獲取第一行
TRUE:從顯式游標(biāo)的最近一次提取返回了一行
FALSE:其他情況
%NOTFOUND NULL:顯示游標(biāo)打開(kāi)但是還沒(méi)有獲取第一行
FALSE:從顯式游標(biāo)的最近一次提取返回了一行
TRUE:其他情況
%ROWCOUNT:在顯式游標(biāo)打開(kāi)后但在第一次提取之前為零;否則就獲取行數(shù)。
四、例子
4.1 獲取tabs中表名稱(chēng)的兩個(gè)例子
方法一:將結(jié)果集裝在記錄中
declare
--表行的記錄變量
cursor mycur is select * from tabs;
cur_result tabs%rowtype;
begin
open mycur;--打開(kāi)游標(biāo)
loop
fetch mycur into cur_result;--獲取數(shù)據(jù)
exit when mycur%notfound;--退出循環(huán)
dbms_output.put_line('The table name is '||cur_result.table_name);
end loop;
close mycur;--關(guān)閉游標(biāo)
end;
方法二:將結(jié)果集裝在變量中
declare
--變量
cursor mycur is select table_name from tabs;
v_tablename tabs.table_name%type;
begin
open mycur;--打開(kāi)游標(biāo)
loop
fetch mycur into v_tablename;--獲取數(shù)據(jù)
exit when mycur%notfound;--退出循環(huán)
dbms_output.put_line('The table name is '||v_tablename);
end loop;
close mycur;--關(guān)閉游標(biāo)
end;
方法三:將結(jié)果集裝在游標(biāo)類(lèi)型的row%type中
declare
--表行的記錄變量
cursor mycur is select table_name from tabs;
cur_result mycur%rowtype;
begin
open mycur;--打開(kāi)游標(biāo)
loop
fetch mycur into cur_result;--獲取數(shù)據(jù)
exit when mycur%notfound;--退出循環(huán)
dbms_output.put_line('The table name is '||cur_result.table_name);
end loop;
close mycur;--關(guān)閉游標(biāo)
end;
4.2 動(dòng)態(tài)游標(biāo)
靜態(tài)游標(biāo)的聲明與定義必須在同一個(gè)塊中執(zhí)行,動(dòng)態(tài)游標(biāo)可以在begin之前聲明游標(biāo),在打開(kāi)游標(biāo)時(shí)定義sql語(yǔ)句,即可以使用open cursor_name for sql_statement的形式打開(kāi)游標(biāo)。sql_statement可以是靜態(tài)的SQL語(yǔ)句,也可以是動(dòng)態(tài)的SQL語(yǔ)句。
例一:靜態(tài)的SQL語(yǔ)句
declare
--表行的記錄變量
type cursor_type is ref cursor;
mycur cursor_type;
cur_result tabs%rowtype;
begin
open mycur for select * from tabs;--打開(kāi)游標(biāo)
loop
fetch mycur into cur_result;--獲取數(shù)據(jù)
exit when mycur%notfound;--退出循環(huán)
dbms_output.put_line('The table name is '||cur_result.table_name);
end loop;
close mycur;--關(guān)閉游標(biāo)
end;
例二:動(dòng)態(tài)的SQL語(yǔ)句
declare
type cursor_type is ref cursor;
mycur cursor_type;
cur_result tabs%rowtype;
v_sql varchar2(1000);
begin
v_sql:='select * from tabs';
open mycur for v_sql;--打開(kāi)游標(biāo)
loop
fetch mycur into cur_result;--獲取數(shù)據(jù)
exit when mycur%notfound;--退出循環(huán)
dbms_output.put_line('The table name is '||cur_result.table_name);
end loop;
close mycur;--關(guān)閉游標(biāo)
end;
五、其他說(shuō)明
5.1 Oracle游標(biāo)的官方文檔
http://docs.oracle.com/cd/E11882_01/appdev.112/e25519/static.htm#LNPLS00602