Oracle PL/SQL編程詳解之七:程序包的創建與應用

Oracle PL/SQL編程詳解之七:程序包的創建與應用(聰明在於學習,天才在於積累!)

 


本篇主要內容如下:

第七章  程序包的創建和應用

7.1  程序包簡介

7.2  程序包的定義

7.3  包的開發步驟

7.4  包定義的說明

7.5  子程序重載

7.6  加密實用程序

7.7  刪除包

7.8  包的管理

 


 7.1  程序包簡介

    程序包(PACKAGE,簡稱包)是一組相關過程、函數、變量、常量和遊標等PL/SQL程序設計元素的組合,作爲一個完整的單元存儲在數據庫中,用名稱來標識包。它具有面向對象程序設計語言的特點,是對這些PL/SQL 程序設計元素的封裝。包類似於c#和Java語言中的類,其中變量相當於類中的成員變量,過程和函數相當於類方法。把相關的模塊歸類成爲包,可使開發人員利用面向對象的方法進行存儲過程的開發,從而提高系統性能。

       與高級語言中的類相同,包中的程序元素也分爲公用元素和私用元素兩種,這兩種元素的區別是他們允許訪問的程序範圍不同,即它們的作用域不同。公用元素不僅可以被包中的函數、過程所調用,也可以被包外的PL/SQL程序訪問,而私有元素只能被包內的函數和過程序所訪問。

當然,對於不包含在程序包中的過程、函數是獨立存在的。一般是先編寫獨立的過程與函數,待其較爲完善或經過充分驗證無誤後,再按邏輯相關性組織爲程序包。

 

程序包的優點

u       簡化應用程序設計:程序包的說明部分和包體部分可以分別創建各編譯。主要體現     在以下三個方面:

1)        可以在設計一個應用程序時,只創建各編譯程序包的說明部分,然後再編寫引用該                     程序包的PL/SQL塊。

2)        當完成整個應用程序的整體框架後,再回頭來定義包體部分。只要不改變包的說明部分,就可以單獨調試、增加或替換包體的內容,這不會影響其他的應用程序。

3)        更新包的說明後必須重新編譯引用包的應用程序,但更新包體,則不需重新編譯引用包的應用程序,以快速進行進行應用程序的原形開發。

u       模塊化:可將邏輯相關的PL/SQL塊或元素等組織在一起,用名稱來唯一標識程序 包。把一個大的功能模塊劃分人適當個數小的功能模塊,分別完成各自的功能。這樣組織的程序包都易於編寫,易於理解更易於管理。

u       信息隱藏:因爲包中的元素可以分爲公有元素和私有元素。公有元素可被程序包內的過程、函數等的訪問,還可以被包外的PL/SQL訪問。但對於私有元素只能被包內的過程、函數等訪問。對於用戶,只需知道包的說明,不用瞭解包休的具體細節。

u       效率高:程序包在應用程序第一次調用程序包中的某個元素時,ORACLE將把整個程序包加載到內存中,當第二次訪問程序包中的元素時,ORACLE將直接從內在中讀取,而不需要進行磁盤I/O操作而影響速度,同時位於內在中的程序包可被同一會話期間的其它應用程序共享。因此,程序包增加了重用性並改善了多用戶、多應用程序環境的效率。

 

對程序包的優點可總結如下:在PL/SQL程序設計中,使用包不僅可以使程序設計模塊化,對外隱藏包內所使用的信息(通過使用私用變量),而寫可以提高程序的執行效率。因爲,當程序首次調用包內函數或過程時,ORACLE將整個包調入內存,當再次訪問包內元素時,ORACLE直接從內存中讀取,而不需要進行磁盤I/O操作,從而使程序執行效率得到提高。

 

    一個包由兩個分開的部分組成:

    包說明(PACKAGE):包說明部分聲明包內數據類型、變量、常量、遊標、子程序和異常錯誤處理等元素,這些元素爲包的公有元素。

    包主體(PACKAGE BODY):包主體則是包定義部分的具體實現,它定義了包定義部分所聲明的遊標和子程序,在包主體中還可以聲明包的私有元素。

    包說明和包主體分開編譯,並作爲兩部分分開的對象存放在數據庫字典中,可查看數據字典user_source, all_source, dba_source,分別瞭解包說明與包主體的詳細信息。

