• 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 : 80368704@yahoo.com.cn
      -- 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 : 80368704@yahoo.com.cn
      -- 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(7, 2); --当前工资
      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 : 80368704@yahoo.com.cn
      -- 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 : 80368704@yahoo.com.cn
      -- 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, 1, 30);
      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 : 80368704@yahoo.com.cn
      -- 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 : 80368704@yahoo.com.cn
      -- 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';来查看我们创建的包的源码。

  • 相关阅读:
    CodeForces 156B Suspects(枚举)
    CodeForces 156A Message(暴力)
    CodeForces 157B Trace
    CodeForces 157A Game Outcome
    HDU 3578 Greedy Tino(双塔DP)
    POJ 2609 Ferry Loading(双塔DP)
    Java 第十一届 蓝桥杯 省模拟赛 19000互质的个数
    Java 第十一届 蓝桥杯 省模拟赛 19000互质的个数
    Java 第十一届 蓝桥杯 省模拟赛 19000互质的个数
    Java 第十一届 蓝桥杯 省模拟赛十六进制转换成十进制
  • 原文地址:https://www.cnblogs.com/ywsoftware/p/2886500.html
Copyright © 2020-2023  润新知