這是第五章的學習筆記,學習完第四章的數據庫操作和事務之后,開始要學習游標的使用了……,希望大家能多給俺一些支持啊!
編程時使用的工具是PLSQL Developer 7.1.4
隱式游標
隱式游標的屬性等在第四章筆記中已記錄了一部分
如果要確保屬性指向想要的SQL語句,那么就在SQL語句執行后,立即將屬性值保存到一個本地變量中
用存儲過程來實現這種效果:
先定義一個存儲過程remove_from_emp ,用于從雇員中刪除一個員工
在存儲過程的參數中 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;
/
-- 定義一個存儲過程來調用存儲過程remove_from_emp,并保存隱式游標的屬性值
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;
-- 注意employee表中沒有編號為99的員工
-- 調用存儲過程remove_from_emp
remove_from_emp(1);
-- 現在可以用前一條語句的屬性值輸出
dbms_output.put_line(i_numfound);
end;
/
顯式游標(PL/SQL塊中使用顯示游標的本個步驟:聲明、打開、提取記錄、關閉)
在程序包規范中聲明一個游標類型(我們可以在PL/SQL塊或者包的定義部分聲明游標類型)
- 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
-- 定義一個不帶參數的游標emp_cur1,游標的結果是employee表中員工的集合
cursor emp_cur1 is select * from employee;
-- 定義一個帶參數的游標emp_cur2,游標的結果集是匹配由游標傳遞過來的員工編號的員工姓名和加入公司的時間
cursor emp_cur2 (empno_in in number) is select name,hiredate from employee where empno = empno_in;
-- 定義一個帶有return 子句的游標,游標的結果集是員工編號為1的employee表中所有的列
cursor emp_cur3 return employee%rowtype is select * from employee where empno = 1;
如果想通過游標更新數據,必須在select 語句后加上for update 子句,
該select 語句涉及的所有行都會被鎖住
如果是加上了for update of 列名,那么只有在for update 子句中引用了某個表的列時,
該表中的行才會被鎖住,of 列表并不限制只能更改列給出的列,它只讓我們知道要更改什么
可以在for update 子句后添加一個nowait 關鍵字,用于告訴Oracle如果表已經被其他用戶
鎖住,就不需要等待了,這樣控制權會立即返回給我們的程序,如果沒有nowait子句進程就
會阻塞,直到表可用(commit或rollback)為止
可以在Select into、Fetch into、Returning into子句中使用Bulk Collect將數據輸出到集合中
- 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 := &員工編號:;
-
-
-
-
- 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;
-- 應該總是將游標行提取到用%rowtype定義的記錄中,這樣更靈活(表字段改變了不需要更改fetch語句)
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 := &員工編號:;
-- 游標變量和ref cursor
-- 定義ref cursor 類型的游標變量
-- 創建一個強類型的引用游標類型
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;
-- 從Oracle9i 開始提供了一個名為sys_refcursor的預定義的Oracle系統游標,
-- 它相當于弱類型游標,使用它不需要定義游標變量
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
打開游標:open 顯式游標名 (參數列表)
一旦打開了顯式游標,就可以從游標中提取記錄,直到沒有記錄留在游標中
打開游標時,PL/SQL就開始執行該游標的Select 查詢,但是實際上并不返回任何行,
返回行的任務是由后面的Fetch(讀取)…… into(賦值給)…… 語句完成的:
fetch 游標名 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 || '加入公司的時間是 ' || 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 || ',加入公司的時間是 ' || emp_row3.hiredate);
- end if;
- close emp_cur3;
-
- open emp_cur4(n_empno);
- fetch emp_cur4 into emp_row4;
open emp_cur1;
-- 提取記錄
-- 如果游標只返回一行可以用if、loop或for來判斷獲得數據,如果游標返回多行可以用loop或for來循環獲得數據
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 循環能很好的簡化游標的開發,我們不再需要聲明記錄,不再需要Open、Fetch和Close語句
-- 也不再需要%found屬性檢測記錄,一切Oracle隱式的幫我們完成了
for emp_row2 in emp_cur2(n_empno) loop
dbms_output.put_line('員工' || emp_row2.name || '加入公司的時間是 ' || emp_row2.hiredate);
end loop;
-- 打開帶return 子句的游標
open emp_cur3;
fetch emp_cur3 into emp_row3;
if emp_cur3%found then
dbms_output.put_line('員工' || emp_row3.name || '其職位是' || emp_row3.job || ',加入公司的時間是 ' || emp_row3.hiredate);
end if;
close emp_cur3;
-- 打開帶for update 子句的游標,將指定編號的員工工資增加500元
open emp_cur4(n_empno);
fetch emp_cur4 into emp_row4;
where current of 游標名 子句能很容易的修改最近提取的數據行(也就是當前游標指向的位置),
這樣的好處是,如果表表結構發生了改變,我們只需要更改Select語句的Where子句即可,而不
需要更新每個SQL語句
- 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 || '原來的工資是' || emp_row4.salary || '元,增加工資后現在的工資是' || 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 || '加入公司的時間是 ' || emp_info.job);
- end loop;
- close sys_cursor;
- exception
- when NO_DATA_FOUND then dbms_output.put_line('查詢不到員工編號為' || n_empno || '的員工!');
- when TOO_MANY_ROWS then dbms_output.put_line('數據完整性錯誤,員工編號' || n_empno || '重復!');
- when OTHERS then dbms_output.put_line('PL/SQL執行錯誤!' || sqlerrm);
- end;
- /
轉載:http://www.javaeye.com/topic/624079