這是第五章的學(xué)習(xí)筆記,學(xué)習(xí)完第四章的數(shù)據(jù)庫(kù)操作和事務(wù)之后,開(kāi)始要學(xué)習(xí)游標(biāo)的使用了……,希望大家能多給俺一些支持啊!
編程時(shí)使用的工具是PLSQL Developer 7.1.4
隱式游標(biāo)
隱式游標(biāo)的屬性等在第四章筆記中已記錄了一部分
如果要確保屬性指向想要的SQL語(yǔ)句,那么就在SQL語(yǔ)句執(zhí)行后,立即將屬性值保存到一個(gè)本地變量中
用存儲(chǔ)過(guò)程來(lái)實(shí)現(xiàn)這種效果:
先定義一個(gè)存儲(chǔ)過(guò)程remove_from_emp ,用于從雇員中刪除一個(gè)員工
在存儲(chǔ)過(guò)程的參數(shù)中 in 表示輸入,out 表示輸出
- create or replace procedure remove_from_emp(empno_in in employee.empno%type)
- is
- begin
- delete from employee where empno = empno_in;
- dbms_output.put_line('刪除了' || sql%rowcount || '條記錄!');
- end;
- /
-
- create or replace procedure show_emp_count is
- i_count integer;
- i_numfound pls_integer;
- begin
- select count(*) into i_count from employee;
-
- i_numfound := sql%rowcount;
-
-
- remove_from_emp(1);
-
- dbms_output.put_line(i_numfound);
- end;
- /
create or replace procedure remove_from_emp(empno_in in employee.empno%type)
is
begin
delete from employee where empno = empno_in;
dbms_output.put_line('刪除了' || sql%rowcount || '條記錄!');
end;
/
-- 定義一個(gè)存儲(chǔ)過(guò)程來(lái)調(diào)用存儲(chǔ)過(guò)程remove_from_emp,并保存隱式游標(biāo)的屬性值
create or replace procedure show_emp_count is
i_count integer;
i_numfound pls_integer;
begin
select count(*) into i_count from employee;
-- 將屬性值做一個(gè)快照
i_numfound := sql%rowcount;
-- 注意employee表中沒(méi)有編號(hào)為99的員工
-- 調(diào)用存儲(chǔ)過(guò)程remove_from_emp
remove_from_emp(1);
-- 現(xiàn)在可以用前一條語(yǔ)句的屬性值輸出
dbms_output.put_line(i_numfound);
end;
/
顯式游標(biāo)(PL/SQL塊中使用顯示游標(biāo)的本個(gè)步驟:聲明、打開(kāi)、提取記錄、關(guān)閉)
在程序包規(guī)范中聲明一個(gè)游標(biāo)類型(我們可以在PL/SQL塊或者包的定義部分聲明游標(biāo)類型)
- create or replace package types
- is
- type emp_cur5 is ref cursor;
- end;
- /
- declare
-
- cursor emp_cur1 is select * from employee;
-
- cursor emp_cur2 (empno_in in number) is select name,hiredate from employee where empno = empno_in;
-
- cursor emp_cur3 return employee%rowtype is select * from employee where empno = 1;
create or replace package types
is
type emp_cur5 is ref cursor;
end;
/
declare
-- 定義一個(gè)不帶參數(shù)的游標(biāo)emp_cur1,游標(biāo)的結(jié)果是employee表中員工的集合
cursor emp_cur1 is select * from employee;
-- 定義一個(gè)帶參數(shù)的游標(biāo)emp_cur2,游標(biāo)的結(jié)果集是匹配由游標(biāo)傳遞過(guò)來(lái)的員工編號(hào)的員工姓名和加入公司的時(shí)間
cursor emp_cur2 (empno_in in number) is select name,hiredate from employee where empno = empno_in;
-- 定義一個(gè)帶有return 子句的游標(biāo),游標(biāo)的結(jié)果集是員工編號(hào)為1的employee表中所有的列
cursor emp_cur3 return employee%rowtype is select * from employee where empno = 1;
如果想通過(guò)游標(biāo)更新數(shù)據(jù),必須在select 語(yǔ)句后加上for update 子句,
該select 語(yǔ)句涉及的所有行都會(huì)被鎖住
如果是加上了for update of 列名,那么只有在for update 子句中引用了某個(gè)表的列時(shí),
該表中的行才會(huì)被鎖住,of 列表并不限制只能更改列給出的列,它只讓我們知道要更改什么
可以在for update 子句后添加一個(gè)nowait 關(guān)鍵字,用于告訴Oracle如果表已經(jīng)被其他用戶
鎖住,就不需要等待了,這樣控制權(quán)會(huì)立即返回給我們的程序,如果沒(méi)有nowait子句進(jìn)程就
會(huì)阻塞,直到表可用(commit或rollback)為止
可以在Select into、Fetch into、Returning into子句中使用Bulk Collect將數(shù)據(jù)輸出到集合中
- cursor emp_cur4 (empno_in in number) is select name,salary from employee where empno = empno_in for update;
-
- emp_row1 employee%rowtype;
-
- emp_row2 emp_cur2%rowtype;
- emp_row3 emp_cur3%rowtype;
- emp_row4 emp_cur4%rowtype;
- n_salary number(10,2);
- n_empno employee.empno%type := &員工編號(hào):;
-
-
-
-
- type emp_ref_type1 is ref cursor return employee%rowtype;
-
- type emp_ref_type2 is ref cursor;
-
- emp_ref1 emp_ref_type1;
- emp_ref2 emp_ref_type2;
-
-
- sys_cursor sys_refcursor;
-
- type emp_table_type is table of employee%rowtype index by binary_integer;
- emp_table emp_table_type;
- type emp_info_type is record(name employee.name%type,job employee.job%type);
- emp_info emp_info_type;
- begin
cursor emp_cur4 (empno_in in number) is select name,salary from employee where empno = empno_in for update;
-- 應(yīng)該總是將游標(biāo)行提取到用%rowtype定義的記錄中,這樣更靈活(表字段改變了不需要更改fetch語(yǔ)句)
emp_row1 employee%rowtype;
-- 基于游標(biāo)定義一個(gè)記錄
emp_row2 emp_cur2%rowtype;
emp_row3 emp_cur3%rowtype;
emp_row4 emp_cur4%rowtype;
n_salary number(10,2);
n_empno employee.empno%type := &員工編號(hào):;
-- 游標(biāo)變量和ref cursor
-- 定義ref cursor 類型的游標(biāo)變量
-- 創(chuàng)建一個(gè)強(qiáng)類型的引用游標(biāo)類型
type emp_ref_type1 is ref cursor return employee%rowtype;
-- 創(chuàng)建一個(gè)弱類型的引用游標(biāo)類型(弱類型的游標(biāo)變量比強(qiáng)類型的游標(biāo)變量更靈活)
type emp_ref_type2 is ref cursor;
-- 定義實(shí)際的游標(biāo)變量
emp_ref1 emp_ref_type1;
emp_ref2 emp_ref_type2;
-- 從Oracle9i 開(kāi)始提供了一個(gè)名為sys_refcursor的預(yù)定義的Oracle系統(tǒng)游標(biāo),
-- 它相當(dāng)于弱類型游標(biāo),使用它不需要定義游標(biāo)變量
sys_cursor sys_refcursor;
-- 定義一個(gè)行類型的集合
type emp_table_type is table of employee%rowtype index by binary_integer;
emp_table emp_table_type;
type emp_info_type is record(name employee.name%type,job employee.job%type);
emp_info emp_info_type;
begin
打開(kāi)游標(biāo):open 顯式游標(biāo)名 (參數(shù)列表)
一旦打開(kāi)了顯式游標(biāo),就可以從游標(biāo)中提取記錄,直到?jīng)]有記錄留在游標(biāo)中
打開(kāi)游標(biāo)時(shí),PL/SQL就開(kāi)始執(zhí)行該游標(biāo)的Select 查詢,但是實(shí)際上并不返回任何行,
返回行的任務(wù)是由后面的Fetch(讀取)…… into(賦值給)…… 語(yǔ)句完成的:
fetch 游標(biāo)名 into 記錄或變量列表
- open emp_cur1;
-
-
- loop
- fetch emp_cur1 into emp_row1;
- exit when emp_cur1%notfound;
- dbms_output.put_line('員工' || emp_row1.name || '的工資是:' || emp_row1.salary);
- end loop;
-
- close emp_cur1;
-
-
-
- for emp_row2 in emp_cur2(n_empno) loop
- dbms_output.put_line('員工' || emp_row2.name || '加入公司的時(shí)間是 ' || emp_row2.hiredate);
- end loop;
-
- open emp_cur3;
- fetch emp_cur3 into emp_row3;
- if emp_cur3%found then
- dbms_output.put_line('員工' || emp_row3.name || '其職位是' || emp_row3.job || ',加入公司的時(shí)間是 ' || emp_row3.hiredate);
- end if;
- close emp_cur3;
-
- open emp_cur4(n_empno);
- fetch emp_cur4 into emp_row4;
open emp_cur1;
-- 提取記錄
-- 如果游標(biāo)只返回一行可以用if、loop或for來(lái)判斷獲得數(shù)據(jù),如果游標(biāo)返回多行可以用loop或for來(lái)循環(huán)獲得數(shù)據(jù)
loop
fetch emp_cur1 into emp_row1;
exit when emp_cur1%notfound;
dbms_output.put_line('員工' || emp_row1.name || '的工資是:' || emp_row1.salary);
end loop;
-- 關(guān)閉游標(biāo)并釋放資源
close emp_cur1;
-- 打開(kāi)帶參數(shù)的游標(biāo)
-- 游標(biāo)for 循環(huán)能很好的簡(jiǎn)化游標(biāo)的開(kāi)發(fā),我們不再需要聲明記錄,不再需要Open、Fetch和Close語(yǔ)句
-- 也不再需要%found屬性檢測(cè)記錄,一切Oracle隱式的幫我們完成了
for emp_row2 in emp_cur2(n_empno) loop
dbms_output.put_line('員工' || emp_row2.name || '加入公司的時(shí)間是 ' || emp_row2.hiredate);
end loop;
-- 打開(kāi)帶return 子句的游標(biāo)
open emp_cur3;
fetch emp_cur3 into emp_row3;
if emp_cur3%found then
dbms_output.put_line('員工' || emp_row3.name || '其職位是' || emp_row3.job || ',加入公司的時(shí)間是 ' || emp_row3.hiredate);
end if;
close emp_cur3;
-- 打開(kāi)帶for update 子句的游標(biāo),將指定編號(hào)的員工工資增加500元
open emp_cur4(n_empno);
fetch emp_cur4 into emp_row4;
where current of 游標(biāo)名 子句能很容易的修改最近提取的數(shù)據(jù)行(也就是當(dāng)前游標(biāo)指向的位置),
這樣的好處是,如果表表結(jié)構(gòu)發(fā)生了改變,我們只需要更改Select語(yǔ)句的Where子句即可,而不
需要更新每個(gè)SQL語(yǔ)句
- if emp_cur4%found then
- update employee set salary = salary + 500 where current of emp_cur4;
- end if;
- commit;
- n_salary := emp_row4.salary + 500;
- dbms_output.put_line('員工' || emp_row4.name || '原來(lái)的工資是' || emp_row4.salary || '元,增加工資后現(xiàn)在的工資是' || n_salary || '元');
- close emp_cur4;
-
-
- open emp_ref1 for select * from employee order by salary;
-
- fetch emp_ref1 bulk collect into emp_table;
- for i in 1..emp_table.count loop
- dbms_output.put_line(emp_table(i).name || ' 本月工資 ' || emp_table(i).salary);
- end loop;
-
- close emp_ref1;
-
- open emp_ref2 for select name,job from employee;
- loop
- fetch emp_ref2 into emp_info;
- exit when emp_ref2%notfound;
- dbms_output.put_line(emp_info.name || '的工作是 ' || emp_info.job);
- end loop;
- close emp_ref2;
-
- open sys_cursor for select name,hiredate from employee order by hiredate desc;
- loop
- fetch sys_cursor into emp_info;
- exit when sys_cursor%notfound;
- dbms_output.put_line(emp_info.name || '加入公司的時(shí)間是 ' || emp_info.job);
- end loop;
- close sys_cursor;
- exception
- when NO_DATA_FOUND then dbms_output.put_line('查詢不到員工編號(hào)為' || n_empno || '的員工!');
- when TOO_MANY_ROWS then dbms_output.put_line('數(shù)據(jù)完整性錯(cuò)誤,員工編號(hào)' || n_empno || '重復(fù)!');
- when OTHERS then dbms_output.put_line('PL/SQL執(zhí)行錯(cuò)誤!' || sqlerrm);
- end;
- /
轉(zhuǎn)載:http://www.javaeye.com/topic/624079