包可将一些有联系的对象放在其内部。任何能再块定义部分出现的对象都可以在包中出现。这些对象包括存储过程、函数、游标、自定义的类型(例如 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) |