遊標是SQL的壹個內存工作區,由系統或用戶以變量的形式定義。遊標的作用就是用於臨時存儲從數據庫中提取的數據塊。Oracle數據庫的Cursor類型包含三種: 靜態遊標:分為顯式(explicit)遊標和隱式(implicit)遊標;REF遊標:是壹種引用類型,類似於指針。下面我們壹壹介紹它們的使用。
1.隱式遊標
1)Select …INTO…語句,DML語句,使用隱式Cursor。此外,還有壹種使用FOR LOOP的Implicit Cursor用法。
2)可以通過隱式Cusor的屬性來了解操作的狀態和結果。Cursor的屬性包含:
SQL%ROWCOUNT 整型代表DML語句成功執行的數據行數。
SQL%FOUND 布爾型值為TRUE代表插入、刪除、更新或單行查詢操作成功。
SQL%NOTFOUND 布爾型與SQL%FOUND屬性返回值相反。
SQL%ISOPEN 布爾型DML執行過程中為真,結束後為假。
3) 隱式Cursor由系統自動打開和關閉.
例如:
setserveroutputon
declare
begin
updateemployeessetemployee_name='Mike'whereemployee_id=1001;
ifSQL%FOUNDthen
dbms_output.put_line('Nameisupdated');
else
dbms_output.put_line('Nameisnotupdated');
endif;
end;
/
setserveroutputon
declare
begin
fortableInfoin(select*fromuser_tables)loop
dbms_output.put_line(tableInfo.table_name);
endloop;
exception
whenothersthen
dbms_output.put_line(sqlerrm);
end;
/
2.顯式遊標
1) 顯式Cursor的屬性包含:
遊標的屬性 返回值類型 意義
%ROWCOUNT 整型 獲得FETCH語句返回的數據行數
%FOUND 布爾型 最近的FETCH語句返回壹行數據則為真,否則為假
%NOTFOUND 布爾型 與%FOUND屬性返回值相反
%ISOPEN 布爾型 遊標已經打開時值為真,否則為假
2) 對於顯式遊標的運用分為四個步驟:
a 定義遊標---Cursor [Cursor Name] IS;
b 打開遊標---Open [Cursor Name];
c 操作數據---Fetch [Cursor name]
d 關閉遊標---Close [Cursor Name]
以下是幾種常見顯式Cursor用法。
<p>setserveroutputon
declare
cursorcurisselect*fromuser_tables;
tableInfouser_tables%rowtype;
begin
opencur;
loop
fetchcurintotableInfo;
exitwhencur%notfound;
dbms_output.put_line(tableInfo.table_name);
endloop;</p><p>exception
whenothersthen
dbms_output.put_line(sqlerrm);</p><p>closecur;
end;
/</p>
setserveroutputon
declare
cursorcurisselect*fromuser_tables;
begin
fortableInfoincurloop
dbms_output.put_line(tableInfo.table_name);
endloop;
exception
whenothersthen
dbms_output.put_line(sqlerrm);
end;
/
還可以使用帶參數open的cursor。
<p>setserveroutputon
declare
cursorcur(tblNamevarchar2)isselect*fromuser_constraintswheretable_name=tblName;
tableInfouser_constraints%rowtype;
begin
opencur('EMPLOYEES');
loop
fetchcurintotableInfo;
exitwhencur%notfound;
dbms_output.put_line(tableInfo.constraint_name);
endloop;</p><p>exception
whenothersthen
dbms_output.put_line(sqlerrm);</p><p>closecur;
end;
/</p><p></p>
setserveroutputon
declare
cursorcur(tblNamevarchar2)isselect*fromuser_constraintswheretable_name=tblName;
begin
fortableInfoincur('EMPLOYEES')loop
dbms_output.put_line(tableInfo.constraint_name);
endloop;
exception
whenothersthen
dbms_output.put_line(sqlerrm);
end
/
可以使用WHERE CURRENT OF子句執行UPDATE或DELETE操作。
setserveroutputon
declare
cursorcurisselect*fromemployeesforupdate;
begin
fortableInfoincurloop
updateemployeessetsalarysalary=salary*1.1wherecurrentofcur;
endloop;
commit;
exception
whenothersthen
dbms_output.put_line(sqlerrm);
end;
/
3.REF CURSOR(Cursor Variables)
REF Cursor在運行的時候才能確定遊標使用的查詢。利用REF CURSOR,可以在程序間傳遞結果集(壹個程序裏打開遊標變量,在另外的程序裏處理數據)。
也可以利用REF CURSOR實現BULK SQL,提高SQL性能。
REF CURSOR分兩種,Strong REF CURSOR 和 Weak REF CURSOR。
Strong REF CURSOR:指定retrun type,CURSOR變量的類型必須和return type壹致。
Weak REF CURSOR:不指定return type,能和任何類型的CURSOR變量匹配。
Ref cursor的使用:
1) Type [Cursor type name] is ref cursor
2) Open cursor for...
3) Fetch [Cursor name]
4) Close Cursor
例如:
Step1:
createorreplacepackageTESTas
typeemployees_refcursor_typeisrefcursorreturnemployees%rowtype;
procedureemployees_loop(employees_curINemployees_refcursor_type);
endTEST;
/
Step2:
createorreplacepackagebodyTESTas
procedureemployees_loop(employees_curINemployees_refcursor_type)is
empemployees%rowtype;
begin
loop
fetchemployees_curintoemp;
exitwhenemployees_cur%NOTFOUND;
dbms_output.put_line(emp.employee_id);
endloop;
endemployees_loop;
endTEST;
/
Step3:
setserveroutputon
declare
empRefCurTEST.employees_refcursor_type;
begin
foriin10..20loop
dbms_output.put_line('DepartmentID='||i);
openempRefCurforselect*fromemployeeswheredepartment_id=i;
TEST.employees_loop(empRefCur);
endloop;
exception
whenothersthen
dbms_output.put_line(sqlerrm);
closeempRefCur;
end;
/
4.BULK SQL
使用FORALL和BULK COLLECT子句。利用BULK SQL可以減少PLSQL Engine和SQL Engine之間的通信開銷,提高性能。
1. To speed up INSERT, UPDATE, and DELETE statements, enclose the SQL statement within a PL/SQL FORALL statement instead of a loop construct. 加速INSERT, UPDATE, DELETE語句的執行,也就是用FORALL語句來替代循環語句。
2. To speed up SELECT statements, include the BULK COLLECT INTO clause in the SELECT statement instead of using INTO. 加速SELECT,用BULK COLLECT INTO 來替代INTO。
SQL>createtableemployees_tmpasselectfirst_name,last_name,salaryfromemployeeswhere0=1;
setserveroutputon
declare
cursoremployees_cur(depIdemployees.department_id%type)isselectfirst_name,last_name,salaryfromemployeeswheredepartment_id=depId;
typeemployee_table_typeistableofemployees_cur%rowtypeindexbypls_integer;
employee_tableemployee_table_type;
begin
openemployees_cur(100);
fetchemployees_curbulkcollectintoemployee_table;
closeemployees_cur;
foriin1..employee_table.countloop
dbms_output.put_line(employee_table(i).first_name||''||employee_table(i).last_name||','||employee_table(i).salary);
endloop;
foralliinemployee_table.first..employee_table.last
insertintoemployees_tmpvalues(employee_table(i).first_name,employee_table(i).last_name,employee_table(i).salary);
commit;
end;
/