3.6.3 程序包
程序包是一种Oracle数据库对象,它是一组逻辑上相关的数据类型、变量、过程、函数和游标等的集合。程序包被创建后,存储在数据库中,用户可以直接使用包中的数据类型和变量,也可以直接调用包中的过程和函数。
程序包有两种形式,一种是用户根据需要创建的程序包,一种是系统预定义的程序包。这里介绍自定义程序包的创建、使用、删除等操作,以及预定义程序包的使用方法。
用户可以根据需要创建自己的程序包。在程序包中可以定义数据类型、变量、过程、函数、异常和游标等元素,这些元素具有全局的特性,可以在程序包中使用,也可以在程序包之外使用。
一个程序包由两部分组成:程序包的头部和包体。其中头部用来定义类型、变量、异常、声明游标、过程和函数,它的作用相当于程序包的接口。在包体中可以利用头部的类型定义变量,定义过程、游标和函数的代码。
在创建程序包时,头部和包体是分别创建的,并且头部必须在包体之前创建。程序包创建之后,如果要对其功能进行修改,这时只需修改包体的代码即可,不用修改头部,仅当需要改变参数类型、参数个数等信息时,才需要修改程序包的头部。
创建程序包头部的命令是CREATE PACKAGE,这条命令的语法格式为:
CREATE[OR REPLACE]PACKAGE包名
AUTHID CURRENT_USER|DEFINER
AS
类型的定义;
变量的定义;
子程序的声明;
游标的声明;
异常的声明;
END;
其中OR REPLACE选项的作用是当指定的包已经存在时重新创建它。AUTHID选项用来规定程序包以哪个用户的身份执行。这个选项有两个可选值,即CURRENT_USER和DEFINER,二者只能选择其中一个。
子程序的声明就是定义过程和函数的原型,即子程序的名称、参数和返回值,不包含它的代码部分。类型定义部分允许用户根据需要创建自己的数据类型。
例如,要对部门员工的总收入和所得税进行统计,为此需要编写一个程序包。在程序包中首先定义了一个记录类型total,然后声明了一个函数tax_per_depart,用来统计某个部门的所得税,过程total_per_depart用来统计各个部门的员工总收入。最后还定义了一个游标c1。需要注意的是,在程序包的头部定义游标时需要指定它的返回类型。以下是创建程序包employee头部的代码:
CREATE OR REPLACE PACKAGE employee
AS
type total is record(
dno emp.deptno%type,
total_income number
);
function tax_per_depart(dno integer)RETURN number;
procedure total_per_depart;
cursor c1 RETURN total;
END;
程序包的包体是对头部的实现,主要用来定义过程和函数的可执行代码。创建包体的命令是CREATE PACKAGE BODY,这条命令的语法格式为:
CREATE[OR REPLACE]PACKAGE BODY包名AS
游标的实现;
子程序的实现;
END;
其中包名与创建头部时使用的名字完全相同。游标的实现是指定游标中所使用的SELECT语句。子程序的实现是写出过程和函数的代码,过程和函数的编写方法与以前介绍的方法完全相同。以下是创建程序包employee的包体的代码。
CREATE OR REPLACE PACKAGE BODY employee
AS
CURSOR c1 RETURN total is—定义游标
SELECT deptno, sum(sal)FROM emp GROUP BY deptno;
function tax_per_depart(dno integer)—定义函数tax_per_depart
RETURN number
as
result number;
BEGIN
SELECT sum(sal)*0.03 INTO result FROM emp
WHERE deptno=dno
GROUP BY deptno;
RETURN result;
END;—函数tax_per_depart结束
procedure total_per_depart—定义过程total_per_depart
as
depart total;
BEGIN
open c1;
fetch c1 INTO depart;—利用取出游标中的数据
while c1%found loop
dbms_output.put_line('部门'||depart.dno||'总收入:'||depart.total_income);
fetch c1 INTO depart;
END loop;
close c1;
END;—过程total_per_depart结束
END;—包体结束
定义了程序包employee后,用户就可以在PL/SQL块或者SQL*Plus中使用这个包中的类型、游标、变量、过程和函数了,使用的方法为:
包名.元素名
例如,要利用程序包employee中的过程total_per_depart统计各个部门员工的总收入,可以在SQL*Plus中调用这个过程:
SQL>EXEC employee.total_per_depart
部门10 总收入:8750
部门20 总收入:6775
部门30 总收入:9400
再比如,在一个匿名块中调用程序包employee中的函数tax_per_depart,计算部门20的所得税,这个匿名块的代码为:
DECLARE
dno integer;
total_tax number;
t1 employee.total—利用程序包employee中的类型total定义一个变量,
BEGIN
t1.dno:=10;
t1.total_income:=1000;
dno:=20;
total_tax:=employee.tax_per_depart(dno);
dbms_output.put_line('Total tax of department'||dno||'is:'||total_tax);
END;
如果一个程序包不再需要,我们可以将其从数据库中删除。删除程序包时,可以选择只删除包体,或者删除整个包。删除整个程序包的命令是DROP PACKAGE,它的格式为:
DROP PACKAGE包的名字;
这样,程序包的头部和包体都将从数据库中被删除。
如果只删除包体,相应的命令为DROP PACKAGE BODY,它的格式为:
DROP PACKAGE BODY包的名字;