PL/SQL中游標(biāo)和游標(biāo)變量的使用(轉(zhuǎn))
游標(biāo)是什么:
??? 游標(biāo)字面理解就是游動的光標(biāo)。
??? 用數(shù)據(jù)庫語言來描述:游標(biāo)是映射在結(jié)果集中一行數(shù)據(jù)上的位置實體,有了游標(biāo)用戶就可以訪問結(jié)果集中的任意一行數(shù)據(jù)了,將游標(biāo)放置到某行后,即可對該行數(shù)據(jù)進行操作,例如提取當(dāng)前行的數(shù)據(jù)等等。
游標(biāo)的分類: 顯式游標(biāo)和隱式游標(biāo)
(1)、顯示游標(biāo)的使用:
??? 1.聲明游標(biāo)
CURSOR mycur(vartype number) is
select emp_no,emp_zc from cus_emp_basic
where com_no = vartype;
??? 2.打開游標(biāo)
open mycur(000627) 注:000627:參數(shù)
??? 3.讀取數(shù)據(jù)
fetch mycur into varno,varprice;
??? 4.關(guān)閉游標(biāo)
close mycur;
游標(biāo)的屬性
??? oracle 游標(biāo)有4個屬性: %ISOPEN , %FOUND , %NOTFOUND, %ROWCOUNT
??? %ISOPEN 判斷游標(biāo)是否被打開,如果打開%ISOPEN 等于true,否則等于false
??? %FOUND %NOTFOUND 判斷游標(biāo)所在的行是否有效,如果有效,則%FOUNDD等于true,否則等于false
??? %ROWCOUNT 返回當(dāng)前位置為止游標(biāo)讀取的記錄行數(shù)。
??? 示例:
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;
(2)、隱式游標(biāo)的使用:
如果在pl/sql程序中使用了select語句進行操作,pl/sql會隱含處理游標(biāo)定義,即稱做隱式游標(biāo)。這種游標(biāo)不需要聲明、打開和關(guān)閉。
例:
Create or replace procedure cx_xm
(in_xh in char,out_num out char)
As
Begin
?????? Select xm into out_xm from xs where xh=in_xh;?? /*隱式游標(biāo)必須使用into*/
??? Dbms_output.put_line(out_xm);
End
使用隱式游標(biāo)時要注意以下幾點:
A、每一個隱式游標(biāo)必須有一個into;
B、和顯示游標(biāo)一樣,帶有關(guān)鍵字into接收數(shù)據(jù)的變量時數(shù)據(jù)類型要與列表一致。
C、隱式游標(biāo)一次只能返回移行數(shù)據(jù)。
典型游標(biāo)for 循環(huán)
游標(biāo)for循環(huán)和顯示游標(biāo)的一種快捷使用方式,它使用for循環(huán)依次讀取結(jié)果集中的行數(shù)據(jù),當(dāng)for循環(huán)開始時,游標(biāo)自動打開(不需要 open),每循環(huán)一次系統(tǒng)自動讀取游標(biāo)當(dāng)前行的數(shù)據(jù)(不需要fetch),當(dāng)退出for循環(huán)時,游標(biāo)被自動關(guān)閉(不需要使用close)使用游標(biāo)for 循環(huán)的時候不能使用open語句,fetch語句和close語句,否則會產(chǎn)生錯誤。
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;
在游標(biāo)FOR循環(huán)中使用查詢
在游標(biāo)FOR循環(huán)中可以定義查詢,由于沒有顯式聲明所以游標(biāo)沒有名字,記錄名通過游標(biāo)查詢來定義。
DECALRE
v_tot_salary EMP.SALARY%TYPE;
BEGIN
FOR r_dept IN (SELECT deptno,dname FROM dept ORDER BY deptno) LOOP
DBMS_OUTPUT.PUT_LINE('Department:'|| r_dept.deptno||'-'||r_dept.dname);
v_tot_salary:=0;
FOR r_emp IN (SELECT ename,salary
FROM emp
WHERE deptno=p_dept
ORDER BY ename) LOOP
DBMS_OUTPUT.PUT_LINE('Name:'|| v_ename||' salary:'||v_salary);
v_tot_salary:=v_tot_salary+v_salary;
END LOOP;
DBMS_OUTPUT.PUT_LINE('Toltal Salary for dept:'|| v_tot_salary);
END LOOP;
END;
游標(biāo)中的子查詢
語法如下:
CURSOR C1 IS SELECT * FROM emp
WHERE deptno NOT IN (SELECT deptno
FROM dept
WHERE dname!='ACCOUNTING');
可以看出與SQL中的子查詢沒有什么區(qū)別。
游標(biāo)中的更新和刪除
在PL/SQL中依然可以使用UPDATE和DELETE語句更新或刪除數(shù)據(jù)行。顯式游標(biāo)只有在需要獲得多行數(shù)據(jù)的情況下使用。PL/SQL提供了僅僅使用游標(biāo)就可以執(zhí)行刪除或更新記錄的方法。
UPDATE或DELETE語句中的WHERE CURRENT OF子串專門處理要執(zhí)行UPDATE或DELETE操作的表中取出的最近的數(shù)據(jù)。要使用這個方法,在聲明游標(biāo)時必須使用FOR UPDATE子串,當(dāng)對話使用FOR UPDATE子串打開一個游標(biāo)時,所有返回集中的數(shù)據(jù)行都將處于行級(ROW-LEVEL)獨占式鎖定,其他對象只能查詢這些數(shù)據(jù)行,不能進行 UPDATE、DELETE或SELECT...FOR UPDATE操作。
語法:
FOR UPDATE [OF [schema.]table.column[,[schema.]table.column]..
[nowait]
在多表查詢中,使用OF子句來鎖定特定的表,如果忽略了OF子句,那么所有表中選擇的數(shù)據(jù)行都將被鎖定。如果這些數(shù)據(jù)行已經(jīng)被其他會話鎖定,那么正常情況下ORACLE將等待,直到數(shù)據(jù)行解鎖。
在UPDATE和DELETE中使用WHERE CURRENT OF子串的語法如下:
WHERE{CURRENT OF cursor_name|search_condition}
例:
DELCARE
CURSOR c1 IS SELECT empno,salary
FROM emp
WHERE comm IS NULL
FOR UPDATE OF comm;
v_comm NUMBER(10,2);
BEGIN
FOR r1 IN c1 LOOP
IF r1.salary<500 THEN
v_comm:=r1.salary*0.25;
ELSEIF r1.salary<1000 THEN
v_comm:=r1.salary*0.20;
ELSEIF r1.salary<3000 THEN
v_comm:=r1.salary*0.15;
ELSE
v_comm:=r1.salary*0.12;
END IF;
UPDATE emp;
SET comm=v_comm
WHERE CURRENT OF c1l;
END LOOP;
END
使用游標(biāo)變量:
與游標(biāo)類似,游標(biāo)變量指向多行查詢的結(jié)果集的當(dāng)前行。但是,游標(biāo)與游標(biāo)變量是不同的,就像常量和變量的關(guān)系一樣。游標(biāo)是靜態(tài)的,游標(biāo)變量是動態(tài)的,因為它不與特定的查詢綁定在一起。
(1)、用法1:
declare
type cur_tab is ref cursor;
sqlcur cur_tab;
v_T3100101 char(2);
v_T3100102 char(10);
begin
open sqlcur for select T3100101,T3100102 from T31001;
loop
fetch sqlcur into v_T3100101,v_T3100102;
exit when sqlcur%notfound;
dbms_output.put_line(v_T3100101||v_T3100102);
end loop;
close sqlcur;
end;
(2)、用法2:用于存儲過程返回結(jié)果集
create or replace package selecttable
is
type cur_T31001 is ref cursor return T31001%rowtype; --注意,這里沒有begin
end selecttable;
create or replace procedure T31001_select
(
cur out selecttable.cur_T31001?????? --參數(shù)類型定義為先前定義好的T31001
)
is
begin
open cur for
select * from T31001;
end T31001_select;
----------------------------------------------------------------------------------------------------------------------
通過從游標(biāo)工作區(qū)中抽取出來的數(shù)據(jù),可以對數(shù)據(jù)庫中的數(shù)據(jù)進行操縱,包括修改與刪除操作。
要想通過游標(biāo)操縱數(shù)據(jù)庫,在定義游標(biāo)的時候,必須加上FOR UPDATE OF子句;
而且在UPDATE或DELETE時,必須加上WHERE CURRENT OF子句,則游標(biāo)所在行被更新或者刪除。
??? 游標(biāo)字面理解就是游動的光標(biāo)。
??? 用數(shù)據(jù)庫語言來描述:游標(biāo)是映射在結(jié)果集中一行數(shù)據(jù)上的位置實體,有了游標(biāo)用戶就可以訪問結(jié)果集中的任意一行數(shù)據(jù)了,將游標(biāo)放置到某行后,即可對該行數(shù)據(jù)進行操作,例如提取當(dāng)前行的數(shù)據(jù)等等。
游標(biāo)的分類: 顯式游標(biāo)和隱式游標(biāo)
(1)、顯示游標(biāo)的使用:
??? 1.聲明游標(biāo)
CURSOR mycur(vartype number) is
select emp_no,emp_zc from cus_emp_basic
where com_no = vartype;
??? 2.打開游標(biāo)
open mycur(000627) 注:000627:參數(shù)
??? 3.讀取數(shù)據(jù)
fetch mycur into varno,varprice;
??? 4.關(guān)閉游標(biāo)
close mycur;
游標(biāo)的屬性
??? oracle 游標(biāo)有4個屬性: %ISOPEN , %FOUND , %NOTFOUND, %ROWCOUNT
??? %ISOPEN 判斷游標(biāo)是否被打開,如果打開%ISOPEN 等于true,否則等于false
??? %FOUND %NOTFOUND 判斷游標(biāo)所在的行是否有效,如果有效,則%FOUNDD等于true,否則等于false
??? %ROWCOUNT 返回當(dāng)前位置為止游標(biāo)讀取的記錄行數(shù)。
??? 示例:
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;
(2)、隱式游標(biāo)的使用:
如果在pl/sql程序中使用了select語句進行操作,pl/sql會隱含處理游標(biāo)定義,即稱做隱式游標(biāo)。這種游標(biāo)不需要聲明、打開和關(guān)閉。
例:
Create or replace procedure cx_xm
(in_xh in char,out_num out char)
As
Begin
?????? Select xm into out_xm from xs where xh=in_xh;?? /*隱式游標(biāo)必須使用into*/
??? Dbms_output.put_line(out_xm);
End
使用隱式游標(biāo)時要注意以下幾點:
A、每一個隱式游標(biāo)必須有一個into;
B、和顯示游標(biāo)一樣,帶有關(guān)鍵字into接收數(shù)據(jù)的變量時數(shù)據(jù)類型要與列表一致。
C、隱式游標(biāo)一次只能返回移行數(shù)據(jù)。
典型游標(biāo)for 循環(huán)
游標(biāo)for循環(huán)和顯示游標(biāo)的一種快捷使用方式,它使用for循環(huán)依次讀取結(jié)果集中的行數(shù)據(jù),當(dāng)for循環(huán)開始時,游標(biāo)自動打開(不需要 open),每循環(huán)一次系統(tǒng)自動讀取游標(biāo)當(dāng)前行的數(shù)據(jù)(不需要fetch),當(dāng)退出for循環(huán)時,游標(biāo)被自動關(guān)閉(不需要使用close)使用游標(biāo)for 循環(huán)的時候不能使用open語句,fetch語句和close語句,否則會產(chǎn)生錯誤。
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;
在游標(biāo)FOR循環(huán)中使用查詢
在游標(biāo)FOR循環(huán)中可以定義查詢,由于沒有顯式聲明所以游標(biāo)沒有名字,記錄名通過游標(biāo)查詢來定義。
DECALRE
v_tot_salary EMP.SALARY%TYPE;
BEGIN
FOR r_dept IN (SELECT deptno,dname FROM dept ORDER BY deptno) LOOP
DBMS_OUTPUT.PUT_LINE('Department:'|| r_dept.deptno||'-'||r_dept.dname);
v_tot_salary:=0;
FOR r_emp IN (SELECT ename,salary
FROM emp
WHERE deptno=p_dept
ORDER BY ename) LOOP
DBMS_OUTPUT.PUT_LINE('Name:'|| v_ename||' salary:'||v_salary);
v_tot_salary:=v_tot_salary+v_salary;
END LOOP;
DBMS_OUTPUT.PUT_LINE('Toltal Salary for dept:'|| v_tot_salary);
END LOOP;
END;
游標(biāo)中的子查詢
語法如下:
CURSOR C1 IS SELECT * FROM emp
WHERE deptno NOT IN (SELECT deptno
FROM dept
WHERE dname!='ACCOUNTING');
可以看出與SQL中的子查詢沒有什么區(qū)別。
游標(biāo)中的更新和刪除
在PL/SQL中依然可以使用UPDATE和DELETE語句更新或刪除數(shù)據(jù)行。顯式游標(biāo)只有在需要獲得多行數(shù)據(jù)的情況下使用。PL/SQL提供了僅僅使用游標(biāo)就可以執(zhí)行刪除或更新記錄的方法。
UPDATE或DELETE語句中的WHERE CURRENT OF子串專門處理要執(zhí)行UPDATE或DELETE操作的表中取出的最近的數(shù)據(jù)。要使用這個方法,在聲明游標(biāo)時必須使用FOR UPDATE子串,當(dāng)對話使用FOR UPDATE子串打開一個游標(biāo)時,所有返回集中的數(shù)據(jù)行都將處于行級(ROW-LEVEL)獨占式鎖定,其他對象只能查詢這些數(shù)據(jù)行,不能進行 UPDATE、DELETE或SELECT...FOR UPDATE操作。
語法:
FOR UPDATE [OF [schema.]table.column[,[schema.]table.column]..
[nowait]
在多表查詢中,使用OF子句來鎖定特定的表,如果忽略了OF子句,那么所有表中選擇的數(shù)據(jù)行都將被鎖定。如果這些數(shù)據(jù)行已經(jīng)被其他會話鎖定,那么正常情況下ORACLE將等待,直到數(shù)據(jù)行解鎖。
在UPDATE和DELETE中使用WHERE CURRENT OF子串的語法如下:
WHERE{CURRENT OF cursor_name|search_condition}
例:
DELCARE
CURSOR c1 IS SELECT empno,salary
FROM emp
WHERE comm IS NULL
FOR UPDATE OF comm;
v_comm NUMBER(10,2);
BEGIN
FOR r1 IN c1 LOOP
IF r1.salary<500 THEN
v_comm:=r1.salary*0.25;
ELSEIF r1.salary<1000 THEN
v_comm:=r1.salary*0.20;
ELSEIF r1.salary<3000 THEN
v_comm:=r1.salary*0.15;
ELSE
v_comm:=r1.salary*0.12;
END IF;
UPDATE emp;
SET comm=v_comm
WHERE CURRENT OF c1l;
END LOOP;
END
使用游標(biāo)變量:
與游標(biāo)類似,游標(biāo)變量指向多行查詢的結(jié)果集的當(dāng)前行。但是,游標(biāo)與游標(biāo)變量是不同的,就像常量和變量的關(guān)系一樣。游標(biāo)是靜態(tài)的,游標(biāo)變量是動態(tài)的,因為它不與特定的查詢綁定在一起。
(1)、用法1:
declare
type cur_tab is ref cursor;
sqlcur cur_tab;
v_T3100101 char(2);
v_T3100102 char(10);
begin
open sqlcur for select T3100101,T3100102 from T31001;
loop
fetch sqlcur into v_T3100101,v_T3100102;
exit when sqlcur%notfound;
dbms_output.put_line(v_T3100101||v_T3100102);
end loop;
close sqlcur;
end;
(2)、用法2:用于存儲過程返回結(jié)果集
create or replace package selecttable
is
type cur_T31001 is ref cursor return T31001%rowtype; --注意,這里沒有begin
end selecttable;
create or replace procedure T31001_select
(
cur out selecttable.cur_T31001?????? --參數(shù)類型定義為先前定義好的T31001
)
is
begin
open cur for
select * from T31001;
end T31001_select;
----------------------------------------------------------------------------------------------------------------------
通過從游標(biāo)工作區(qū)中抽取出來的數(shù)據(jù),可以對數(shù)據(jù)庫中的數(shù)據(jù)進行操縱,包括修改與刪除操作。
要想通過游標(biāo)操縱數(shù)據(jù)庫,在定義游標(biāo)的時候,必須加上FOR UPDATE OF子句;
而且在UPDATE或DELETE時,必須加上WHERE CURRENT OF子句,則游標(biāo)所在行被更新或者刪除。
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