7.2  程序包的定義

程序包的定義分爲程序包說明定義和程序包主體定義兩部分組成。

程序包說明用於聲明包的公用組件,如變量、常量、自定義數據類型、異常、過程、函數、遊標等。包說明中定義的公有組件不僅可以在包內使用,還可以由包外其他過程、函數。但需要說明與注意的是,我們爲了實現信息的隱藏,建議不要將所有組件都放在包說明處聲明,只應把公共組件放在包聲明部分。包的名稱是唯一的,但對於兩個包中的公有組件的名稱可以相同,這種用“包名.公有組件名“加以區分。

包體是包的具體實現細節,其實現在包說明中聲明的所有公有過程、函數、遊標等。當然也可以在包體中聲明僅屬於自己的私有過程、函數、遊標等。創建包體時,有以下幾點需要注意:

u       包體只能在包說明被創建或編譯後才能進行創建或編譯。

u       在包體中實現的過程、函數、遊標的名稱必須與包說明中的過程、函數、遊標一致,包括名稱、參數的名稱以及參數的模式(IN、OUT、IN OUT)。並建設按包說明中的次序定義包體中具體的實現。

u       在包體中聲明的數據類型、變量、常量都是私有的,只能在包體中使用而不能被印刷體外的應用程序訪問與使用。

u       在包體執行部分,可對包說明,包體中聲明的公有或私有變量進行初始化或其它設置。

 

創建程序包說明語法格式:

 

CREATE [OR REPLACE] PACKAGE package_name
  
[AUTHID {CURRENT_USER | DEFINER}]
  {
IS | AS}
  
[公有數據類型定義[公有數據類型定義]…]
  
[公有遊標聲明[公有遊標聲明]…]
  
[公有變量、常量聲明[公有變量、常量聲明]…]
  
[公有函數聲明[公有函數聲明]…]
  
[公有過程聲明[公有過程聲明]…]
END [package_name];

 

 

其中:AUTHID CURRENT_USERAUTHID DEFINER選項說明應用程序在調用函數時所使用的權限模式,它們與CREATE FUNCTION語句中invoker_right_clause子句的作用相同。

 

創建程序包主體語法格式:

CREATE [OR REPLACE] PACKAGE BODY package_name
  {
IS | AS}
  
[私有數據類型定義[私有數據類型定義]…]
  
[私有變量、常量聲明[私有變量、常量聲明]…]
  
[私有異常錯誤聲明[私有異常錯誤聲明]…]
  
[私有函數聲明和定義[私有函數聲明和定義]…]
  
[私有函過程聲明和定義[私有函過程聲明和定義]…]
  
[公有遊標定義[公有遊標定義]…]
  
[公有函數定義[公有函數定義]…]
  
[公有過程定義[公有過程定義]…]
BEGIN
  執行部分(初始化部分)
END package_name;

 

 

其中:在包主體定義公有程序時,它們必須與包定義中所聲明子程序的格式完全一致。

7.3  包的開發步驟

   與開發存儲過程類似,包的開發需要幾個步驟:

1.   將每個存儲過程調式正確;

2.   用文本編輯軟件將各個存儲過程和函數集成在一起;

3.   按照包的定義要求將集成的文本的前面加上包定義;

4.   按照包的定義要求將集成的文本的前面加上包主體;

5.   使用SQLPLUS或開發工具進行調式。

7.4  包定義的說明

例1:創建的包爲DEMO_PKG, 該包中包含一個記錄變量DEPTREC、兩個函數和一個過程。實現對dept表的增加、刪除與查詢。

 

CREATE OR REPLACE PACKAGE  DEMO_PKG
IS
  DEPTREC DEPT
%ROWTYPE;
  
  
--Add dept...
  FUNCTION add_dept(
           dept_no    
NUMBER
           dept_name 
VARCHAR2
           location  
VARCHAR2)
  
RETURN NUMBER;
  
  
--delete dept...
  FUNCTION delete_dept(dept_no NUMBER)
  
RETURN NUMBER;
  
  
--query dept...
  PROCEDURE query_dept(dept_no IN NUMBER);
