PL/SQL --> 包的创建与管理

系统 1565 0

--============================

-- PL/SQL --> 包的创建与管理

--============================

 

    包,是一个逻辑集合,是由 PL / SQL 类型以及 PL / SQL 子程序的集合。 PL / SQL 类型包括 table 类型, record 类型。 PL / SQL 项则包括游标,游标

变量。 PL / SQL 子程序包括过程,函数等。可以说包可谓是包罗万象。是所有 PL / SQL 相关资源的汇总。

    包的使用可以简化应用程序设计,实现信息掩藏,子程序重载等功能。

    包的优点

        1. 模块化:将函数,子程序全部融合在一起,使得成为一个有机的整体,封装了相关的结构。

        2. 易于维护:整合了子程序,更易于维护

        3. 简化应用程序设计:包的声明与包体内容相分离。

        4. 隐藏信息:私有对象不可访问,所有的包体内代码可以实现隐藏。

        5. 节省 I / O :一次编译,多次使用。

   

一、包的组成与创建语法

    包头:用于定义包的公共组件,如函数头,过程头,游标等以及常量,变量等。包头中定义的公共组件可以在包内引用,也可以被其

        它子程序引用。

    包体:用于定义包头中定义过的过程和函数。可以单独定义私有组件,包括变量,常量,过程和函数等。私有组件只能在包内使用,而

        不能被其它子程序所调用。

        一言以蔽之,包头定义包的声明及描述部分,而包体则定义了对应包的具体执行部分。

    创建包的语法:

        CREATE [OR REPLACE] PACKAGE package_name      -- 定义包头

        { AS|IS}

            public_variable_declarations |

            public_type_declarations |

            public_exception_declarations |  

            public_cursor_declarations |

            function_declarations |

            procedure_specifications

        END [package_name]  

       

        CREATE [OR REPLACE] PACKAGE BODY package_name    -- 定义包体,包体中的 package_name 应当与包头中的 package_name 相同

        { AS|IS}  

            private_variable_declarations |

            private_type_declarations |

            private_exception_declarations |

            private_cursor_declarations |  

            function_declarations |

            procedure_specifications  

        END [package_name]  

 

二、创建包         

    下面演示包的创建,基于用户 scott 创建,存储过程,函数等依赖于其下的对象

    1. 创建包头

        CREATE OR REPLACE PACKAGE emp_package IS     -- 创建包头,包的名字为 emp_package

            g_deptno NUMBER ( 3 ) := 30 ;                -- 定义一个公共变量 g_deptno

            PROCEDURE add_employee ( eno NUMBER , name VARCHAR2 , salary NUMBER , dno NUMBER DEFAULT g_deptno ); -- 声明过程

            PROCEDURE fire_employee ( eno NUMBER );                                                            -- 声明过程

            FUNCTION get_sal ( eno NUMBER ) RETURN NUMBER ;                                                     -- 声明函数

        END emp_package ;

        /

 

    2. 创建包体  

        CREATE OR REPLACE PACKAGE BODY emp_package IS     -- 创建包体,注意,包体中包的名字必须与包头的名字相一致

            FUNCTION validate_deptno ( v_deptno NUMBER ) RETURN BOOLEAN   -- 创建一个私有函数 , , 此私有函数不能该包外子程序调用

            IS

                v_temp INT ;

            BEGIN

                SELECT 1 INTO v_temp FROM dept WHERE deptno = v_deptno ;

                RETURN TRUE ;

            EXCEPTION

                WHEN NO_DATA_FOUND THEN

                    RETURN FALSE ;

            END ;

           

            PROCEDURE add_employee    -- 创建添加雇员的过程

                ( eno NUMBER , name VARCHAR2 , salary NUMBER , dno NUMBER DEFAULT g_deptno ) IS

            BEGIN

                IF validate_deptno ( dno ) THEN    -- 该过程调用了包内的一个函数 validate_deptno 来验证 dno 的有效性

                    INSERT INTO emp ( empno , ename , sal , deptno ) VALUES ( eno , name , salary , dno );

                ELSE

                    RAISE_APPLICATION_ERROR (- 20000 , ' 不存在该部门 ' );

                END IF ;

            EXCEPTION

                WHEN DUP_VAL_ON_INDEX THEN

                    RAISE_APPLICATION_ERROR (- 20011 , ' 该雇员已存在 ' );

            END ;

 

            PROCEDURE fire_employee ( eno NUMBER ) IS   -- 创建解除雇员的过程

            BEGIN

                DELETE FROM emp WHERE empno = eno ;

                IF SQL % NOTFOUND THEN

                    RAISE_APPLICATION_ERROR (- 20012 , ' 该雇员不存在 ' );

                END IF ;

            END ;

 

            FUNCTION get_sal ( eno NUMBER ) RETURN NUMBER IS   -- 创建函数 get_sal 返回雇员的薪水

                v_sal emp . sal % TYPE ;

            BEGIN

                SELECT sal INTO v_sal FROM emp WHERE empno = eno ;

                RETURN v_sal ;

            EXCEPTION

                WHEN NO_DATA_FOUND THEN

                    RAISE_APPLICATION_ERROR (- 20012 , ' 该雇员不存在 ' );

            END ;

        END emp_package ;

        /

   

    3. 创建仅包含包头的包 ( 仅包含包头的包也可以被调用,具体参照后面的包的调用 )

        CREATE OR REPLACE PACKAGE global_int

        IS

          g_positive   CONSTANT NUMBER := 10 ;

          g_negative CONSTANT NUMBER :=- 10 ;

        END global_int ;

               

