Chinaunix首页 | 论坛 | 博客
  • 博客访问: 363683
  • 博文数量: 56
  • 博客积分: 2721
  • 博客等级: 中校
  • 技术积分: 460
  • 用 户 组: 普通用户
  • 注册时间: 2008-07-29 16:18
文章分类

全部博文(56)

文章存档

2014年(1)

2011年(15)

2010年(5)

2008年(35)

分类: 数据库开发技术

2008-08-08 15:30:11

    包可将一些有联系的对象放在其内部。任何能再块定义部分出现的对象都可以在包中出现。这些对象包括存储过程、函数、游标、自定义的类型(例如 PL/SQL表和记录)和变量。我们可以在其他的PL/SQL块中引用包中的这些对象,也就是说,包为了PL/SQL提供了全局变量。
   
  1.包的定义
    一个包由两个独立的部分组成--包头和包体。各部分被单独地存放在数据字典中。定义一个包,要分别定义包头和包体。
   
    1.1 定义包头
    存储过程或函数必须在包头中预定义。也就是说,在包头中仅定义存在存储过程名或函数名以及它们的参数,存储过程或函数的执行代码将在包体中定义。这不同于无名块中定义存储过程和函数。如:
   
    CREATE OR REPLACE PACKAGE AuthsPack AS
      --获得auths表中作家的工资
      PROCEDURE QuerySalary(p_code auths.author_code%TYPE,
        p_Salary OUT auths.salary%TYPE);
       
      --向auths表插入记录
      PROCEDURE InsertAuthor(p_Code auths.author_code%TYPE,
        p_Name auths.name%TYPE,
        p_Sex auths.sex%TYPE,
        p_Birthdate auths.birthdate%TYPE,
        p_entry_date_time auths.entry_date_time%TYPE);
    END AuthsPack;
   

    1.2 定义包体
   
    包体是一个数据字典对象。只有在包头成功编译后,包体才能被编译。包体只包含包头中已于定义的子程序的代码。在包头中定义(不是预定义)的对象可以直接在包体中使用,不必再在包体中定义。
    下面是AuthsPack包的包体:
   
   
CREATE OR REPLACE PACKAGE BODY AuthsPack AS
      --获得auths表中作家的工资
      PROCEDURE QuerySalary(p_code auths.author_code%TYPE,
        p_Salary OUT auths.salary%TYPE)
      AS
      BEGIN
        SELECT salary INTO p_Salary
        FROM auths
        WHERE author_code = p_code;
      END QuerySalary;
    
       
      --向auths表插入记录
      PROCEDURE InsertAuthor(p_Code auths.author_code%TYPE,
        p_Name auths.name%TYPE,
        p_Sex auths.sex%TYPE,
        p_Birthdate auths.birthdate%TYPE,
        p_entry_date_time auths.entry_date_time%TYPE)
      AS
      BEGIN
        INSERT INTO auths
          (author_code, name, sex, birthdate, entry_date_time)
        VALUES
          (p_Code, p_Name, p_Sex, p_Birthdate, p_entry_date_time);
      END InsertAuthor;
       
    END AuthsPack;
   
    如果包头不包含存储过程和函数,则不必定义包体。如果包头中有预定义的子程序,则在包体中必须编写其子程序代码,而且包头和包体两部分指定的子程序必须一致,这包括相同的子程序名、参数名和参数类型。
   
    1.3包的初始化
    与变量类似,包也可以初始化。只是初始化部分在包体的最后部分被定义。如果在包体中定义了初始化部分,则每次调用包时,这个包都被初始化。如下是一个包被初始化的例子:   
   
   
CREATE OR REPLACE PACKAGE AuthorInfoPack AS
      v_auths_sex VARCHAR2(2);
      PROCEDURE Author_sex(p_Author_code auths.author_code%TYPE,
        p_Sex OUT VARCHAR2);
    END AuthorInfoPack;   
     

    定义AuthorInfoPack包的包体:
   
  
  CREATE OR REPLACE PACKAGE BODY AuthorInfoPack AS
      PROCEDURE Author_sex(p_Author_code auths.author_code%TYPE,
        p_Sex OUT VARCHAR2)
      AS
        v_Sex NUMBER;
      BEGIN
          --获取作家的性别代码
          SELECT sex INTO v_Sex
          FROM auths
          WHERE author_code = p_author_code;
          --将性别代码转换为性别
          IF v_Sex = 0 THEN
            p_Sex := '女';
          ELSE
            p_Sex := '男';
          END IF;
      END Author_sex;
    BEGIN
      Author_sex('A00001',v_auths_sex);
    END AuthorInfoPack;
   

  2.包的使用
   
    2.1包中对象的引用
   
    在包中定义的任意对象都可以在包外使用,只是在引用该度相前用包名作前缀。
    例如,我们可通过如下PL/SQL语句调用AuthsPack包中的存储过程QuerySalary:
   
   
--设置存储缓冲区的大小。
    SET SERVEROUTPUT ON SIZE 100000
    DECLARE
      v_Salary auths.salary%TYPE;
    BEGIN
      AuthsPack.QuerySalary('A00010', v_Salary);
     
      --显示过程QuerySalary的查询结果
      DBMS_OUTPUT.PUT_LINE('A00010作家的工资为:');
      DBMS_OUTPUT.PUT_LINE(v_Salary);
    END;
   

    这个存储过程的调用与单独调用存储过程是类似的。唯一不同的是此存储过程的调用有包名作前缀。于标准的存储过程一样,包中存储过程的参数也可以有缺省值,这些参数可通过位置表示法或命名表示法来调用。在包体内部不必带包名前缀即可直接引用包头中的对象。
   
    2.2重载包中的子程序
   
    在包的内部,存储过程和函数都可被重载,这以为着有多个存储过程或函数可以使用同一个名称,但是参数不能相同。这样就允许不同的参数调用同一个名字的过程或函数。
   
    例如,通过指定文章编码和作家代码来增加一篇文章,或通过指定作家性命和文章编码来增加一篇文章。下面定义一个包ArticlePack来实现这个功能:
  
   
CREATE OR REPLACE PACKAGE ArticlePack is
      PROCEDURE AddArticle(p_ArticleCode article.article_code%TYPE,
        p_AuthorCode aricle.author_code%TYPE,
        p_SecrateLevel articel.secrate_level%TYPE,
        p_PubDate article.pub_date%TYPE);
       
      PROCEDURE AddArticle(p_Birthdate auths.birthdate%TYPE,
        p_AuthorCode aricle.author_code%TYPE,
        p_SecrateLevel articel.secrate_level%TYPE,
        p_PubDate article.pub_date%TYPE);
    END ArticlePack;
   
    重载是非常游泳的技术,但是,它也有一些约束,这些约束如下所示:
    a)当仅仅参数名不同或者是模式(IN、OUT、IN OUT)不同时,不能重载子程序。例如,下面的两个存储过程不能被重载:
   
   
PROCEDURE Overload(p_Par IN CHAR);
    PROCEDURE Overload(p_Par OUT CHAR);

   
    b)不能对仅有返回类型的函数进行重载。例如,下面的函数不能被重载;
   
   
FUNCTION Overload FUN RETURN CHAR;
    FUNCTION Overload FUN RETURN BINARY_INTGER;
   
    c)重载函数的参数必须是数据类型不同或其类型间不可自动转换。例如,由于CHAR和VARCHAR2的变量类型可以自动转换,因此不能重载下面的存储过程:
   
   
PROCEDURE OverloadChar(p_TheParameter IN CHAR);
    PROCEDURE OverloadChar(p_TheParameter IN VARCHAR2);
   
  3.在SQL语句中使用的函数
 
    通常在SQL语句中不能调用PL/SQL函数(无论是单独存储在数据库中的函数还是保重的函数),因为PL/SQL函数是过程性的语句。在PL/SQL 2.1以上版本中放宽了这个限制,但函数必须满足特定的约束才能在SQL语句中使用。
   
    PL/SQL为函数指定了4种基本约束,如下:
   
    基本约束                 含义                        描述
    ====================================================================
    WNDS      Writes no database state    在函数内不能用DML语句修改数
                                          据库中的表。
    --------------------------------------------------------------------
    RNDS      Reads no database state     在函数内不能通过SELECT语句
                                          来读取数据库中的表。
    --------------------------------------------------------------------
    WNPS      Writes no package state     在函数内不能修改包变量(包变量不
                                          能在赋值语句的左边或一个FETCH语
                                          句的INTO语句中)
    --------------------------------------------------------------------
    RNPS      Reads no package state      在函数内不能查询包变量(包变量
                                          能在赋值语句的右边,或不能是SQL
                                          表达式的一部分)
    --------------------------------------------------------------------                                                                                               
阅读(1479) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~