Oracle入门(十四.10)之显式游标简介
一、上下文區(qū)域和游標(biāo)
Oracle服務(wù)器分配一個(gè)稱為上下文區(qū)域的私有內(nèi)存區(qū)域來(lái)存儲(chǔ)由SQL語(yǔ)句處理的數(shù)據(jù)。 每個(gè)上下文區(qū)域(因此每個(gè)SQL語(yǔ)句)都有一個(gè)與其關(guān)聯(lián)的游標(biāo)。您可以將游標(biāo)視為上下文區(qū)域的標(biāo)簽,或者將其作為指向上下文區(qū)域的指針。 事實(shí)上,一個(gè)游標(biāo)就是這兩個(gè)項(xiàng)目。二、隱式和顯式游標(biāo)
有兩種類型的游標(biāo):?隱式游標(biāo):由Oracle自動(dòng)為所有SQL DML語(yǔ)句(INSERT,UPDATE,DELETE和MERGE)以及僅返回一行的SELECT語(yǔ)句定義。
?顯式游標(biāo):由程序員為返回多行的查詢聲明。 您可以使用顯式游標(biāo)來(lái)命名上下文區(qū)域并訪問(wèn)其存儲(chǔ)的數(shù)據(jù)。
三、隱式游標(biāo)的限制
EMPLOYEES表中有多行:
DECLAREv_salary employees.salary%TYPE; BEGINSELECT salary INTO v_salaryFROM employees;DBMS_OUTPUT.PUT_LINE(' Salary is : '||v_salary); END;ORA-01422: exact fetch returns more than requested number of rows
四、顯式游標(biāo)
使用顯式游標(biāo),您可以從數(shù)據(jù)庫(kù)表中檢索多行,為檢索到的每行提供一個(gè)指針,并且一次處理一行。 以下是使用顯式游標(biāo)的一些原因:?這是PL / SQL從表中檢索多行的唯一方法。
?每行由一個(gè)單獨(dú)的程序語(yǔ)句提取,使程序員可以更好地控制行的處理。
(1)顯式游標(biāo)的例子
以下示例使用明確的游標(biāo)來(lái)獲取亞洲國(guó)家的國(guó)家名稱和國(guó)定假日。
DECLARECURSOR wf_holiday_cursor IS --定義游標(biāo)SELECT country_name, national_holiday_dateFROM wf_countries where region_id IN(30,34,35);v_country_name wf_countries.country_name%TYPE;v_holiday wf_countries.national_holiday_date%TYPE; BEGINOPEN wf_holiday_cursor; --打開(kāi)游標(biāo)LOOPFETCH wf_holiday_cursor INTO v_country_name, v_holiday; --提取游標(biāo)一行EXIT WHEN wf_holiday_cursor%NOTFOUND;DBMS_OUTPUT.PUT_LINE(v_country_name||' '||v_holiday);END LOOP; CLOSE wf_holiday_cursor; --關(guān)閉游標(biāo) END;(2)顯式游標(biāo)操作
由多行查詢返回的行集稱為活動(dòng)集,并存儲(chǔ)在上下文區(qū)域中。 它的大小是符合您的搜索條件的行數(shù)。將上下文區(qū)域(由光標(biāo)命名)看作一個(gè)框,并將活動(dòng)集作為框的內(nèi)容。 為了獲得數(shù)據(jù),您必須打開(kāi)盒子并逐個(gè)從盒子中取出每一行。 完成后,您必須關(guān)閉該框。
(3)控制顯式游標(biāo)
(4)聲明和控制顯式游標(biāo)
五、使用顯式游標(biāo)的步驟
您首先聲明一個(gè)游標(biāo),然后使用OPEN,FETCH和CLOSE語(yǔ)句來(lái)控制游標(biāo)。
1.在聲明部分中聲明游標(biāo)。
2.打開(kāi)光標(biāo)。
3.從活動(dòng)集中取出每行,直到該框?yàn)榭铡?br />
4.關(guān)閉光標(biāo)。
OPEN語(yǔ)句執(zhí)行與游標(biāo)相關(guān)的查詢,標(biāo)識(shí)結(jié)果集并將光標(biāo)定位在第一行之前。 FETCH語(yǔ)句檢索當(dāng)前行并將光標(biāo)前進(jìn)到下一行。 當(dāng)最后一行被處理完后,CLOSE語(yǔ)句禁用游標(biāo)。
(1)聲明游標(biāo)的語(yǔ)法
游標(biāo)的活動(dòng)集由游標(biāo)聲明中的SELECT語(yǔ)句確定。句法:
CURSOR cursor_name ISselect_statement;在語(yǔ)法中:
cursor_name是PL / SQL標(biāo)識(shí)符
select_statement是一個(gè)沒(méi)有INTO子句的SELECT語(yǔ)句
(2)聲明游標(biāo)示例1
聲明emp_cursor游標(biāo)以檢索部門(mén)中使用department_id為30的員工的employee_id和last_name列。DECLARECURSOR emp_cursor ISSELECT employee_id, last_name FROM employeesWHERE department_id =30; ...
(3)聲明游標(biāo)示例2
聲明dept_cursor游標(biāo)以檢索具有l(wèi)ocation_id 1700的部門(mén)的所有詳細(xì)信息。您想按department_name的升序序列提取和處理這些行。
DECLARECURSOR dept_cursor ISSELECT * FROM departmentsWHERE location_id = 1700ORDER BY department_name; ...(4)聲明游標(biāo)示例3
游標(biāo)聲明中的SELECT語(yǔ)句可以包含連接,組函數(shù)和子查詢。 此示例檢索每個(gè)至少有兩名員工的部門(mén),并給出部門(mén)名稱和員工人數(shù)。DECLARECURSOR dept_emp_cursor ISSELECT department_name, COUNT(*) AS how_manyFROM departments d, employees eWHERE d.department_id = e.department_idGROUP BY d.department_nameHAVING COUNT(*) > 1; ...
六、聲明游標(biāo)的指南
在聲明游標(biāo)時(shí):?不要在游標(biāo)聲明中包含INTO子句,因?yàn)樗院蟪霈F(xiàn)在FETCH語(yǔ)句中。
?如果需要處理特定順序的行,則在查詢中使用ORDER BY子句。
游標(biāo)可以是任何有效的SELECT語(yǔ)句,包括連接,子查詢等等。
?如果游標(biāo)聲明引用任何PL / SQL變量,則必須在聲明游標(biāo)之前聲明這些變量。
(1)打開(kāi)光標(biāo)
OPEN語(yǔ)句執(zhí)行與游標(biāo)關(guān)聯(lián)的查詢,標(biāo)識(shí)活動(dòng)集并將光標(biāo)指針定位到第一行。 OPEN語(yǔ)句包含在PL / SQL塊的可執(zhí)行部分中。DECLARECURSOR emp_cursor ISSELECT employee_id, last_name FROM employeesWHERE department_id = 30; ... BEGINOPEN emp_cursor; ...OPEN語(yǔ)句執(zhí)行以下操作:
1.為上下文區(qū)域分配內(nèi)存(創(chuàng)建框)
2.在游標(biāo)聲明中執(zhí)行SELECT語(yǔ)句,將結(jié)果返回到活動(dòng)集(用數(shù)據(jù)填充框)
3.將指針定位到活動(dòng)集中的第一行
(2)從光標(biāo)獲取數(shù)據(jù)
FETCH語(yǔ)句一次從光標(biāo)中檢索一行。 每次提取后,光標(biāo)前進(jìn)到活動(dòng)集中的下一行。 兩個(gè)變量v_empno和v_lname被聲明為保存游標(biāo)中的取值。
DECLARECURSOR emp_cursor ISSELECT employee_id, last_name FROM employeesWHERE department_id =10;v_empno employees.employee_id%TYPE;v_lname employees.last_name%TYPE; BEGINOPEN emp_cursor;FETCH emp_cursor INTO v_empno, v_lname;DBMS_OUTPUT.PUT_LINE( v_empno ||' '||v_lname);... END;輸出:
200 Whalen
Statement processed.您已成功將光標(biāo)中的值提取到變量中。 但是,第30部門(mén)有6名員工。只有一行被提取。 要獲取所有行,您必須使用循環(huán)。
輸出:
124 Mourgos
141 Rajs142 Davies
143 Matos
144 Vargas
Statement processed.
(3)從光標(biāo)獲取數(shù)據(jù)的準(zhǔn)則
從光標(biāo)獲取數(shù)據(jù)時(shí)遵循以下準(zhǔn)則:?在FETCH語(yǔ)句的INTO子句中包含與SELECT語(yǔ)句中的列相同數(shù)量的變量,并確保數(shù)據(jù)類型兼容。
?將每個(gè)變量與位置上的列進(jìn)行匹配。?測(cè)試以查看游標(biāo)是否包含行。 如果提取沒(méi)有獲取值,則在活動(dòng)集中沒(méi)有剩余行要處理,并且不記錄錯(cuò)誤。 最后一行被重新處理。
?您可以使用%NOTFOUND游標(biāo)屬性來(lái)測(cè)試退出條件。
從光標(biāo)獲取數(shù)據(jù)示例1
這個(gè)例子有什么問(wèn)題?
DECLARECURSOR emp_cursor ISSELECT employee_id, last_name, salary FROM employeesWHERE department_id =30;v_empno employees.employee_id%TYPE;v_lname employees.last_name%TYPE;v_sal employees.salary%TYPE; BEGINOPEN emp_cursor;LOOPFETCH emp_cursor INTO v_empno, v_lname;EXIT WHEN emp_cursor%NOTFOUND;DBMS_OUTPUT.PUT_LINE( v_empno ||' '||v_lname);END LOOP; … END;從光標(biāo)獲取數(shù)據(jù)示例2部門(mén)10中只有一名員工。執(zhí)行此示例時(shí)會(huì)發(fā)生什么?
DECLARECURSOR emp_cursor ISSELECT employee_id, last_name FROM employeesWHERE department_id =10;v_empno employees.employee_id%TYPE;v_lname employees.last_name%TYPE; BEGINOPEN emp_cursor;LOOPFETCH emp_cursor INTO v_empno, v_lname;DBMS_OUTPUT.PUT_LINE( v_empno ||' '||v_lname);END LOOP; … END;(4)關(guān)閉光標(biāo)
CLOSE語(yǔ)句禁用游標(biāo),釋放上下文區(qū)域,并取消定義活動(dòng)集。 完成FETCH語(yǔ)句處理后關(guān)閉游標(biāo)。 如果需要,您可以稍后重新打開(kāi)游標(biāo)。 把CLOSE想象成關(guān)閉和清空盒子,所以你不能再取出它的內(nèi)容。...LOOPFETCH emp_cursor INTO v_empno, v_lname;EXIT WHEN emp_cursor%NOTFOUND;DBMS_OUTPUT.PUT_LINE( v_empno ||' '||v_lname);END LOOP; CLOSE emp_cursor; --關(guān)閉游標(biāo) END;關(guān)閉游標(biāo)指南
關(guān)閉游標(biāo)時(shí)請(qǐng)遵循以下準(zhǔn)則:
?光標(biāo)只有關(guān)閉后才能重新打開(kāi)。 如果您嘗試在游標(biāo)關(guān)閉后從游標(biāo)讀取數(shù)據(jù),則會(huì)引發(fā)INVALID_CURSOR異常。
?如果稍后重新打開(kāi)游標(biāo),將重新執(zhí)行關(guān)聯(lián)的SELECT語(yǔ)句,以使用來(lái)自數(shù)據(jù)庫(kù)的最新數(shù)據(jù)重新填充上下文區(qū)域。
七、把它放在一起
以下示例聲明并處理游標(biāo)以獲取亞洲國(guó)家的國(guó)家名稱和國(guó)家法定節(jié)假日。DECLARECURSOR wf_holiday_cursor ISSELECT country_name, national_holiday_dateFROM wf_countries where region_id IN(30,34,35);v_country_name wf_countries.country_name%TYPE;v_holiday wf_countries.national_holiday_date%TYPE; BEGINOPEN wf_holiday_cursor;LOOPFETCH wf_holiday_cursor INTO v_country_name, v_holiday;EXIT WHEN wf_holiday_cursor%NOTFOUND;DBMS_OUTPUT.PUT_LINE(v_country_name||' '||v_holiday);END LOOP;CLOSE wf_holiday_cursor; END;
總結(jié)
以上是生活随笔為你收集整理的Oracle入门(十四.10)之显式游标简介的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 抖音收藏怎么看不到是谁收藏的
- 下一篇: Oracle入门(十四.11)之使用显式