三、包的调用

        对于包的私有对象只能在包内调用。如上面的例子中对包内私有函数 validate_deptno 进行了直接调用

        对于包的公共对象,既可以在包内调用,也可以由其他应用程序调用。使用其他应用程序调用时的方法:包名 . 包对象

       

    1. 调用包的公共变量

        scott@ORCL > exec emp_package . g_deptno := 10 ;

       

    2. 调用包的公共过程

        scott@ORCL > exec emp_package . add_employee ( 2222 , 'Robinson' , 3000 ); -- 此调用未指定部门号,则使用缺省值 , 但前面执行了

                                                                         --exec emp_package.g_deptno:=10; 故部门号变为

        scott@ORCL > exec emp_package . add_employee ( 3333 , 'Jackson' , 4000 , 20 );

 

        scott@ORCL > select * from emp where empno in( 2222 , 3333 );

 

              EMPNO ENAME       JOB               MGR HIREDATE          SAL        COMM      DEPTNO

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

              2222 Robinson                                         3000                     10

              3333 Jackson                                          4000                     20       

   

    3. 调用包的公共函数

        scott@ORCL > var sal number

        scott@ORCL > exec : sal := emp_package . get_sal ( 7788 );

 

        PL / SQL procedure successfully completed .

 

        scott@ORCL > print sal

 

               SAL

        ----------

              310       

             

    4. 以不同用户身份调用包 . 需要使用 schema 名字来调用,即:用户名 . 包名 . 包对象名

        scott@ORCL > conn lion / lion    -- 注意帐户需要具有执行所调用包的权限

       

        lion@ORCL > exec scott . emp_package . fire_employee ( 2222 );      

   

    5. 调用远程数据库包的公共对象。调用方法 : 包名 . 包对象名 @ 数据库链接名

        sys@ASMDB > create database link orcl

          2   connect to lion identified by lion

          3   using 'orcl' ;

 

        Database link created .

       

        sys@ASMDB > exec scott . emp_package . add_employee@orcl ( 4444 , 'Richard' , 4000 );

        BEGIN scott . emp_package . add_employee@orcl ( 4444 , 'Richard' , 4000 ); END ;

 

              *

        ERROR at line 1 :

        ORA - 06550 : line 1 , column 7 :    -- 注意远程调用时,对于缺省的参数不适用,需要明确指定参数

        PLS - 00424 : RPC defaults cannot include Package State

        ORA - 06550 : line 1 , column 7 :

        PL / SQL : Statement ignored   

       

        sys@ASMDB > exec scott . emp_package . add_employee@orcl ( 4444 , 'Richard' , 4000 , 20 );   -- 下面的调用被成功执行

 

        PL / SQL procedure successfully completed .

       

    6. 无包体包的调用 ( 使用前面创建的包 global_int )    

        scott@ORCL > BEGIN

          2   DBMS_OUTPUT . PUT_LINE ( 'Result is : ' || 2 * global_int . g_positive ); -- 使用包 DBMS_OUTPUT 来调用

          3   END ;

          4   /

        Result is : 20

 

        PL / SQL procedure successfully completed .    

           

        scott@ORCL > CREATE OR REPLACE FUNCTION f_negative ( m number )    -- 将包嵌入到函数之中

          2   RETURN NUMBER

          3   IS

          4   BEGIN

          5     RETURN ( m * global_int . g_negative );

          6   END f_negative ;

          7   /

 

        Function created .

 

        scott@ORCL > EXEC DBMS_OUTPUT . PUT_LINE ( f_negative ( 2 ));

        - 20

 

        PL / SQL procedure successfully completed .