END DEMO_PKG;

 

 

   包主體的創建方法,它實現上面所聲明的包定義,並在包主體中聲明一個私有變量flag和一個私有函數check_dept,由於在add_dept和remove_dept等函數中需要調用check_dpet函數,所以,在定義check_dept 函數之前首先對該函數進行聲明,這種聲明方法稱作前向聲明。

 

 

CREATE OR REPLACE PACKAGE BODY DEMO_PKG
IS 
FUNCTION add_dept
(
   dept_no 
NUMBER
   dept_name 
VARCHAR2
   location 
VARCHAR2
)
RETURN NUMBER
IS 
  empno_remaining EXCEPTION; 
--自定義異常
  PRAGMA EXCEPTION_INIT(empno_remaining, -1);
   
/* -1 是違反唯一約束條件的錯誤代碼 */
BEGIN
  
INSERT INTO dept VALUES(dept_no, dept_name, location);
  
IF SQL%FOUND THEN
     
RETURN 1;
  
END IF;
EXCEPTION
     
WHEN empno_remaining THEN 
        
RETURN 0;
     
WHEN OTHERS THEN
        
RETURN -1;
END add_dept;

FUNCTION delete_dept(dept_no NUMBER)
RETURN NUMBER
IS 
BEGIN
  
DELETE FROM dept WHERE deptno = dept_no;
  
IF SQL%FOUND THEN
    
RETURN 1;
  
ELSE
    
RETURN 0;
   
END IF;
EXCEPTION
  
WHEN OTHERS THEN
    
RETURN -1;
END delete_dept;

PROCEDURE query_dept
(dept_no 
IN NUMBER)
IS
BEGIN
      
SELECT * INTO DeptRec FROM dept WHERE deptno=dept_no;
EXCEPTION
       
WHEN NO_DATA_FOUND THEN  
          DBMS_OUTPUT.PUT_LINE(
'溫馨提示:數據庫中沒有編碼爲'||dept_no||'的部門');
       
WHEN TOO_MANY_ROWS THEN
          DBMS_OUTPUT.PUT_LINE(
'程序運行錯誤,請使用遊標進行操作!');
       
WHEN OTHERS THEN
           DBMS_OUTPUT.PUT_LINE(SQLCODE
||'----'||SQLERRM);
END query_dept;

BEGIN 
    
Null;
END DEMO_PKG;

 

 

   對包內共有元素的調用格式爲:包名.元素名稱

 

 

調用DEMO_PKG包內函數對dept表進行插入、查詢和刪除操作,並通過DEMO_PKG包中的記錄變量DEPTREC顯示所查詢到的數據庫信息:

DECLARE
    
Var NUMBER;
BEGIN
    
Var := DEMO_PKG.add_dept(90,'HKLORB''HAIKOU');
    
IF var =-1 THEN
        DBMS_OUTPUT.PUT_LINE(SQLCODE
||'----'||SQLERRM);
    ELSIF 
var =0 THEN
        DBMS_OUTPUT.PUT_LINE(
'溫馨提示:該部門記錄已經存在!');
    
ELSE
        DBMS_OUTPUT.PUT_LINE(
'溫馨提示:添加記錄成功!');
        DEMO_PKG.query_dept(
90);
        DBMS_OUTPUT.PUT_LINE(DEMO_PKG.DeptRec.deptno
||'---'||
         DEMO_PKG.DeptRec.dname
||'---'||DEMO_PKG.DeptRec.loc);
        
var := DEMO_PKG.delete_dept(90);
        
IF var =-1 THEN
            DBMS_OUTPUT.PUT_LINE(SQLCODE
||'----'||SQLERRM);
        ELSIF 
var=0 THEN
            DBMS_OUTPUT.PUT_LINE(
'溫馨提示:該部門記錄不存在!');
        
ELSE
            DBMS_OUTPUT.PUT_LINE(
'溫馨提示:刪除記錄成功!');
        
END IF;
    
END IF;
END;

 

 

 

例2: 創建包EMP_PKG,讀取emp表中的數據

  

--創建包說明
CREATE OR REPLACE PACKAGE EMP_PKG 
IS
  TYPE emp_table_type 
IS TABLE OF emp%ROWTYPE 
  
INDEX BY BINARY_INTEGER;
  
  
PROCEDURE read_emp_table (p_emp_table OUT emp_table_type);
END EMP_PKG;

