儲存過程基本語法和須注意事項

langgufu314發表於2012-06-15

儲存過程建立語法

1)無參

create or replace procedure
儲存過程名

as
變數1 型別(值範圍)
;
變數2 型別(值範圍)
;
Begin
       ........................
Exception
       ........................
End;



2)帶參

create or replace procedure
儲存過程名(param1 in typeparam2 out type

as
變數1 型別(值範圍)
;
變數2 型別(值範圍)
;
Begin
    Select count(*) into
變數1 from A where列名=param1

    If (
判斷條件
) then
       Select
列名 into 變數2 from A where列名=param1

       Dbms_output.Put_line(‘
列印資訊
’);
    Elseif (
判斷條件
) then
       Dbms_output.Put_line(‘
列印資訊
’);
    Else
       Raise
異常名(NO_DATA_FOUND
;
    End if;
Exception
    When others then
       Rollback;
End;



注意事項:


1
  儲存過程引數不帶取值範圍,in表示傳入,out表示輸出


2
  變數帶取值範圍,後面接分號


3
  在判斷語句前最好先用count*)函式判斷是否存在該條操作記錄


4
  select 。。。into。。。給變數賦值


5
  在程式碼中拋異常用 raise+異常名




以命名的異常


命名的系統異常                          產生原因


ACCESS_INTO_NULL                  
未定義物件


CASE_NOT_FOUND                     CASE
中若未包含相應的 WHEN ,並且沒有設定


ELSE


COLLECTION_IS_NULL               
集合元素未初始化


CURSER_ALREADY_OPEN         
遊標已經開啟


DUP_VAL_ON_INDEX                  
唯一索引對應的列上有重複的值


INVALID_CURSOR                
在不合法的遊標上進行操作


INVALID_NUMBER                      
內嵌的 SQL 語句不能將字元轉換為數字


NO_DATA_FOUND                       
使用 select into 未返回行,或應用索引表未初始化的
 



TOO_MANY_ROWS                     
執行 select into 時,結果集超過一行


ZERO_DIVIDE                             
除數為
0

SUBSCRIPT_BEYOND_COUNT    
元素下標超過巢狀表或 VARRAY 的最大值


SUBSCRIPT_OUTSIDE_LIMIT      
使用巢狀表或 VARRAY 時,將下標指定為負數


VALUE_ERROR                            
賦值時,變數長度不足以容納實際資料


LOGIN_DENIED                           PL/SQL
應用程式連線到 oracle 資料庫時,提供了不正確的使用者名稱或密碼


NOT_LOGGED_ON                       PL/SQL
應用程式在沒有連線 oralce 資料庫的情況下訪問資料


PROGRAM_ERROR                       PL/SQL
內部問題,可能需要重灌資料字典& pl./SQL系統包


ROWTYPE_MISMATCH               
宿主遊標變數與 PL/SQL 遊標變數的返回型別不相容


SELF_IS_NULL                            
使用物件型別時,在 null 物件上呼叫物件方法


STORAGE_ERROR                       
執行 PL/SQL 時,超出記憶體空間


SYS_INVALID_ID                        
無效的 ROWID 字串


TIMEOUT_ON_RESOURCE         Oracle
在等待資源時超時
 



例子:


1  create or replace procedure runbyparmeters  (isal in emp.sal%type,
                            sname out varchar,sjob in out varchar)
2  as icount number;
3  begin
4       select count(*) into icount from emp where sal>isal and job=sjob;
5       if icount=1 then
6         ....
9       else
10         ....
12       end if;
13  exception
14       when too_many_rows then
15       DBMS_OUTPUT.PUT_LINE('
返回值多於1
');
16       when others then
17       DBMS_OUTPUT.PUT_LINE('
RUNBYPARMETERS過程中出錯!
');
18  end;


過程呼叫



 
方式一

1  declare
2        realsal emp.sal%type;
3        realname varchar(40);
4        realjob varchar(40);
5  begin
6        realsal:=1100;
7        realname:='';
8        realjob:='CLERK';
9        runbyparmeters(realsal,realname,realjob);    
--必須按順序

10        DBMS_OUTPUT.PUT_LINE(REALNAME||'   '||REALJOB);
11  END;
12

 
方式二

1 declare
2       realsal emp.sal%type;
3       realname varchar(40);
4       realjob varchar(40);
5 begin
6       realsal:=1100;
7       realname:='';
8       realjob:='CLERK';
9       runbyparmeters(sname=>realname,isal=>realsal,sjob=>realjob); 
--指定值對應變數順序可變

10       DBMS_OUTPUT.PUT_LINE(REALNAME||'   '||REALJOB);
11 END;



說明:


1)使用
%TYPE
在許多情況下,PL/SQL變數可以用來儲存在資料庫表中的資料。在這種情況下,變數應該擁有與表列相同的型別。例如,students表的first_name列的型別為VARCHAR2(20),我們可以按照下述方式宣告一個變數

DECLARE
v_FirstName VARCHAR2(20);
但是如果first_name列的定義改變了會發生什麼(比如說表改變了,first_name現在的型別變為VARCHAR2(25))?那就會導致所 有使用這個列的PL/SQL程式碼都必須進行修改。如果你有很多的PL/SQL程式碼,這種處理可能是十分耗時和容易出錯的。

這時,你可以使用”%TYPE”屬性而不是將變數型別硬性編碼。


2)使用%ROWTYPE  (相當於定義一個struct 來進行存放,以物件來看對資料)

PL/SQL中將一個記錄宣告為具有相同型別的資料庫行的作法是很常見的。PL/SQL提供了%ROWTYPE運算子,使得這樣的操作更為方便。

例如:

DECLARE
v_StudentRecord students%ROWTYPE;
將定義一個記錄,該記錄中的欄位將與students表中的列相對應。

例如:

declare
    v_jobs hr.jobs%rowtype;
begin
    select
      *
    into
      v_jobs
    from
      hr.jobs
where job_id ='&aa';
    dbms_output.put_line('
序號
'||v_jobs.job_id );
    dbms_output.put_line('
名稱
'||v_jobs.job_title);
end;
執行,我們輸入aa變數的值:
AD_VP
輸出結果為:

序號
AD_VP
名稱Administration Vice President

 

 

 

儲存過程例項

 

 

儲存過程 包含三部分: 宣告,執行部分,異常。    
可以有無引數程式和帶引數儲存過程。
    
無參程式語法
    
1 create or replace procedure NoParPro   
2 as   ;   
3 begin   
4  ;   
5 exception   
6      ;   
7 end;   
8    
  
  
帶參儲存過程例項
    
1 create or replace procedure queryempname(sfindno emp.empno%type) as   
2        sName emp.ename%type;   
3        sjob emp.job%type;   
4 begin   
5        ....   
7 exception   
          ....   
14 end;   
15    
  
  
帶引數儲存過程含賦值方式
    
1 create or replace procedure runbyparmeters  (isal in emp.sal%type,    
                            sname out varchar,sjob in out varchar)   
2  as icount number;   
3  begin   
4       select count(*) into icount from emp where sal>isal and job=sjob;   
5       if icount=1 then   
6         ....   
9       else  
10         ....   
12       end if;   
13  exception   
14       when too_many_rows then   
15       DBMS_OUTPUT.PUT_LINE('
返回值多於1
');   
16       when others then   
17       DBMS_OUTPUT.PUT_LINE('
RUNBYPARMETERS過程中出錯!
');   
18  end;   
19    
  
 
過程呼叫
   
 
方式一
   
1 declare   
2        realsal emp.sal%type;   
3        realname varchar(40);   
4        realjob varchar(40);   
5  begin   
6        realsal:=1100;   
7        realname:='';   
8        realjob:='CLERK';   
9        runbyparmeters(realsal,realname,realjob);    
--必須按順序
   
10        DBMS_OUTPUT.PUT_LINE(REALNAME||'   '||REALJOB);   
11  END;   
12    
  
 
方式二
   
1 declare   
2       realsal emp.sal%type;   
3       realname varchar(40);   
4       realjob varchar(40);   
5 begin   
6       realsal:=1100;   
7       realname:='';   
8       realjob:='CLERK';   
9       runbyparmeters(sname=>realname,isal=>realsal,sjob=>realjob); 
--指定值對應變數順序可變
   
10       DBMS_OUTPUT.PUT_LINE(REALNAME||'   '||REALJOB);   
11 END;   
12   



oracle
儲存過程的基本語法


1.
基本結構

CREATE OR REPLACE PROCEDURE
儲存過程名字

(
   
引數
1 IN NUMBER,
   
引數
2 IN NUMBER
) IS
變數
1 INTEGER :=0;
變數
2 DATE;
BEGIN

END
儲存過程名字


2.SELECT INTO STATEMENT
 
select查詢的結果存入到變數中,可以同時將多個列儲存多個變數中,必須有一條

 
記錄,否則丟擲異常(如果沒有記錄丟擲
NO_DATA_FOUND)
 
例子:

  BEGIN
  SELECT col1,col2 into
變數1,變數
2 FROM typestruct where xxx;
  EXCEPTION
  WHEN NO_DATA_FOUND THEN
      xxxx;
  END;
  ...

3.IF
判斷

  IF V_TEST=1 THEN
    BEGIN
       do something
    END;
  END IF;

4.while
迴圈

  WHILE V_TEST=1 LOOP
  BEGIN
XXXX
  END;
  END LOOP;

5.
變數賦值

  V_TEST := 123;

6.
for in 使用
cursor
  ...
  IS
  CURSOR cur IS SELECT * FROM xxx;
  BEGIN
FOR cur_result in cur LOOP
  BEGIN
   V_SUM :=cur_result.
列名1+cur_result.列名
2
  END;
END LOOP;
  END;

7.
帶引數的
cursor
  CURSOR C_USER(C_ID NUMBER) IS SELECT NAME FROM USER WHERE TYPEID=C_ID;
  OPEN C_USER(
變數值
);
  LOOP
FETCH C_USER INTO V_NAME;
EXIT FETCH C_USER%NOTFOUND;
    do something
  END LOOP;
  CLOSE C_USER;

8.
pl/sql developer debug
 
連線資料庫後建立一個
Test WINDOW
 
在視窗輸入呼叫SP的程式碼,F9開始debug,CTRL+N單步除錯


關於oracle儲存過程的若干問題備忘

1.
oracle中,資料表別名不能加as,如:


select a.appname from appinfo a;--
正確

select a.appname from appinfo as a;--
錯誤

也許,是怕和oracle中的儲存過程中的關鍵字as衝突的問題吧


2.
在儲存過程中,select某一欄位時,後面必須緊跟into,如果select整個記錄,利用遊標的話就另當別論了。


  select af.keynode into kn from APPFOUNDATION af where af.appid=aid and af.foundationid=fid;--
into,正確編譯

  select af.keynode from APPFOUNDATION af where af.appid=aid and af.foundationid=fid;--
沒有into,編譯報錯,提示:
Compilation
  Error: PLS-00428: an INTO clause is expected in this SELECT statement


3.
在利用select...into...語法時,必須先確保資料庫中有該條記錄,否則會報出"no data found"異常。


  
可以在該語法之前,先利用select count(*) from 檢視資料庫中是否存在該記錄,如果存在,再利用
select...into...

4.
在儲存過程中,別名不能和欄位名稱相同,否則雖然編譯可以通過,但在執行階段會報錯


select keynode into kn from APPFOUNDATION where appid=aid and foundationid=fid;--
正確執行

select af.keynode into kn from APPFOUNDATION af where af.appid=appid and af.foundationid=foundationid;--
執行階段報錯,提示

ORA-01422:exact fetch returns more than requested number of rows
5.
在儲存過程中,關於出現null的問題


假設有一個表A,定義如下:

create table A(
id varchar2(50) primary key not null,
vcount number(8) not null,
bid varchar2(50) not null --
外來鍵

);
如果在儲存過程中,使用如下語句:

select sum(vcount) into fcount from A where bid='xxxxxx';
如果A表中不存在bid="xxxxxx"的記錄,則fcount=null(即使fcount定義時設定了預設值,如:fcount number(8):=0依然無效,fcount還是會變成null),這樣以後使用fcount時就可能有問題,所以在這裡最好先判斷一下:

if fcount is null then
    fcount:=0;
end if;
這樣就一切ok了。


6.Hibernate
呼叫oracle儲存過程


        this.pnumberManager.getHibernateTemplate().execute(
                new HibernateCallback() ...{
                    public Object doInHibernate(Session session)
                            throws HibernateException, SQLException ...{
                        CallableStatement cs = session
                                .connection()
                                .prepareCall("{call modifyapppnumber_remain(?)}");
                        cs.setString(1, foundationid);
                        cs.execute();
                        return null;
                    }
                });

相關文章