第十四章:包

目錄

一、概述

二、包的創建

三、包的調用與刪除 

四、子程序重載


一、概述

什麼是包?

包是一組相關過程、函數、變量、常量和遊標等PL/SQL程序設計元素的組合。類似於Java裏面的類(class)。包中的程序元素分爲兩種:公用元素(公用組件)和私用元素(私用組件)。

特點:

  • 具有面向對象程序設計語言的特點,是對PL/SQL程序設計元素(過程、函數、變量)的封裝。
  • 使程序設計模塊化

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

  • 包規範(包定義):用於定義包的公共組件,包括常量、變量、遊標、過程和函數等。
  • 包體(包主體):用於實現包規範所定義的公用過程和函數。包體不僅可用於實現公用過程和函數,而且還可定義包的私有組件(變量、遊標、過程、函數等)。
--創建包規範
CREATE OR REPLACE PACKAGE first_package
IS
       v_no emp.deptno%TYPE:=10;
       --過程
       PROCEDURE query_emp(v_deptno IN NUMBER DEFAULT v_no,v_avgsal OUT NUMBER, v_cnt OUT NUMBER);
END first_package;

--創建包體
CREATE OR REPLACE PACKAGE BODY first_package
IS
       PROCEDURE query_emp(v_deptno IN NUMBER DEFAULT v_no,v_avgsal OUT NUMBER, v_cnt OUT NUMBER)
       IS
       BEGIN
            SELECT avg(sal), count(*)
            INTO v_avgsal, v_cnt
            FROM emp
            WHERE deptno = v_deptno;
       EXCEPTION
            WHEN NO_DATA_FOUND THEN
                 DBMS_OUTPUT.put_line('沒有此部門!');
            WHEN OTHERS THEN
                 DBMS_OUTPUT.put_line(SQLERRM);
       END;
END first_package;

--調用
DECLARE
    v_avgsal NUMBER;
    v_cnt    NUMBER;
BEGIN
    first_package.query_emp(20,v_avgsal,v_cnt);
	--v_deptno採用默認值時,需要使用名稱傳遞這種傳值方式
	--first_package.query_emp(v_avgsal => v_avgsal,v_cnt => v_cnt);
    DBMS_OUTPUT.put_line('平均工資:'||v_avgsal);
    DBMS_OUTPUT.put_line('總人數:'||v_cnt);
END;

二、包的創建

--創建包規範
CREATE OR REPLACE PACKAGE emp_package
IS
       --添加員工信息的存儲過程
       PROCEDURE add_emp_proc
       (v_empno IN emp.empno%TYPE,
        v_ename IN emp.ename%type,
        v_sal   IN emp.sal%type,
        v_deptno IN emp.deptno%type);
        
        --刪除員工信息的存儲過程
        PROCEDURE del_emp_proc
        (v_empno IN emp.empno%type);
END emp_package;

--創建包體
CREATE OR REPLACE PACKAGE BODY emp_package
IS
        --添加員工信息的存儲過程
       PROCEDURE add_emp_proc
       (v_empno IN emp.empno%TYPE,
        v_ename IN emp.ename%type,
        v_sal   IN emp.sal%type,
        v_deptno IN emp.deptno%type)
        IS
                 e_2291  EXCEPTION;
                 PRAGMA EXCEPTION_INIT(e_2291,-2291);                
                 
        BEGIN
                 INSERT INTO emp(empno, ename, sal, deptno) VALUES(v_empno,v_ename,v_sal,v_deptno);
        EXCEPTION
                 WHEN DUP_VAL_ON_INDEX THEN
                   RAISE_APPLICATION_ERROR(-20001,'員工號不能重複');
                 WHEN e_2291 THEN
                   RAISE_APPLICATION_ERROR(-20008,'部門號不存在');
                 
        END;
        
        --刪除員工信息的存儲過程        
        PROCEDURE del_emp_proc
        (v_empno IN emp.empno%type)
        IS
        BEGIN
          --根據員工號刪除指定的員工信息
          DELETE FROM emp WHERE empno = v_empno;
          --判斷是否刪除成功
          IF SQL%NOTFOUND THEN
             RAISE_APPLICATION_ERROR(-20009,'指定刪除的員工不存在');
          ELSE
             DBMS_OUTPUT.put_line('刪除成功');
          END IF;
        END;
END emp_package;
--根據員工號查詢工資,如果工資小於等於3000,工資漲500.

--創建包規範
CREATE OR REPLACE PACKAGE emp_sal_pkg
IS
       FUNCTION get_sal(eno NUMBER)RETURN NUMBER;
       
       PROCEDURE upd_sal(eno NUMBER, salary NUMBER);
END emp_sal_pkg;

--包體
CREATE OR REPLACE PACKAGE BODY emp_sal_pkg
IS
	   --根據員工號查詢員工的工資
       FUNCTION get_sal(eno NUMBER)RETURN NUMBER
       IS
                v_sal emp.sal%TYPE:= 0;
       BEGIN
                SELECT sal INTO v_sal FROM emp WHERE empno = eno;
                RETURN v_sal;
       EXCEPTION
                WHEN NO_DATA_FOUND THEN
                     RAISE_APPLICATION_ERROR(-20008,'此員工號不存在!');
       END;
       
	   --更新滿足條件的員工的工資
       PROCEDURE upd_sal(eno NUMBER, salary NUMBER)
       IS
       BEGIN
                IF salary<=3000 THEN
                    UPDATE emp SET sal = sal + 500 WHERE empno = eno;
                END IF;
       END;
END  emp_sal_pkg;

三、包的調用與刪除 

--示例一:調用emp_package包下添加員工信息的存儲過程
DECLARE
    v_empno emp.empno%TYPE:=&empno;
    v_ename emp.ename%TYPE:='&name';
    v_sal   emp.sal%TYPE:=&salary;
    v_deptno emp.deptno%TYPE:=&deptno;
    e_dup_val  EXCEPTION;
    e_no_dept  EXCEPTION;    
    PRAGMA EXCEPTION_INIT(e_dup_val,-20001);
    PRAGMA EXCEPTION_INIT(e_no_dept,-20008);
BEGIN
    emp_package.add_emp_proc(v_empno,v_ename,v_sal,v_deptno);
    COMMIT;
EXCEPTION
    WHEN e_dup_val THEN
         DBMS_OUTPUT.put_line(SQLERRM);
    WHEN e_no_dept THEN
         DBMS_OUTPUT.put_line(SQLERRM);
    ROLLBACK;
END;

SELECT * FROM EMP;

--示例二:調用emp_package包下刪除指定員工的存儲過程
DECLARE
    v_empno emp.empno%TYPE:=&empno;
    e_no_emp   EXCEPTION;
    PRAGMA EXCEPTION_INIT(e_no_emp,-20009);
BEGIN
    emp_package.del_emp_proc(v_empno);
    COMMIT;
EXCEPTION
    WHEN e_no_emp THEN
        DBMS_OUTPUT.put_line(SQLERRM); 
        ROLLBACK;
END;

--示例三:調用emp_sal_pkg包下函數和過程
DECLARE
        v_empno emp.empno%TYPE := &empno;
        v_salary emp.sal%TYPE;
        e_no_emp   EXCEPTION;
        PRAGMA EXCEPTION_INIT(e_no_emp,-20008);
BEGIN
        v_salary:= emp_sal_pkg.get_sal(v_empno);
        emp_sal_pkg.upd_sal(v_empno,v_salary);
        COMMIT;
EXCEPTION
    WHEN e_no_emp THEN
        DBMS_OUTPUT.put_line(SQLERRM);           
END; 

--用SQLPLUS命令調用(下述命令請在command窗口或SQLPLUS窗口執行)
/*
VAR  v_empno  NUMBER
EXEC :v_empno := &no
VAR  v_salary  NUMBER
EXEC :v_salary := emp_sal_pkg.get_sal(:v_empno)
EXEC emp_sal_pkg.upd_sal(:v_empno, :v_salary)
*/

--刪除包
DROP PACKAGE first_package;
--刪除包體
DROP PACKAGE BODY first_package;

四、子程序重載

