oracle 存儲過程及REF CURSOR的使用

摘要:主要記錄了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,參數2INNUMBERAS
變量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;


--記得聲明用於存放procedureout值的變量
--語句結束了一定記得結尾的 —— ;
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();
      } 
  }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章