一、引言
PLSQL中的包类似于C++中的类,在包中我们可以定义变量、游标、存储过程、存储函数等等。它实现了将上述类型统一创建和管理,同时在不同包之间这个PLSQL的对象不会存在命名冲突问题。包的定义包含两部分,包头和包体,有点类似于C++中的类的头文件和cpp文件。在包头中我们对变量、存储过程等等进行声明,而在包体中是对他们的实现。下面,我们在emp表的基础之上介绍包的用法。如下,假设有以下的emp表:
二、包的定义
我们将创建一个名叫emp_page的包,包中包含一个存储过程insert_emp用来向emp表中插入数据,一个存储函数get_emp_func,根据部门号返回该部门所有雇员的信息。
2.1 包头定义
create or replace package emp_pack
as
function get_emp_func(p_dno dept.deptno%type) return sys_refcursor;
procedure insert_emp(v_empno emp.empno%type,v_ename emp.ename%type,v_job emp.job%type,v_mgr emp.mgr%type,v_sal emp.sal%type,v_deptno emp.deptno%type);
end;
/
可以看到我们在包头中分别声明了存储过程insert_emp和存储函数get_emp_func,包头中只负责声明,我们需要在包体中进行实现。需要特别注意的是编写完包头和包体之后,我们要先编译包头再去编译包体,才能正确完成一个包的创建。
2.2 包体定义
create or replace package body emp_pack
as
function get_emp_func(p_dno dept.deptno%type) return sys_refcursor
as
v_cur sys_refcursor;
begin
open v_cur for select * from emp where deptno=p_dno;
return v_cur;
end;
procedure insert_emp(v_empno emp.empno%type,v_ename emp.ename%type,v_job emp.job%type,v_mgr emp.mgr%type,v_sal emp.sal%type,v_deptno emp.deptno%type)
as
v_count number;
begin
select count(*) into v_count from emp where empno=v_empno;
if v_count>0 then
raise_application_error(-20789,'增加失败,该部门已经存在');
else
insert into emp values(v_empno,v_ename,v_job,v_mgr,sysdate,v_sal,null,v_deptno);
end if;
commit;
exception
when others then
dbms_output.put_line('sqlerrm='||sqlerrm);
rollback;
end;
end;
/
包体的创建语法中,与包头唯一不同之处在于在package后面加了一个body关键字,接下来就是对包头中定义的内容的实现。get_emp_func接收一个部门号的参数,在函数内部定义了一个系统参考游标,用来接收该部门对应的雇员,并最终返回这个游标;insert_emp中接收一个雇员的信息,将他插入emp表中。完成上述代码之后,分别对包头和包体进行编译,一个包就被定义好了,我们可以用sql developer看到我们创建的包:
三、包的使用
创建完包之后,我们可以在PLSQL的程序块中使用包里的函数或者过程,如下的例子我们使用一个系统的参考游标接收了包中
get_emp_func返回的游标,并打印出游标管理的结果集:
declare
v_cur sys_refcursor;
v_emp emp%rowtype;
begin
v_cur:=emp_pack.get_emp_func(20);
fetch v_cur into v_emp;
while v_cur%found loop
dbms_output.put_line('姓名:'||v_emp.ename||',薪资:'||v_emp.sal);
fetch v_cur into v_emp;
end loop;
close v_cur;
end;
/
结果如下:
四、使用包中的变量
包中出了可以定义存储过程和存储函数之外,我们也可以定义一个变量供外部使用,如,我们在包头增加一个v_empno的变量:
create or replace package emp_pack
as
v_empno emp.empno%type :=10;
function get_emp_func(p_dno dept.deptno%type) return sys_refcursor;
procedure insert_emp(v_empno emp.empno%type,v_ename emp.ename%type,v_job emp.job%type,v_mgr emp.mgr%type,v_sal emp.sal%type,v_deptno emp.deptno%type);
end;
/
增加完之后要重新编译包头和包体,然后直接可以在PLSQL代码块中使用该变量:
begin
dbms_output.put_line(emp_pack.v_empno);
end;
/
结果如下: