1. 程式人生 > >Oracle儲存過程詳解(二)

Oracle儲存過程詳解(二)

無參儲存過程:

create or replace procedure sayhello
as
--說明部分
begin
  dbms_output.put_line('hello world');
end;

命令視窗的兩種呼叫方法

    1.
SQL> set serveroutput on;   --第一次一定要開
SQL> exec sayhello
hello world
PL/SQL procedure successfully completed
    2.
SQL> begin
  2  sayhello();
  3  sayhello();
  4
end; 5 / hello world hello world PL/SQL procedure successfully completed

pl/sql塊 除錯

BEGIN
  SAYHELLO();
--rollback; 
END;

SQL視窗呼叫(不會輸出dbms_output的內容)

exec是sqlplus的命令,只能在sqlplus中使用(PLSQL Developer的命令視窗也是這種)。
call是sql命令,任何工具都可以使用。如果想返回結果就用 傳遞引數

call sayhello();

有參儲存過程

案例:給員工漲薪水

create
or replace procedure raisesalary(eno in number) as --定義一個變數用來儲存漲薪前的薪水 psal emp.sal%TYPE; begin --漲薪前 select sal into psal from emp where empno = eno; --漲薪 update emp set sal = sal + 100 where empno = eno; DBMS_OUTPUT.PUT_LINE('漲薪前:' ||psal|| '漲薪後:' || (psal+100)); end;

PL/SQL塊除錯

DECLARE
  ENO NUMBER;
BEGIN
ENO := 7499; RAISESALARY( ENO => ENO ); --rollback; END;

案例:查詢員工資訊

create or replace procedure queryempinfo
(
  eno in number,
  pname out varchar2,
  psal out number,
  pjob out varchar2
)
 as
 begin
   select ename,sal,job into pname,psal,pjob from emp where empno = eno;
end; 

PL/SQL塊除錯

DECLARE
  ENO NUMBER;
  PNAME VARCHAR2(200);
  PSAL NUMBER;
  PJOB VARCHAR2(200);
BEGIN
  ENO := 7521;

  QUERYEMPINFO(
    ENO => ENO,
    PNAME => PNAME,
    PSAL => PSAL,
    PJOB => PJOB
  );

DBMS_OUTPUT.PUT_LINE('PNAME = ' || PNAME);

  :PNAME := PNAME;

DBMS_OUTPUT.PUT_LINE('PSAL = ' || PSAL);

  :PSAL := PSAL;

DBMS_OUTPUT.PUT_LINE('PJOB = ' || PJOB);

  :PJOB := PJOB;
--rollback; 
END;

有參儲存函式

案例:查詢員工的年收入

create or replace function queryempincome(eno in number)
return number
as
psal emp.sal%TYPE;
pcomm emp.comm%TYPE;
BEGIN
  SELECT SAL,COMM INTO PSAL,PCOMM FROM EMP WHERE EMPNO = ENO;

  --返回年收入(這裡一定要注意空值的情況)
  return psal*12+nvl(pcomm,0);
END;

–PL/SQL塊除錯

DECLARE
  ENO NUMBER;
  v_Return NUMBER;
BEGIN
  ENO := 7839;

  v_Return := QUERYEMPINCOME(
    ENO => ENO
  );

DBMS_OUTPUT.PUT_LINE('v_Return = ' || v_Return);

  :v_Return := v_Return;
--rollback; 
END;

檢視儲存過程的屬性是輸入還是輸出的

SQL> DESC DBMS_OUTPUT;
Element   Type      
--------- --------- 
ENABLE    PROCEDURE 
DISABLE   PROCEDURE 
PUT       PROCEDURE 
PUT_LINE  PROCEDURE 
NEW_LINE  PROCEDURE 
GET_LINE  PROCEDURE 
CHARARR   TYPE      
GET_LINES PROCEDURE 

SQL> DESC DBMS_OUTPUT.put_line;
Parameter Type     Mode Default? 
--------- -------- ---- -------- 
A         VARCHAR2 IN   