--創建包體
CREATE OR REPLACE PACKAGE BODY EMP_PKG 
IS
PROCEDURE read_emp_table (p_emp_table OUT emp_table_type) 
IS
I BINARY_INTEGER :
= 0;
BEGIN
   
FOR emp_record IN ( SELECT * FROM emp ) LOOP
      P_emp_table(i) :
= emp_record;
      I :
= I + 1;
    
END LOOP;
  
END read_emp_table;
END EMP_PKG;

--執行
DECLARE 
  E_table EMP_PKG.emp_table_type;
BEGIN
  EMP_PKG.read_emp_table(e_table);
  
FOR I IN e_table.FIRST ..e_table.LAST LOOP
    DBMS_OUTPUT.PUT_LINE(e_table(i).empno
||'  '||e_table(i).ename);
  
END LOOP;
END;

 

例3: 創建包MANAGE_EMP_PKG,對員工進行管理(新增員工、新增部門、刪除指定員工、刪除指定部門、增加指定員工的工資與獎金)

  

--創建序列從100開始,依次增加1
CREATE SEQUENCE empseq 
START 
WITH 100 
INCREMENT 
BY 1 
ORDER NOCYCLE;

--創建序列從100開始,依次增加10
CREATE SEQUENCE deptseq
START 
WITH 100
INCREMENT 
BY 10 
ORDER NOCYCLE;

-- *******************************************
  -- 創建包說明
  -- 包   名:MANAGE_EMP_PKG 
  -- 功能描述:對員工進行管理(新增員工,新增部門
  --            ,刪除員工,刪除部門,增加工資與獎金等)
  -- 創建人員:胡勇
  -- 創建日期:2010-05-19
  -- Q     Q: 80368704
  -- E-mail : [email protected]
  -- WebSite: http://www.cnblogs.com/huyong
--
 ******************************************
CREATE OR REPLACE PACKAGE MANAGE_EMP_PKG 
AS
  
--增加一名員工     
  FUNCTION hire_emp
    (ename 
VARCHAR2, job VARCHAR2
    , mgr 
NUMBER, sal NUMBER
    , comm 
NUMBER, deptno NUMBER)
  
RETURN NUMBER;

  
--新增一個部門
  FUNCTION add_dept(dname VARCHAR2, loc VARCHAR2)
  
RETURN NUMBER;
  
  
--刪除指定員工
  PROCEDURE remove_emp(empno NUMBER);
  
--刪除指定部門
  PROCEDURE remove_dept(deptno NUMBER);
  
--增加指定員工的工資
  PROCEDURE increase_sal(empno NUMBER, sal_incr NUMBER);
  
--增加指定員工的獎金
  PROCEDURE increase_comm(empno NUMBER, comm_incr NUMBER);
END MANAGE_EMP_PKG;--創建包說明結束

-- *******************************************
  -- 創建包體
  -- 包   名:MANAGE_EMP_PKG 
  -- 功能描述:對員工進行管理(新增員工,新增部門
  --            ,刪除員工,刪除部門,增加工資與獎金等)
  -- 創建人員:胡勇
  -- 創建日期:2010-05-19
  -- Q     Q: 80368704
  -- E-mail : [email protected]
  -- WebSite: http://www.cnblogs.com/huyong
--
 ******************************************
CREATE OR REPLACE PACKAGE BODY MANAGE_EMP_PKG 
AS
    total_emps  
NUMBER--員工數
    total_depts NUMBER--部門數
    no_sal    EXCEPTION;
    no_comm   EXCEPTION;
  
--增加一名員工 
  FUNCTION hire_emp(ename VARCHAR2, job VARCHAR2, mgr NUMBER,
                       sal 
NUMBER, comm NUMBER, deptno NUMBER)
  
RETURN NUMBER  --返回新增加的員工編號
  IS
    new_empno 
NUMBER(4);
  
