摘要:主要記錄了oracle的stored procedure相關知識、從定義到使用。從最簡單的例子入手、逐漸深入。同時後面結合了ref cursor的使用。順便補充了在java中如何使用。
一:簡介
1、存儲過程定義:
存儲過程(Stored Procedure )是一組爲了完成特定功能的SQL 語句集,經編譯後存儲在數據庫中。用戶通過指定存儲過程的名字並給出參數(如果該存儲過程帶有參數)來執行它。存儲過程是數據庫中的一個重要對象,任何一個設計良好的數據庫應用程序都應該用到存儲過程。
存儲過程是由流控制的和SQL 語句書寫的過程,這個過程經編譯和優化後存儲在數據庫服務器中,應用程序使用時只要調用即可。在ORACLE 中,若干個有聯繫的過程可以組合在一起構成程序包。
2、優點:
a) 存儲過程只在創造時進行編譯,以後每次執行存儲過程都不需再重新編譯,而一般SQL語句每執行一次就編譯一次,所以使用存儲過程可提高數據庫執行速度。
b) 當對數據庫進行復雜操作時(如對多個表進行Update、Insert、Query、Delete時),可將此複雜操作用存儲過程封裝起來與數據庫提供的事務管理結合一起使用。
c)存儲過程可以重複使用,可減少數據庫開發人員的工作量。
d)安全性高,可設定只有某用戶才具有對指定存儲過程的使用權。
簡單說,你在你的機器上寫了個存儲過程,這個存儲過程像那些表裏的數據一樣被放在遙遠的數據庫服務器當中,但是它又是可執行的代碼,其他能連到數據庫服務器的用戶,可以調用你寫的存儲過程
它的作用是隱藏細節,就是說,你寫的存儲過程代碼可能很複雜,但是其他人調用它卻很簡單,不用具體知道它是如何做的,且一次能完成多個指令
3、分類:
oracle有系統存儲過程和自定義存儲過程2種存儲過程。
系統存儲過程就是由oracle預先提供的一組完成特定功能的存儲過程,安裝完oracle就有了。
自定義存儲過程就是存在oracle數據庫裏由一組plsql語句組成的自定義過程(procedure)。它可以供其它oracle自定義存儲過程、自定義函數和job調用或者由客戶端程序調用。
二:基本使用方法及示例
1、基本結構:
CREATEORREPLACE PROCEDURE 存儲過程名字
(參數1INNUMBER,參數2INNUMBER)
AS
變量1INTEGER:=0;
變量2DATE;
BEGIN
END存儲過程名字
2、 無參形式的procedure:
--無參procedure
createorreplace procedure pro_no_param
is
begin
dbms_output.put_line('the procedure without params');
endpro_no_param;
--調用
--one: 無參的procedure名字後面必須要();
call pro_no_param();
--two:procedure名稱後面可以沒有();
begin
pro_no_param();
end;
3、 參數類型爲IN的procedure:
--有參procedure 只有IN類型
createorreplace procedure pro_in_param(
v_1innumber,
v_2invarchar2,
v_3indate
)
is
begin
dbms_output.put_line('v1: ' || v_1 || ' v2: ' || v_2 || ' v2: '|| (to_char(v_3, 'yyyy-mm-dd')));
endpro_in_param;
begin
pro_in_param(1,'chy', sysdate);
end;
4、 參數類型爲OUT的procedure:
--有參procedure 只有OUT類型
createorreplace procedure pro_out_param(
v1outnumber,
v2outchar
)
is
begin
v1 := 2;
v2 := 'andyChen';
endpro_out_param;
--記得聲明用於存放procedure的out值的變量
--語句結束了一定記得結尾的 —— ;
declare
v_1 number;
v_2 varchar2(200);
begin
pro_out_param(v_1, v_2);
dbms_output.put_line('v1: ' || v_1 || ' v2: ' || v_2);
end;
5、 參數類型同時爲IN和OUT的procedure:
–同時爲INOUT參數的procedure
–用同一變量接收傳入的值然後將這個變量當作輸出的值賦給執行時聲明的變量
createorreplace procedure pro_in_out_param(
in_out_paraminoutvarchar2
)
is
begin
in_out_param := 'in_out_param and ' || in_out_param;
endpro_in_out_param;
declare
in_out_param varchar2(222) := 'detail param';
begin
pro_in_out_param(in_out_param);
dbms_output.put_line(in_out_param);
end;
三:實例
CREATETABLEuser_info
(
id VARCHAR2(4) notnullprimary key,
nameVARCHAR2(15),
pwd VARCHAR2(15),
address VARCHAR2(30)
);
--創建一個添加用戶的stored_procedure;
createorreplace procedure pro_addUser(
n_id user_info.id%type,
n_name user_info.name%type,
n_pwd user_info.pwd%TYPE,
n_address user_info.address%TYPE
)
as
begin
--插入數據
insertintouser_info(id,name,pwd,address)
values(n_id, n_name, n_pwd, n_address);
endpro_addUser;
--調用、有變量需要聲明的時候纔有declare、沒有就直接begin
begin
pro_addUser('1','chy','admin','nanjin');
if SQL%found then
dbms_output.put_line('add successed');
endif;
end;
--根據id查詢用戶名和密碼
createorreplace procedure pro_getUserInfo(
n_id user_info.id%type,
n_nameoutuser_info.name%type,
n_pwd outuser_info.pwd%type
)
as
begin
selectuser_info.name, user_info.pwd inton_name, n_pwd
fromuser_info
whereuser_info.id=n_id;
endpro_getUserInfo;
--調用
declare
v_id user_info.id%type := '1';
v_name user_info.name%type;
v_pwd user_info.pwd%type;
begin
pro_getUserInfo(v_id, v_name, v_pwd);
dbms_output.put_line('name: ' || v_name || ' pwd: ' || v_pwd);
end;
-- 打印九九乘法表
createorreplace procedure pro_multiplication_table
is
i integer;
j integer;
begin
foriin1..9 loop
forjin1..9 loop
if i>=j then
DBMS_output.put(To_Char(j)||'*'||to_char(i)||'='||to_char(i*j)||' ');
endif;
endloop;
DBMS_output.put_line('');
endloop;
end pro_multiplication_table;
--調用
call pro_multiplication_table();
--使用自定義遊標、根據工作and薪水查詢員工姓名
createorreplace procedure pro_getName(
n_sal emp.sal%type,
n_ename outemp.ename%type,
n_jobinoutemp.job%type
)
is
n_count number;
cursorcurisselectename fromempwhereemp.sal > n_sal andemp.job=n_job;
n_row cur%rowtype;
begin
selectcount(*)inton_countfromempwhereemp.sal > n_sal andemp.job=n_job;
if n_count > 1 then
forn_rowincur loop
DBMS_output.put_line('職工姓名爲:'||n_row.ename||' 工作爲:'||n_job);
endloop;
else
DBMS_output.put_line('未查到符合條件的記錄!');
endif;
end pro_getName;
-- 調用
declare
v_sal emp.sal%type := 2000;
v_job emp.job%type :='MANAGER';
v_ename emp.ename%type;
begin
pro_getName(v_sal, v_ename, v_job);
end;
--ref cursor的使用
--創建存放弱引用和強引用的cursor的包
createorreplace package refcursor_pkg
as
type weak_ref_cursor isrefcursor;
type strong_ref_cursor isrefcursorreturnemp%rowtype;
endrefcursor_pkg;
--將弱引用的cursor作爲結果返回
createorreplace procedure test(
p_deptnoinnumber,
p_cursoroutrefcursor_pkg.weak_ref_cursor
)
isbegin
openp_cursorforselect* fromempwheredeptno=p_deptno;
endtest;
/**或者不用包直接使用下面這種定義
createorreplace procedure test_1(
p_deptnoINnumber,
p_cursorOUTSYS_REFCURSOR
)
is
begin
openp_cursorFORselect*fromempwhere deptno = p_deptno;
endtest_1;
*/
declare
v_deptno number := 20;
v_cursor refcursor_pkg.weak_ref_cursor;
r_emp emp%rowtype;
begin
test(v_deptno, v_cursor);
loop
fetchv_cursorintor_emp;
exitwhenv_cursor%notfound;
dbms_output.put_line('empno: ' || r_emp.empno || ' ename: ' || r_emp.ename || ' job: ' || r_emp.job);
endloop;
closev_cursor;
end;
//java中使用refcursor
publicvoid method() throws SQLException{
Connectionconn = getConnection();
CallableStatement cstmt = null;
ResultSet rs = null;
intdeptno = 10;
Objecttemp;
try{
cstmt = conn.prepareCall("begin test(?,?); end;");
cstmt.setInt(1, deptno);
cstmt.registerOutParameter(2, OracleTypes.CURSOR);
cstmt.execute();
rs = (ResultSet) cstmt.getObject(2);
ResultSetMetaData rsm = rs.getMetaData();
intcolumnCount = rsm.getColumnCount();
while (rs.next()){
for(intj=0;j< columnCount;j++){
temp= rs.getObject(j+1);
}
}
} finally {
if (!rs==null){
rs.close();
}
if (!stmt==null){
stmt.close();
}
if (!conn==null){
conn.close();
}
}
}