out 集合(使用游標)

--包頭
create or replace package mypackage as
 type empcursor is ref cursor; --宣告一個游標型別
 procedure queryEmpList(dno in number,empList out empcursor);
end;

--包體
create or replace package body mypackage as

 procedure queryEmpList(dno in number,empList out empcursor) as
   begin
     --開啟游標
     open empList for select * from emp where deptno=dno;
   end;
end;

命令視窗(檢視程式包的結構)

SQL> desc mypackage
Element      Type      
------------ --------- 
EMPCURSOR    TYPE      
QUERYEMPLIST PROCEDURE 

SQL> desc mypackage.queryEmpList
Parameter Type       Mode Default? 
--------- ---------- ---- -------- 
DNO       NUMBER     IN            
EMPLIST   REF CURSOR OUT 

應用程式中訪問儲存過程和儲存函式

訪問儲存過程

//獲取資料庫的連線
略
//sql語句
String sql = "{call queryEmpinfo(?,?,?,?)}";
//通過連線建立statment
CallableStatement call = conn.prepareCall(sql);

//對於IN引數需要賦值
call.setInt(1,7839);

//對於OUT引數需要先申明
call.registerOutParameter(2,OracleTypes.VARCHAR);
call.registerOutParameter(3,OracleTypes.NUMBER);
call.registerOutParameter(4,OracleTypes.VARCHAR);

//執行呼叫
call.execute();

//取出結果
String name = call.getString(2);
double sal = call.getDouble(3);
String job = call.getString(4);

訪問儲存函式

//獲取資料庫的連線
略
//sql語句
String sql = "{?=call queryempincome(?)}";
//通過連線建立statment
CallableStatement call = conn.prepareCall(sql);

//對於輸出引數需要宣告
call.setInt(1,OracleTypes.NUMBER);

//對於輸入引數需要賦值
call.registOutParameterr(2,7839);

//執行呼叫
call.execute();

//取出年收入
double income = call.getDouble(1);

訪問有游標的儲存過程

//獲取資料庫的連線
略
//sql語句 (一定要寫上包名)
String sql = "{call mypackage.queryEmpList(?,?)}";
//通過連線建立statment
CallableStatement call = conn.prepareCall(sql);

//對於IN引數需要賦值
call.setInt(1,10);

//對於OUT引數需要先申明
call.registerOutParameter(2,OracleTypes.CURSOR);

//執行呼叫
call.execute();

//取出該部門中所有員工資訊(注意這裡)
ResultSet rs = ((OracleCallableStatement)call).getCursor(2);

while(rs.next()){
    //可以取出sql語句中查詢的所有欄位(這裡只取幾個演示下)
    int empno = rs.getInt("empno");
    String ename = rs.getString("ename");
    double sal = rs.getDouble("sal");
}

公司用的最基本的兩個儲存過程:

刪除表

create or replace procedure drop_table(tablename in VARCHAR2)
is

  vn_ctn number(2);
  Begin

  select count(*) into vn_ctn from user_all_tables a where a.table_name = upper(tablename); 

   if vn_ctn > 0 then 
       --execute immediate不管表在與不成都通過編譯或執行
      execute immediate 'drop table ' || tablename;  
   end if;

EXCEPTION  
  WHEN OTHERS THEN 

    dbms_output.put_line(SQLCODE || '::'||SUBSTR(SQLERRM, 1, 400));
End drop_table;

刪除序列

create or replace procedure drop_sequence(sequenceName in VARCHAR2)
is

  vn_ctn number(2);
  Begin

  select count(*) into vn_ctn from user_sequences a where a.sequence_name = upper(sequenceName); 

   if vn_ctn > 0 then 
      execute immediate 'drop sequence ' || sequenceName;  
   end if;

EXCEPTION  
  WHEN OTHERS THEN 

    dbms_output.put_line(SQLCODE || '::'||SUBSTR(SQLERRM, 1, 400));
End drop_sequence;