四、包的管理

    1. 查看包

        scott@ORCL > select line , text from user_source         -- 查看包头

          2   where name = 'EMP_PACKAGE' and type = 'PACKAGE' ;

 

              LINE TEXT

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

                  1 PACKAGE emp_package IS

                  2    g_deptno NUMBER ( 3 ) := 30 ;

                  3    PROCEDURE add_employee ( eno NUMBER , name VARCHAR2 , salary N

                   UMBER , dno NUMBER DEFAULT g_deptno );

 

                  4    PROCEDURE fire_employee ( eno NUMBER );

                  5    FUNCTION get_sal ( eno NUMBER ) RETURN NUMBER ;

                  6 END emp_package ;

 

           

        scott@ORCL > select line , text from user_source      -- 查看包体

          2   where name = 'EMP_PACKAGE' and type = 'PACKAGE BODY' ;

 

              LINE TEXT

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

                  1 PACKAGE BODY emp_package IS

                  2    FUNCTION validate_deptno ( v_deptno NUMBER ) RETURN BOOLEAN IS

                  3      v_temp INT ;

                  4    BEGIN

                  5      SELECT 1 INTO v_temp FROM dept WHERE deptno = v_deptno ;

                  6      RETURN TRUE ;

                            ......................

                 

    2. 查看包的参数

        scott@ORCL > desc emp_package ;

        PROCEDURE ADD_EMPLOYEE

          Argument Name                   Type                     In/ Out Default ?

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

          ENO                             NUMBER                   IN

          NAME                            VARCHAR2                 IN

          SALARY                          NUMBER                   IN

          DNO                             NUMBER                   IN      DEFAULT

        PROCEDURE FIRE_EMPLOYEE

          Argument Name                   Type                     In/ Out Default ?

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

          ENO                             NUMBER                   IN

        FUNCTION GET_SAL RETURNS NUMBER

          Argument Name                   Type                     In/ Out Default ?

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

          ENO                             NUMBER                   IN

         

    3. 包的删除

        DROP PACKAGE package_name    -- 同时删除包体和包头

       

        scott@ORCL > DROP PACKAGE global_int ;

       

        删除包体,保留包头

            DROP PACKAGE BODY package_name    -- 删除包体

           

        scott@ORCL > drop package body emp_package ;

 

        Package body dropped .

 

    4.包的编译

          重新编译包规范和包体:alter package...compile
          重新编译包规范:alter package...compile specification
          重新编译包体:alter package...compile body

      

五、总结

    创键包体之前应该先创建包头

    包头应当仅仅包含那些希望作为公共对象的部分

    包头的声明应包含尽可能少的结构信息

    任意包头的变更,需要重新编译该包内的子程序

    在包头内定义的任意公共对象可以被任意内部或外部子程序调用

    包体内的私有对象仅仅能被该包体内的子程序调用

   

六、更多参考

有关 SQL 请参考

        SQL 基础--> 子查询

        SQL 基础--> 多表查询

SQL 基础--> 分组与分组函数

SQL 基础--> 常用函数

SQL 基础--> ROLLUP 与CUBE 运算符实现数据汇总

SQL 基础--> 层次化查询(START BY ... CONNECT BY PRIOR)

 

    有关 PL/SQL 请参考

        PL/SQL --> 语言基础

PL/SQL --> 流程控制

PL/SQL --> 存储过程

PL/SQL --> 函数

PL/SQL --> 游标

PL/SQL --> 隐式游标(SQL%FOUND)

PL/SQL --> 异常处理(Exception)

PL/SQL --> PL/SQL 记录

PL/SQL --> 包的创建与管理

PL/SQL --> 包重载、初始化

PL/SQL --> DBMS_DDL 包的使用

PL/SQL --> DML 触发器

PL/SQL --> INSTEAD OF 触发器

 

 

       

PL/SQL --> 包的创建与管理


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论