子程序重載是指兩個或多個子程序有相同的名稱,但擁有不同的參數變量、參數順序或參數數據類型

--根據員工號或員工姓名獲取員工的信息
--根據員工號或員工姓名刪除員工的信息
--創建包規範
CREATE OR REPLACE PACKAGE overload_pkg
IS
       FUNCTION get_info(eno NUMBER) RETURN emp%ROWTYPE;
       FUNCTION get_info(name VARCHAR2) RETURN emp%ROWTYPE;
       
       PROCEDURE del_emp(eno NUMBER);
       PROCEDURE del_emp(name VARCHAR2);
END;

--創建包體
CREATE OR REPLACE PACKAGE BODY overload_pkg
IS
       FUNCTION get_info(eno NUMBER) RETURN emp%ROWTYPE
       IS
                emp_record  emp%ROWTYPE;
       BEGIN
                SELECT * INTO emp_record FROM emp WHERE empno = eno;
                RETURN emp_record;    
       EXCEPTION
                WHEN NO_DATA_FOUND THEN
                     RAISE_APPLICATION_ERROR(-20020,'不存在此員工!');
       END;
       
       FUNCTION get_info(name VARCHAR2) RETURN emp%ROWTYPE
       IS 
                emp_record  emp%ROWTYPE;
       BEGIN
                SELECT * INTO emp_record FROM emp WHERE ename = name;
                RETURN emp_record; 
       EXCEPTION
                WHEN NO_DATA_FOUND THEN
                     RAISE_APPLICATION_ERROR(-20020,'不存在此員工!');
       END;       
       
       PROCEDURE del_emp(eno NUMBER)
       IS
       BEGIN
                 DELETE FROM emp WHERE empno = eno;
                 IF SQL%NOTFOUND THEN
                    RAISE_APPLICATION_ERROR(-20020,'不存在此員工');
                 END IF;
       END;
       
       PROCEDURE del_emp(name VARCHAR2)
       IS
       BEGIN
                 DELETE FROM emp WHERE ename = name;
                 IF SQL%NOTFOUND THEN
                    RAISE_APPLICATION_ERROR(-20020,'不存在此員工');
                 END IF;
       END;
END;

--調用
--根據員工號查詢員工信息
DECLARE
       emp_record emp%rowtype;
       e_no_emp  EXCEPTION;
       PRAGMA EXCEPTION_INIT(e_no_emp,-20020);
BEGIN
       emp_record:= overload_pkg.get_info(&no);
       DBMS_OUTPUT.PUT_LINE('員工號:'||emp_record.empno||'姓名:'||emp_record.ename||'工資:'||emp_record.sal);
EXCEPTION
       WHEN e_no_emp THEN
            DBMS_OUTPUT.put_line(SQLERRM);
END;

--根據員工姓名查詢員工信息
DECLARE
       emp_record emp%rowtype;
       e_no_emp  EXCEPTION;
       PRAGMA EXCEPTION_INIT(e_no_emp,-20020);
BEGIN
       emp_record:= overload_pkg.get_info('&name');
       DBMS_OUTPUT.PUT_LINE('員工號:'||emp_record.empno||'姓名:'||emp_record.ename||'工資:'||emp_record.sal);
EXCEPTION
       WHEN e_no_emp THEN
            DBMS_OUTPUT.put_line(SQLERRM);
END;

--根據員工號刪除員工信息
DECLARE
       e_no_emp EXCEPTION;
       PRAGMA EXCEPTION_INIT(e_no_emp, -20020);
BEGIN
       overload_pkg.del_emp(&no);
       COMMIT;
EXCEPTION
       WHEN e_no_emp THEN
            DBMS_OUTPUT.put_line(SQLERRM);
       ROLLBACK;
END;  

SELECT * FROM EMP;

--根據員工的姓名刪除員工的信息
DECLARE
       e_no_emp EXCEPTION;
       PRAGMA EXCEPTION_INIT(e_no_emp, -20020);
BEGIN
       overload_pkg.del_emp('&name');
       COMMIT;
EXCEPTION
       WHEN e_no_emp THEN
            DBMS_OUTPUT.put_line(SQLERRM);
       ROLLBACK;
END;  

 

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