BEGIN
SELECT empseq.NEXTVAL INTO new_empno FROM dual;
SELECT COUNT(*INTO total_emps FROM emp;--當前記錄總數

    
INSERT INTO emp 
    
VALUES (new_empno, ename, job, mgr, sysdate, sal, comm, deptno);
    total_emps:
=total_emps+1;
  
RETURN(new_empno);
  EXCEPTION
     
WHEN OTHERS THEN
        DBMS_OUTPUT.PUT_LINE(
'溫馨提示:發生系統錯誤!');
  
END hire_emp;
  
  
--新增一個部門
  FUNCTION add_dept(dname VARCHAR2, loc VARCHAR2)
  
RETURN NUMBER 
  
IS
    new_deptno 
NUMBER(4); --部門編號
  BEGIN
    
--得到一個新的自增的員工編號
    SELECT deptseq.NEXTVAL INTO new_deptno FROM dual;
    
SELECT COUNT(*INTO total_depts FROM dept;--當前部門總數
    INSERT INTO dept VALUES (new_deptno, dname, loc);
    total_depts:
=total_depts;
  
RETURN(new_deptno);
  EXCEPTION
     
WHEN OTHERS THEN
        DBMS_OUTPUT.PUT_LINE(
'溫馨提示:發生系統錯誤!');
  
END add_dept;
  
  
--刪除指定員工
  PROCEDURE remove_emp(empno NUMBER
  
IS
    no_result EXCEPTION; 
--自定義異常
  BEGIN 
    
DELETE FROM emp WHERE emp.empno=remove_emp.empno;
    
IF SQL%NOTFOUND THEN
        RAISE no_result;
    
END IF;
    total_emps:
=total_emps - 1--總的員工數減1
  EXCEPTION
     
WHEN no_result THEN 
        DBMS_OUTPUT.PUT_LINE(
'溫馨提示:你需要的數據不存在!');
     
WHEN OTHERS THEN
        DBMS_OUTPUT.PUT_LINE(
'溫馨提示:發生系統錯誤!');
  
END remove_emp;
  
  
--刪除指定部門
  PROCEDURE remove_dept(deptno NUMBER
  
IS
     no_result EXCEPTION; 
--自定義異常
     exception_deptno_remaining EXCEPTION; --自定義異常
     /*-2292 是違反一致性約束的錯誤代碼*/
     PRAGMA EXCEPTION_INIT(exception_deptno_remaining, 
-2292);
  
BEGIN
    
DELETE FROM dept WHERE dept.deptno=remove_dept.deptno;
    
    
IF SQL%NOTFOUND THEN
        RAISE no_result;
    
END IF;
    total_depts:
=total_depts-1--總的部門數減1
  EXCEPTION
     
WHEN no_result THEN 
        DBMS_OUTPUT.PUT_LINE(
'溫馨提示:你需要的數據不存在!');
     
WHEN exception_deptno_remaining THEN 
        DBMS_OUTPUT.PUT_LINE(
'溫馨提示:違反數據完整性約束!');
     
WHEN OTHERS THEN
        DBMS_OUTPUT.PUT_LINE(
'溫馨提示:發生系統錯誤!');
  
END remove_dept;

  
--給指定員工增加指定數量的工資
  PROCEDURE increase_sal(empno NUMBER, sal_incr NUMBER)
  
IS
    curr_sal 
NUMBER(72); --當前工資
  BEGIN
    
--得到當前工資
    SELECT sal INTO curr_sal FROM emp WHERE emp.empno=increase_sal.empno;
    
    
IF curr_sal IS NULL THEN 
       RAISE no_sal;
    
ELSE
       
UPDATE emp SET sal = sal + increase_sal.sal_incr --當前工資加新增的工資 
       WHERE emp.empno = increase_sal.empno;
    
END IF;
    EXCEPTION
       
WHEN NO_DATA_FOUND THEN 
          DBMS_OUTPUT.PUT_LINE(
'溫馨提示:你需要的數據不存在!');
       
WHEN no_sal THEN 
          DBMS_OUTPUT.PUT_LINE(
'溫馨提示:此員工的工資不存在!');
       
WHEN OTHERS THEN 
          DBMS_OUTPUT.PUT_LINE(
'溫馨提示:發生系統錯誤!');
  
END increase_sal;
  
  
--給指定員工增加指定數量的獎金
  PROCEDURE increase_comm(empno NUMBER, comm_incr NUMBER
  
IS
    curr_comm 
NUMBER(7,2);
  
BEGIN 
    
--得到指定員工的當前資金
    SELECT comm INTO curr_comm 
    
FROM emp WHERE emp.empno = increase_comm.empno;
    
    
IF curr_comm IS NULL THEN 
       RAISE no_comm;
    
ELSE
      
UPDATE emp SET comm = comm + increase_comm.comm_incr
      
WHERE emp.empno=increase_comm.empno;
    
END IF;
  EXCEPTION
     
WHEN NO_DATA_FOUND THEN 
        DBMS_OUTPUT.PUT_LINE(
'溫馨提示:你需要的數據不存在!');
     
WHEN no_comm THEN 
        DBMS_OUTPUT.PUT_LINE(
'溫馨提示:此員工的獎金不存在!');
     
WHEN OTHERS THEN 
        DBMS_OUTPUT.PUT_LINE(
'溫馨提示:發生系統錯誤!');
  
END increase_comm;
END MANAGE_EMP_PKG;--創建包體結束

--調用
SQL> variable empno number
SQL
>execute  :empno:= manage_emp_pkg.hire_emp('HUYONG',PM,1455,5500,14,10)

PL
/SQL procedure successfully completed
empno
---------
105

 

例4:利用遊標變量創建包 CURROR_VARIBAL_PKG。由於遊標變量指是一個指針,其狀態是不確定的,因此它不能隨同包存儲在數據庫中,既不能在PL/SQL包中聲明遊標變量。但在包中可以創建遊標變量參照類型,並可向包中的子程序傳遞遊標變量參數。

-- *******************************************
  -- 創建包體
  -- 包   名:CURROR_VARIBAL_PKG 
  -- 功能描述:在包中引用遊標變量
  -- 創建人員:胡勇
  -- 創建日期:2010-05-19
  -- Q     Q: 80368704
  -- E-mail : [email protected]
  -- WebSite: http://www.cnblogs.com/huyong
--
 ******************************************
CREATE OR REPLACE PACKAGE CURROR_VARIBAL_PKG AS
  TYPE DeptCurType 
IS REF CURSOR 
  
RETURN dept%ROWTYPE; --強類型定義
  
  TYPE CurType 
IS REF CURSOR;-- 弱類型定義
  
  
PROCEDURE OpenDeptVar(
    Cv 
IN OUT DeptCurType,
    Choice 
INTEGER DEFAULT 0,
    Dept_no 
NUMBER DEFAULT 50,
    Dept_name 
VARCHAR DEFAULT '%');
END;

-- *******************************************
  -- 創建包體
  -- 包   名:CURROR_VARIBAL_PKG 
  -- 功能描述:在包中引用遊標變量
  -- 創建人員:胡勇
  -- 創建日期:2010-05-19
  -- Q     Q: 80368704
  -- E-mail : [email protected]
  -- WebSite: http://www.cnblogs.com/huyong
--
 ******************************************
CREATE OR REPLACE PACKAGE BODY CURROR_VARIBAL_PKG
AS
  
PROCEDURE OpenDeptvar(
    Cv 
IN OUT DeptCurType,
    Choice 
INTEGER DEFAULT 0,
    Dept_no 
NUMBER DEFAULT 50,
    Dept_name 
VARCHAR DEFAULT ‘%’)
  
IS 
  
BEGIN
    
IF choice =1 THEN
      
OPEN cv FOR SELECT * FROM dept WHERE deptno <= dept_no;
    ELSIF choice 
= 2 THEN
      
OPEN cv FOR SELECT * FROM dept WHERE dname LIKE dept_name;
    
ELSE
      
OPEN cv FOR SELECT * FROM dept;
    
END IF;
  
END OpenDeptvar;
END CURROR_VARIBAL_PKG;

--定義一個過程
CREATE OR REPLACE PROCEDURE UP_OpenCurType(
  Cv 
IN OUT CURROR_VARIBAL_PKG.CurType,
  FirstCapInTableName 
CHAR
AS
BEGIN
  
--CURROR_VARIBAL_PKG.CurType採用弱類型定義
  --所以可以使用它定義的遊標變量打開不同類型的查詢語句
  IF FirstCapInTableName = 'D' THEN
    
OPEN cv FOR SELECT * FROM dept;
  
ELSE
    
OPEN cv FOR SELECT * FROM emp;
  
END IF;
END UP_OpenCurType;


--定義一個應用
DECLARE 
  DeptRec Dept
%ROWTYPE;
  EmpRec Emp
%ROWTYPE;
  Cv1 CURROR_VARIBAL_PKG.deptcurtype;
  Cv2 CURROR_VARIBAL_PKG.curtype;
BEGIN
  DBMS_OUTPUT.PUT_LINE(
'遊標變量強類型定義應用');
  CURROR_VARIBAL_PKG.OpenDeptVar(cv1, 
130);
  
FETCH cv1 INTO DeptRec;
  
WHILE cv1%FOUND LOOP
    DBMS_OUTPUT.PUT_LINE(DeptRec.deptno
||':'||DeptRec.dname);
    
FETCH cv1 INTO DeptRec;
  
END LOOP;
  
CLOSE cv1;

  DBMS_OUTPUT.PUT_LINE(
'遊標變量弱類型定義應用');
  CURROR_VARIBAL_PKG.OpenDeptvar(cv2, 
2, dept_name => 'A%');
  
FETCH cv2 INTO DeptRec;
  
WHILE cv2%FOUND LOOP
    DBMS_OUTPUT.PUT_LINE(DeptRec.deptno
||':'||DeptRec.dname);
    
FETCH cv2 INTO DeptRec;
  
END LOOP;

  DBMS_OUTPUT.PUT_LINE(
'遊標變量弱類型定義應用—dept表');
  UP_OpenCurType(cv2, 
'D');
  
FETCH cv2 INTO DeptRec;
  
WHILE cv2%FOUND LOOP
    DBMS_OUTPUT.PUT_LINE(deptrec.deptno
||':'||deptrec.dname);
    
FETCH cv2 INTO deptrec;
  
END LOOP;

  DBMS_OUTPUT.PUT_LINE(
'遊標變量弱類型定義應用—emp表');
  UP_OpenCurType(cv2, 
'E');
  
FETCH cv2 INTO EmpRec;
  
WHILE cv2%FOUND LOOP
    DBMS_OUTPUT.PUT_LINE(emprec.empno
||':'||emprec.ename);
    
FETCH cv2 INTO emprec;
  
END LOOP;
  
CLOSE cv2;
END;
----------運行結果-------------------
遊標變量強類型定義應用
10:ACCOUNTING
20:RESEARCH
30:SALES
遊標變量弱類型定義應用
10:ACCOUNTING
遊標變量弱類型定義應用—dept表
10:ACCOUNTING
20:RESEARCH
30:SALES
40:OPERATIONS
50:50abc
60:Developer
遊標變量弱類型定義應用—emp表
7369:SMITH
7499:ALLEN
7521:WARD
7566:JONES
7654:MARTIN
7698:BLAKE
7782:CLARK
7788:SCOTT
7839:KING
7844:TURNER
7876:ADAMS
7900:JAMES
7902:FORD
7934:MILLER
 
PL
/SQL procedure successfully completed

7.5  子程序重載

PL/SQL 允許對包內子程序和本地子程序進行重載。所謂重載時指兩個或多個子程序有相同的名稱,但擁有不同的參數變量、參數順序或參數數據類型。

例5:

-- *******************************************
  -- 創建包說明
  -- 包   名:DEMO_PKG1 
  -- 功能描述:創建包對子程序重載進行測試
  -- 創建人員:胡勇
  -- 創建日期:2010-05-22
  -- Q     Q: 80368704
  -- E-mail : [email protected]
  -- WebSite: http://www.cnblogs.com/huyong
--
 ******************************************
CREATE OR REPLACE PACKAGE DEMO_PKG1
IS
    DeptRec dept
%ROWTYPE;
    V_sqlcode 
NUMBER;
    V_sqlerr 
VARCHAR2(2048);
  
  
--兩個子程序名字相同,但參數類型不同
    FUNCTION query_dept(dept_no IN NUMBER)
    
RETURN INTEGER;
  
    
FUNCTION query_dept(dept_no IN VARCHAR2)
    
RETURN INTEGER;
END DEMO_PKG1;

-- *******************************************
  -- 創建包體
  -- 包   名:DEMO_PKG1 
  -- 功能描述:創建包對子程序重載進行測試
  -- 創建人員:胡勇
  -- 創建日期:2010-05-22
  -- Q     Q: 80368704
  -- E-mail : [email protected]
  -- WebSite: http://www.cnblogs.com/huyong
--
 ******************************************
CREATE OR REPLACE PACKAGE BODY DEMO_PKG1
IS 
  
FUNCTION check_dept(dept_no NUMBER)
  
RETURN INTEGER
  
IS
    deptCnt 
INTEGER--指定部門號的部門數量
  BEGIN
    
SELECT COUNT(*INTO deptCnt FROM dept WHERE deptno = dept_no;
    
IF deptCnt > 0 THEN
      
RETURN 1;
    
ELSE
      
RETURN 0;
    
END IF;
  
END check_dept;

  
FUNCTION check_dept(dept_no VARCHAR2)
  
RETURN INTEGER
  
IS
    deptCnt 
INTEGER;
  
BEGIN
    
SELECT COUNT(*INTO deptCnt FROM dept WHERE deptno=dept_no;
    
IF deptCnt > 0 THEN
      
RETURN 1;
    
ELSE
      
RETURN 0;
    
END IF;
  
END check_dept;

  
FUNCTION query_dept(dept_no IN NUMBER)
  
RETURN INTEGER
  
IS
  
BEGIN
    
IF check_dept(dept_no) =1 THEN
      
SELECT * INTO DeptRec FROM dept WHERE deptno=dept_no;
      
RETURN 1;
    
ELSE
      
RETURN 0;
    
END IF;
  
END query_dept;

  
FUNCTION query_dept(dept_no IN VARCHAR2)
    
RETURN INTEGER
  
IS
  
BEGIN
    
IF check_dept(dept_no) =1 THEN
      
SELECT * INTO DeptRec FROM dept WHERE deptno = dept_no;
      
RETURN 1;
    
ELSE
      
RETURN 0;
    
END IF;
  
END query_dept;

END DEMO_PKG1;

7.6  加密實用程序

ORACLE 提供了一個實用工具來加密或者包裝用戶的PL/SQL,它會將用戶的PL/SQL改變爲只有ORACLE能夠解釋的代碼版本.

WRAP 實用工具位於$ORACLE_HOME/BIN.

 

格式爲:

WRAP INAME=<input_file_name> [ONAME=<output_file_name>]

 

wrap iname=e:/sample.txt

 

注意:在加密前,請將PL/SQL程序先保存一份,以備後用。

7.7  刪除包

可以使用 DROP PACKAGE 命令對不需要的包進行刪除,語法如下:

DROP PACKAGE [BODY] [user.]package_name;

DROP PROCEDURE OpenCurType; --刪除存儲過程
--
刪除我們實例中創建的各個包
DROP PACKAGE demo_pack;
DROP PACKAGE demo_pack1;
DROP PACKAGE emp_mgmt;
DROP PACKAGE emp_package;

7.8  包的管理

包與過程、函數一樣,也是存儲在數據庫中的,可以隨時查看其源碼。若有需要,在創建包時可以隨時查看更詳細的編譯錯誤。不需要的包也可以刪除。

同樣,爲了避免調用的失敗,在更新表的結構後,一定要記得重新編譯依賴於它的程序包。在更新了包說明或包體後,也應該重新編譯包說明與包體。語法如下:

ALTER PACKAGE package_name COMPILE [PACKAGE|BODY|SPECIFICATION];

 

 

也可以通過以下數據字典視圖查看包的相關。

DBA_SOURCE, USER_SOURCE, USER_ERRORS, DBA-OBJECTS  

 

如,我們可以用:select text from user_source where name = 'DEMO_PKG1';來查看我們創建的包的源碼。

 

 

 

© 2011  EricHu

原創作品,轉貼請註明作者和出處,留此信息。

 

------------------------------------------------

cnBlobs:http://www.cnblogs.com/huyong/
CSDNhttp://blog.csdn.NET/chinahuyong 

 

作者:EricHuDBC/SB/SWebServiceWCFPM等)
出處:http://www.cnblogs.com/huyong/

Q Q80368704   E-Mail: [email protected]
本博文歡迎大家瀏覽和轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,在『參考』的文章中,我會表明參考的文章來源,尊重他人版權。若您發現我侵犯了您的版權,請及時與我聯繫。
更多文章請看 [置頂]索引貼——(不斷更新中)

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章