Oracle 11g Release 1 (11.1) 游标——显式游标
http://docs.oracle.com/cd/B28359_01/appdev.111/b28370/static.htm#CIHCAHJA
?
本文內(nèi)容
- 聲明一個(gè)游標(biāo)
- 打開一個(gè)游標(biāo)
- 用游標(biāo)獲取一個(gè)(Fetch)數(shù)據(jù)
- 用游標(biāo)獲取全部(Fetch Bulk)數(shù)據(jù)
- 關(guān)閉一個(gè)游標(biāo)
- 顯式游標(biāo)的屬性
?
當(dāng)需要準(zhǔn)確控制查詢時(shí),可以在任何 PL/SQL 塊(block)、子程序(subprogram)或包(package)的聲明部分里聲明一個(gè)顯式游標(biāo)。
可以使用三個(gè)語句來控制游標(biāo):OPEN、FETCH 和 CLOSE。
- 首先,用 OPEN 語句初始化游標(biāo),確定結(jié)果集;
- 之后,重復(fù)執(zhí)行 FETCH 語句,知道所有數(shù)據(jù)行已經(jīng)被檢索,或使用 BULK COLLECT 子句一次性獲取所有數(shù)據(jù);
- 當(dāng)最后一行數(shù)據(jù)已經(jīng)被處理,可以用 CLOSE 語句釋放游標(biāo)。
該技術(shù)需要比其他技術(shù),如 SQL 游標(biāo) FOR LOOP,更多的代碼。但它的優(yōu)點(diǎn)是靈活。你可以:
- 通過聲明和打開多個(gè)游標(biāo),來并行處理很多查詢
- 在一個(gè)循環(huán)迭代中處理多個(gè)行,掠過行,把處理分割到多個(gè)循環(huán)
?
本文示例使用的表,位于 Oracle OE Schema 示例。另外,示例在 SQL*PLUS 下運(yùn)行。示例最后 "/" 符號可讓 SQL*PLUS 編譯代碼;而在 PL/SQL Developer 下則可有可無。
?
聲明一個(gè)游標(biāo)
在語句中引用游標(biāo)前,必須聲明游標(biāo)。給出游標(biāo)的名稱,并與指定查詢關(guān)聯(lián)。另外,也可以為游標(biāo)聲明一個(gè)返回類型,如 table_name%ROWTYPE。也可以在 WHERE 子句指定游標(biāo)參數(shù)(不是本地變量)。游標(biāo)參數(shù)可以有默認(rèn)值。
示例 1:演示聲明一個(gè)游標(biāo)。
DECLARE my_emp_id NUMBER(6); -- variable for employee_id my_job_id VARCHAR2(10); -- variable for job_id my_sal NUMBER(8, 2); -- variable for salary CURSOR c1 IS SELECT employee_id, job_id, salary FROM employees WHERE salary > 2000; my_dept departments%ROWTYPE; -- variable for departments row CURSOR c2 RETURN departments%ROWTYPE IS SELECT * FROM departments WHERE department_id = 110; BEGIN NULL; END; /- 游標(biāo)不是 PL/SQL 變量,因此,不能分配一個(gè)值給游標(biāo),或是在表達(dá)式中使用游標(biāo)。
- 游標(biāo)和變量遵循相同的作用域規(guī)則。
- 游標(biāo)可以帶參數(shù),可以出現(xiàn)在與其相關(guān)的查詢中。游標(biāo)的形參(formal parameters )必須是 IN 參數(shù)(輸入?yún)?shù));參數(shù)為查詢提供值,但不能從查詢中返回任何值。不能在游標(biāo)參數(shù)上強(qiáng)加 NOT NULL 約束。
示例 2:演示游標(biāo)參數(shù)。你可以初始化游標(biāo)參數(shù)為默認(rèn)值。可以傳遞不同數(shù)量的實(shí)參(actual parameters )給游標(biāo)。也可以添加新的行參,而無需改變現(xiàn)有的游標(biāo)引用。
DECLARE CURSOR c1(low NUMBER DEFAULT 0, high NUMBER DEFAULT 99) IS SELECT * FROM departments WHERE department_id > low AND department_id < high; BEGIN NULL; END; /?
打開一個(gè)游標(biāo)
打開游標(biāo)執(zhí)行查詢,并確定結(jié)果集。
對于用 FOR UPDATE 子句聲明的游標(biāo),OPEN 語句還會鎖定那些行。
示例 3:演示打開一個(gè)游標(biāo)。
DECLARE CURSOR c1 IS SELECT employee_id, last_name, job_id, salary FROM employees WHERE salary > 2000; BEGIN OPEN c1; END; /?
用游標(biāo)獲取一個(gè)(Fetch)數(shù)據(jù)
除非使用 BULK COLLECT 子句,否則,FETCH 語句每次在結(jié)果集中取出一行。每次取出當(dāng)前行,游標(biāo)在結(jié)果集中前進(jìn)到下一行。你可以把每列存儲到單獨(dú)變量。也可以存儲整行,通常變量用 %ROWTYPE 聲明。
對于與游標(biāo)關(guān)聯(lián)的查詢返回的每列,在 INTO 列表中必須是相對應(yīng)的、類型兼容的變量。一般,使用帶 LOOP 和 EXIT WHEN NOTFOUND 的 FETCH 語句。
示例 4:演示用游標(biāo)獲取一個(gè)(Fetch)數(shù)據(jù)。
DECLARE v_jobid employees.job_id%TYPE; -- variable for job_id v_lastname employees.last_name%TYPE; -- variable for last_name CURSOR c1 IS SELECT last_name, job_id FROM employees WHERE REGEXP_LIKE(job_id, 'S[HT]_CLERK'); v_employees employees%ROWTYPE; -- record variable for row CURSOR c2 is SELECT * FROM employees WHERE REGEXP_LIKE(job_id, '[ACADFIMKSA]_M[ANGR]'); BEGIN OPEN c1; -- open the cursor before fetching LOOP -- Fetches 2 columns into variables FETCH c1 INTO v_lastname, v_jobid; EXIT WHEN c1%NOTFOUND; DBMS_OUTPUT.PUT_LINE(RPAD(v_lastname, 25, ' ') || v_jobid); END LOOP; CLOSE c1; DBMS_OUTPUT.PUT_LINE('-------------------------------------'); OPEN c2; LOOP -- Fetches entire row into the v_employees record FETCH c2 INTO v_employees; EXIT WHEN c2%NOTFOUND; DBMS_OUTPUT.PUT_LINE(RPAD(v_employees.last_name, 25, ' ') || v_employees.job_id); END LOOP; CLOSE c2; END; /輸出:
Nayer ST_CLERK Mikkilineni ST_CLERK Landry ST_CLERK Markle ST_CLERK Bissot ST_CLERK Atkinson ST_CLERK Marlow ST_CLERK Olson ST_CLERK Mallin ST_CLERK Rogers ST_CLERK Gee ST_CLERK Philtanker ST_CLERK Ladwig ST_CLERK Stiles ST_CLERK Seo ST_CLERK Patel ST_CLERK Rajs ST_CLERK Davies ST_CLERK Matos ST_CLERK Vargas ST_CLERK Taylor SH_CLERK Fleaur SH_CLERK Sullivan SH_CLERK Geoni SH_CLERK Sarchand SH_CLERK Bull SH_CLERK Dellinger SH_CLERK Cabrio SH_CLERK Chung SH_CLERK Dilly SH_CLERK Gates SH_CLERK Perkins SH_CLERK Bell SH_CLERK Everett SH_CLERK McCain SH_CLERK Jones SH_CLERK Walsh SH_CLERK Feeney SH_CLERK OConnell SH_CLERK Grant SH_CLERK ------------------------------------- Greenberg FI_MGR Russell SA_MAN Partners SA_MAN Errazuriz SA_MAN Cambrault SA_MAN Zlotkey SA_MAN Hartstein MK_MAN Higgins AC_MGR可以在與游標(biāo)關(guān)聯(lián)的查詢中,在游標(biāo)作用域內(nèi)引用 PL/SQL 變量。當(dāng)游標(biāo)打開時(shí),計(jì)算查詢中的所有變量。
示例 5:查詢可以在游標(biāo)的作用域內(nèi)引用 PL/SQL 變量。每次取出的工資 salary 都被乘以 2,即使每次取出后,factor 變量自增 1。
DECLARE my_sal employees.salary%TYPE; my_job employees.job_id%TYPE; factor INTEGER := 2; CURSOR c1 IS SELECT factor * salary FROM employees WHERE job_id = my_job; BEGIN OPEN c1; -- factor initially equals 2 LOOP FETCH c1 INTO my_sal; EXIT WHEN c1%NOTFOUND; factor := factor + 1; -- does not affect FETCH END LOOP; CLOSE c1; END; /若想改變查詢結(jié)果集或變量的值,必須關(guān)閉并用輸入變量重新打開游標(biāo)來設(shè)置新值。你可以用同一個(gè)游標(biāo),使用不同的 INTO 列表來單獨(dú)獲取。
示例 6:演示獲取到不同的變量。
DECLARE CURSOR c1 IS SELECT last_name FROM employees ORDER BY last_name; name1 employees.last_name%TYPE; name2 employees.last_name%TYPE; name3 employees.last_name%TYPE; BEGIN OPEN c1; FETCH c1 INTO name1; -- this fetches first row FETCH c1 INTO name2; -- this fetches second row FETCH c1 INTO name3; -- this fetches third row CLOSE c1; END; /若獲取結(jié)果集中最后一行,不會定義目標(biāo)變量的值。最終,FETCH 語句不會返回行。此時(shí),不會產(chǎn)生異常。可以使用游標(biāo)屬性 %FOUND 或 %NOTFOUND 來檢測。參考 Using Cursor Expressions。
?
用游標(biāo)獲取全部(Fetch Bulk)數(shù)據(jù)
BULK COLLECT 子句可以一次性從結(jié)果集獲取所有行。參考 See Retrieving Query Results into Collections (BULK COLLECT Clause)。
示例 7:演示用游標(biāo)獲取全部(Fetch Bulk)數(shù)據(jù)。演示從一個(gè)游標(biāo)獲取全部數(shù)據(jù)到兩個(gè)集合。
DECLARE TYPE IdsTab IS TABLE OF employees.employee_id%TYPE; TYPE NameTab IS TABLE OF employees.last_name%TYPE; ids IdsTab; names NameTab; CURSOR c1 IS SELECT employee_id, last_name FROM employees WHERE job_id = 'ST_CLERK'; BEGIN OPEN c1; FETCH c1 BULK COLLECT INTO ids, names; CLOsE c1; -- Here is where you process the elements in the collections FOR i IN ids.FIRST .. ids.LAST LOOP IF ids(i) > 140 THEN DBMS_OUTPUT.PUT_LINE(ids(i)); END IF; END LOOP; FOR i IN names.FIRST .. names.LAST LOOP IF names(i) LIKE '%Ma%' THEN DBMS_OUTPUT.PUT_LINE(names(i)); END IF; END LOOP; END; /輸出:
141 142 143 144 Markle Marlow Mallin Matos?
關(guān)閉一個(gè)游標(biāo)
CLOSE 語句禁用游標(biāo),并使結(jié)果集為未定義。可以重新打開已關(guān)閉的游標(biāo),用所有游標(biāo)參數(shù)的值,和 WHERE 子句引用的變量,再次執(zhí)行查詢。任何在一個(gè)已關(guān)閉的游標(biāo)上的操作都會產(chǎn)生預(yù)定義異常 INVALID_CURSOR。
?
顯式游標(biāo)的屬性
每個(gè)顯式游標(biāo)和游標(biāo)變量都有四個(gè)屬性:%FOUND、%ISOPEN、%NOTFOUND 和 %ROWCOUNT。當(dāng)追加到游標(biāo)或游標(biāo)變量名時(shí),這些屬性返回關(guān)于一個(gè) SQL 語句執(zhí)行很有用的信息。你可以在過程語句中使用游標(biāo)屬性,而不能在 SQL 語句。
顯式游標(biāo)屬性返回執(zhí)行一個(gè)多行查詢的執(zhí)行信息。當(dāng)打開一個(gè)顯式游標(biāo)或一個(gè)游標(biāo)變量時(shí),確定滿足與其關(guān)聯(lián)查詢的行,并形成結(jié)果集。行被從結(jié)果集中取出來。
%FOUND 屬性:一個(gè)行已被取出?
打開一個(gè)游標(biāo)或游標(biāo)變量后,第一次取出前,%FOUND 返回 NULL。取出后,若最后最后取出已返回一行,則返回 %FOUND 返回 TRUE;若接下來的取出沒有返回行,則返回 FALSE。
示例 8:演示 %FOUND。
DECLARE CURSOR c1 IS SELECT last_name, salary FROM employees WHERE ROWNUM < 11; my_ename employees.last_name%TYPE; my_salary employees.salary%TYPE; BEGIN OPEN c1; LOOP FETCH c1 INTO my_ename, my_salary; IF c1%FOUND THEN -- fetch succeeded DBMS_OUTPUT.PUT_LINE('Name = ' || my_ename || ', salary = ' || my_salary); ELSE -- fetch failed, so exit loop EXIT; END IF; END LOOP; END; /輸出:
Name = King, salary = 24000 Name = Kochhar, salary = 17000 Name = De Haan, salary = 17000 Name = Hunold, salary = 9000 Name = Ernst, salary = 6000 Name = Austin, salary = 4800 Name = Pataballa, salary = 4800 Name = Lorentz, salary = 4200 Name = Greenberg, salary = 12000 Name = Faviet, salary = 9000引用沒有打開的游標(biāo)或游標(biāo)變量,會產(chǎn)生預(yù)定義異常 INVALID_CURSOR。
%ISOPEN 屬性: 游標(biāo)是打開的?
若游標(biāo)或游標(biāo)變量是打開的,則 %ISOPEN 返回 TRUE;否則,返回 FALSE。
示例 9:演示 %ISOPEN。
DECLARE CURSOR c1 IS SELECT last_name, salary FROM employees WHERE ROWNUM < 11; the_name employees.last_name%TYPE; the_salary employees.salary%TYPE; BEGIN IF c1%ISOPEN = FALSE THEN -- cursor was not already open OPEN c1; END IF; FETCH c1 INTO the_name, the_salary; CLOSE c1; END; /%NOTFOUND 屬性:沒有獲取行?
%NOTFOUND 與 %FOUND 相反。若接下來的取出返回一行,則 %NOTFOUND 為 FALSE;否則為 TRUE。
示例 10:演示 %NOTFOUND。當(dāng)沒有獲取一行時(shí),用 %NOTFOUND 退出循環(huán)。
DECLARE CURSOR c1 IS SELECT last_name, salary FROM employees WHERE ROWNUM < 11; my_ename employees.last_name%TYPE; my_salary employees.salary%TYPE; BEGIN OPEN c1; LOOP FETCH c1 INTO my_ename, my_salary; IF c1%NOTFOUND THEN -- fetch failed, so exit loop -- Another form of this test is -- "EXIT WHEN c1%NOTFOUND OR c1%NOTFOUND IS NULL;" EXIT; ELSE -- fetch succeeded DBMS_OUTPUT.PUT_LINE('Name = ' || my_ename || ', salary = ' || my_salary); END IF; END LOOP; END; /輸出:
Name = King, salary = 24000 Name = Kochhar, salary = 17000 Name = De Haan, salary = 17000 Name = Hunold, salary = 9000 Name = Ernst, salary = 6000 Name = Austin, salary = 4800 Name = Pataballa, salary = 4800 Name = Lorentz, salary = 4200 Name = Greenberg, salary = 12000 Name = Faviet, salary = 9000在第一次獲取前,%NOTFOUND 返回 NULL。若 FETCH 沒有執(zhí)行成功,則循環(huán)不能被退出,因?yàn)?#xff0c;只要 WHEN 條件為 TRUE,EXTI WHEN 語句就執(zhí)行。安全起見,你可以使用下面語句:
EXIT WHEN c1%NOTFOUND OR c1%NOTFOUND IS NULL;引用沒有開發(fā)的游標(biāo)或游標(biāo)變量,會產(chǎn)生預(yù)定義異常 INVALID_CURSOR。
%ROWCOUNT 屬性:目前為止受影響的行有多少?
當(dāng)打開游標(biāo)或游標(biāo)變量時(shí),%ROWCOUNT 為 0。在第一次取出前,%ROWCOUNT 也為 0。此后,它為目前為止受影響行的數(shù)量。若接下來的取出返回一行,則數(shù)量是遞增的。
示例 11:演示 %ROWCOUNT。
DECLARE CURSOR c1 IS SELECT last_name FROM employees WHERE ROWNUM < 11; name employees.last_name%TYPE; BEGIN OPEN c1; LOOP FETCH c1 INTO name; EXIT WHEN c1%NOTFOUND OR c1%NOTFOUND IS NULL; DBMS_OUTPUT.PUT_LINE(c1%ROWCOUNT || '. ' || name); IF c1%ROWCOUNT = 5 THEN DBMS_OUTPUT.PUT_LINE('--- Fetched 5th record ---'); END IF; END LOOP; CLOSE c1; END; /輸出:
1. King 2. Kochhar 3. De Haan 4. Hunold 5. Ernst --- Fetched 5th record --- 6. Austin 7. Pataballa 8. Lorentz 9. Greenberg 10. Faviet引用沒有打開的游標(biāo)或游標(biāo)變量,會產(chǎn)生預(yù)定義異常 INVALID_CURSOR。
下表顯示在 OPEN、FETCH 和 CLOSE 語句執(zhí)行之前和之后,每個(gè)游標(biāo)屬性的值。
| 時(shí)間點(diǎn) | %FOUND 值 | %ISOPEN 值 | %NOTFOUND 值 | %ROWCOUNT 值 |
| OPEN 前 | 異常 | FALSE | 異常 | 異常 |
| OPEN 后 | NULL | TRUE | NULL | 0 |
| 第一次 FETCH 前 | NULL | TRUE | NULL | 0 |
| 第一次 FETCH 后 | TRUE | TRUE | FALSE | 1 |
| 每次連續(xù) FETCH 前,除了最后一行 | TRUE | TRUE | FALSE | 1 |
| 每次連續(xù) FETCH 后,除了最后一行 | TRUE | TRUE | FALSE | 依賴數(shù)據(jù) |
| 最后 FETCH 前 | TRUE | TRUE | FALSE | 依賴數(shù)據(jù) |
| 最后 FETCH 后 | FALSE | TRUE | TRUE | 依賴數(shù)據(jù) |
| CLOSE 前 | FALSE | TRUE | TRUE | 依賴數(shù)據(jù) |
| CLOSE 后 | 異常 | FALSE | 異常 | 異常 |
轉(zhuǎn)載于:https://www.cnblogs.com/liuning8023/archive/2012/07/29/2614254.html
總結(jié)
以上是生活随笔為你收集整理的Oracle 11g Release 1 (11.1) 游标——显式游标的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: bridge模式
- 下一篇: EDM营销的三个小窍门-EDM营销必看