一 遊標是什麼
遊標字面理解就是遊動的光標。
用數據庫語言來描述:遊標是映射在結果集中一行數據上的位置實體,有了遊標,用戶就可以訪問結果集中的任意一行數據了,將遊標放置到某行後,即可對該行數據進行操作,例如提取當前行的數據等。
二 遊標的分類
顯式遊標和隱式遊標
顯式遊標的使用需要4步:
1. 聲明遊標
CURSOR mycur(vartype number) is
select emp_no,emp_zc from cus_emp_basic
where com_no = vartype;
2. 打開遊標
open mycur(000627)
注:000627是參數
3. 讀取數據
fetch mycur into varno, varprice;
4. 關閉遊標
close mycur;
三 遊標的屬性
oracle 遊標有4個屬性:%ISOPEN,%FOUND,%NOTFOUND,%ROWCOUNT。
%ISOPEN判斷遊標是否被打開,如果打開%ISOPEN等於true,否則等於false;
%FOUND %NOTFOUND判斷遊標所在的行是否有效,如果有效,則%FOUNDD等於true,否則等於false;
%ROWCOUNT返回當前位置爲止遊標讀取的記錄行數。
四 示例
set serveroutput on;
declare
varno varchar2(20);
varprice varchar2(20);
CURSOR mycur(vartype number) is
select emp_no,emp_zc from cus_emp_basic
where com_no = vartype;
begin
if mycur%isopen = false then
open mycur(000627);
end if;
fetch mycur into varno,varprice;
while mycur%found
loop
dbms_output.put_line(varno||','||varprice);
if mycur%rowcount=2 then
exit;
end if;
fetch mycur into varno,varprice;
end loop;
close mycur;
end;
PL/SQL記錄的結構和C語言中的結構體類似,是由一組數據項構成的邏輯單元。
PL/SQL記錄並不保存在數據庫中,它與變量一樣,保存在內存空間中,在使用記錄時候,要首先定義記錄結構,然後聲明記錄變量。可以把PL/SQL記錄看作是一個用戶自定義的數據類型。
set serveroutput on;
declare
type person is record
(
empno cus_emp_basic.emp_no%type,
empzc cus_emp_basic.emp_zc%type);
person1 person;
cursor mycur(vartype number)is
select emp_no,emp_zc from cus_emp_basic
where com_no=vartype;
begin
if mycur%isopen = false then
open mycur(000627);
end if;
loop
fetch mycur into person1;
exit when mycur%notfound;
dbms_output.put_line('僱員編號:'||person1.empno||',地址:'||person1.empzc);
end loop;
close mycur;
end;
典型遊標for 循環
遊標for循環示顯示遊標的一種快捷使用方式,它使用for循環依次讀取結果集中的行數據,當form循環開始時,遊標自動打開(不需要open),每循環一次系統自動讀取遊標當前行的數據(不需要fetch),當退出for循環時,遊標被自動關閉(不需要使用close)。使用遊標for循環的時候不能使用open語句,fetch語句和close語句,否則會產生錯誤。
set serveroutput on;
declare
cursor mycur(vartype number)is
select emp_no,emp_zc from cus_emp_basic
where com_no=vartype;
begin
for person in mycur(000627) loop
dbms_output.put_line('僱員編號:'||person.emp_no||',地址:'||person.emp_zc);
end loop;
end;
==================================================================================
實例:
FROM Rs_Employees
Where HeTongId = ' WL-090001 ' ;
if sql % Notfound then
Dbms_Output.put_line( ' 沒有找到要刪除的記錄 ' );
else
Dbms_Output.put_line( ' 已刪除記錄 ' );
end if ;
END ;
-- 例七:%RowCount,查詢記錄行數
Declare
v_name Rs_Employees.Name % type;
BEGIN
SELECT Name Into v_Name
FROM Rs_Employees
Where HeTongId = ' WL-090010 ' ;
if sql % RowCount > 0 Then
Dbms_Output.put_line( ' 已從表中選擇行,Name爲: ' || v_Name);
else
Dbms_Output.put_line( ' 從表中未選擇行 ' );
end if ;
END ;
-- 再演示以下代碼
BEGIN
DELETE FROM Rs_Employees
Where HeTongId <= ' WL-090010 ' ;
Dbms_Output.put_line( ' 已從表中刪除 ' || To_Char(sql % RowCount ) || ' 條記錄 ' );
END ;
-- 例八:顯式遊標
-- 以下示例在所有遊標的記錄中的Name字段中加一字串
-- 同時在此示範瞭如何使用%NotFound屬性
-- set serveroutput on;
Declare
v_Id Rs_Employees.Hetongid % type;
v_name Rs_Employees.Name % type;
v_Count Number : = 0 ;
Cursor MyCur Is
SELECT HetongId,Name FROM Rs_Employees
Where HeTongId <= ' WL-090010 ' ;
BEGIN
-- 打開遊標
Open MyCur;
-- 進入循環
Loop
Fetch MyCur Into v_id,v_name;
Exit When MyCur % NotFound;
Update Rs_Employees
Set Name = Name || ' X '
Where HeTongId = v_Id;
v_Count : = v_Count + 1 ;
End Loop;
Dbms_Output.put_line( ' 已更新 ' || v_Count || ' 行 ' );
END ;
-- 例10:以下示範%RowCount和%IsOpen,同時示範了%RowType的使用
-- 例10:以下示例%RowCount
Declare
v_Row Rs_Employees % RowType;
Cursor MyCur Is
SELECT * FROM Rs_Employees
Where HeTongId <= ' WL-090010 ' ;
BEGIN
if Not MyCur % IsOpen then
Dbms_Output.put_line( ' 遊標未打開 ' );
-- 打開遊標
Open MyCur;
end if ;
-- 進入循環
Loop
Fetch MyCur Into v_row;
Exit When MyCur % NotFound;
Dbms_Output.put_line( ' 當前已取得 ' || MyCur % RowCount || ' 行 ' );
Dbms_Output.put_line( ' 姓名: ' || v_row.Name || ' ' || ' 合同號: ' || v_row.HeTongId);
Dbms_Output.put_line( '' );
End Loop;
Dbms_Output.put_line( ' 總共已取得 ' || MyCur % RowCount || ' 行 ' );
if MyCur % IsOpen then
Dbms_Output.put_line( ' 遊標已打開 ' );
Close MyCur;
end if ;
if Not MyCur % IsOpen then
Dbms_Output.put_line( ' 遊標已關閉 ' );
end if ;
END ;
-- 例12:查詢嵌套表中數據的遊標
-- 1 創建類型
CREATE OR REPLACE TYPE emp_type As Object
(eno number ,
ename varchar2 ( 20 ),
esal number );
-- 2 使用Table of 子句創建Table類型
CREATE TYPE emp_nt AS Table Of emp_type;
-- 3 使用emp_nt數據類型創建myemp表
CREATE TABLE myemp
(deptno number ,
edet emp_nt)
NESTED TABLE edet Store As myemployee;
-- 4 初始化myemp的數據
Insert Into myemp values
( 10 ,emp_nt(emp_type( 1000 , ' James ' , 10000 ),
emp_type( 1001 , ' Daniel ' , 20000 )));
Commit ;
-- 執行下列代碼
Declare
sal number ;
ena varchar2 ( 20 );
Cursor MyCur Is
SELECT a.esal,a.ename
FROM the
( Select edet From myemp
Where deptno = 10 ) a;
BEGIN
-- 打開遊標
Open MyCur;
-- 進入循環
Loop
Fetch MyCur Into sal,ena;
Exit When MyCur % NotFound;
Dbms_Output.put_line(ena || ' ' || sal);
End Loop;
Close MyCur;
END ;
-- 例13:此例改自例10,示範循環遊標的用法
Declare
Cursor MyCur Is
SELECT * FROM Rs_Employees
Where HeTongId <= ' WL-090010 ' ;
BEGIN
For tmp_cur In MyCur
Loop
Dbms_Output.put_line( ' 當前已取得 ' || MyCur % RowCount || ' 行 ' );
Dbms_Output.put_line( ' 姓名: ' || tmp_cur.Name || ' ' || ' 合同號: ' || tmp_cur.HeTongId);
End Loop;
-- 在這種情況下,下面這條語句不能執行
-- Dbms_Output.put_line('當前已取得'||MyCur%RowCount||'行');
END ;
-- 再示範帶參數的遊標
Declare
Cursor MyCur(m_HeTongId Rs_Employees.Hetongid % type) Is
SELECT * FROM Rs_Employees
Where HeTongId <= m_HeTongId;
BEGIN
For tmp_cur In MyCur( ' WL-090020 ' )
Loop
Dbms_Output.put_line( ' 當前已取得 ' || MyCur % RowCount || ' 行 ' );
Dbms_Output.put_line( ' 姓名: ' || tmp_cur.Name || ' ' || ' 合同號: ' || tmp_cur.HeTongId);
End Loop;
-- 在這種情況下,下面這條語句不能執行
-- Dbms_Output.put_line('當前已取得'||MyCur%RowCount||'行');
END ;
-- 再示範以下寫法
-- 在循環遊標中使用查詢
Declare
v_HeTongId Rs_Employees.Hetongid % type;
BEGIN
v_HeTongId : = ' WL-090020 ' ;
For tmp_cur In ( SELECT * FROM Rs_Employees
Where HeTongId <= v_HeTongId)
Loop
Dbms_Output.put_line( ' 姓名: ' || tmp_cur.Name || ' ' || ' 合同號: ' || tmp_cur.HeTongId);
End Loop;
END ;
-- 例15:示範遊標變量
-- 此例要在Command window或Sql Plus中示範,結果會有點區別
-- SET SERVEROUTPUT ON;
Declare
TYPE r1_cur IS REF CURSOR ;
var1 r1_cur;
no varchar2 ( 20 );
v_czy sc_chukudan.czy % type;
v_pid sc_chukudanDetail.Productid % type;
BEGIN
no : = ' &你選擇的 ' ;
IF UPPER (no) = ' MASTER ' then
OPEN var1 For
Select Czy FROM sc_chukudan
Where ChuKuDanId = ' SCKD04020001 ' ;
FETCH var1 into v_Czy;
Dbms_Output.put_line( ' 操作員是: ' || v_czy);
CLOSE var1;
ELSE
OPEN var1 For
Select Productid FROM sc_chukudanDetail
Where ChuKuDanId = ' SCKD04020001 ' ;
LOOP
FETCH var1 into v_pid;
EXIT WHEN var1 % NotFound;
Dbms_Output.put_line( ' 生產通知單ID是: ' || v_pid);
END LOOP;
CLOSE var1;
END IF ;
END ;
-- 例16: 遊標中的更新和刪除
-- 此例改自例8
Declare
-- 當打開此遊標,將鎖住了相關記錄
Cursor MyCur Is
SELECT Name FROM Rs_Employees
Where HeTongId <= ' WL-090010 '
For Update OF Name;
BEGIN
For tmp_cur in MyCur
Loop
Update Rs_Employees
Set Name = Name || ' X '
Where Current of MyCur;
End Loop;
END ;