PL/Sql Package

Allow the Oralcel server to read multiple objects into memory at once.

Package bundle related PL/SQL types, items, and subprograms into one container.

包含2部分 : specification , body ( stored separately in the database )

The specification is the interface to your applications. ( 声明 )

body : 真实定义

The package itself cannot be called . package once written and compiled, the contents can be shared by many applications.

When you call a packaged PL/SQL construct for the first time, the whole package is loaded into memory. ( thus, later calls to constructs in the same package require no disk input/output I/O )

Public package : are those that are declared in the package specification and defined in the package body.

Private package : are those that are defined solely within the package body.

image

变量可见度

image

G_VARIABLE_NAME ( g 前缀开头的是 Global )

A package specification can exist without a package body, but a package body cannot exist without a package specification.

声明: ( specification )

CREATE [ OR REPLACE ] PACKAGE package_name

IS | AS

  public type and item declarations

  subprogram specifications

END package_name;

例子 :

image

包体 ( body )

CREATE [ OR REPLACE ] PACKAGE BODY package_name

IS | AS

  private type and item declarations

  subprogram bodies

END package_name ;

It is quite common in the package body to see all private variables and subprograms defined first and the public subprograms defined last ( 先定义似有的, 再定义公共变量 )

例子 :

image

调用 :

EXECUTE comm_package.reset_comm( 0.15 )

EXECUTE scott.comm_package.reset_comm( 0.15 )   // different schema

EXECUTE comm_package.reset_comm@ny( 0.15 )     // remote database

可以只有 specification , 没有 body.

删除 :

DROP PACKAGE package_name ;

DROP PACKAGE BODY package_name;

包里的东西可以重载,比如 you can careate multiple subprograms with the same name in the same package, each taking parameters of different number or datatype.

重载例子 :

image

image

例如: 系统中的 TO_CHAR, 之类的,就是重载,可以接受不同参数。

You must declare an identifier before using it. Therefore, a subprogram must be declared before calling it.

( 必须先声明,或者在 specification 中声明,或者在 body中声明,总之,真实定义之前必须要声明 )

比如当系统在一个 procedure 中调用另一个 procedure , 但是,该 procedure 没有被声明或定义,那么它就不知道如何调用 ( 定义或声明要在这个 procedure 之前 )

image

calc_rating(), 被调用了,但是 它的定义在下边,所以就会出错。

最好还是声明,因为如果两个 procedure 互相调用时,哪个放在前边也是不行的。

image

包中,函数 Functions 的限制 : ( 跟之前单体函数的限制差不多 )

  • A function called from a query or DML statement may not end the current transaction , create or roll back to a savepoint, or alter the system or session
  • A function called from a query statement or from a parallelized DML statement may not execute a DML statement or otherwise modify the database
  • A function called from a DML statement may not read or modify the particular table being modified by that DML statement.

调用自己定义包中的函数

SELECT taxes_pack.tax( salary ) , salary, last_name FROM employees; // taxes_pack 包名

 

Oracle Supply package. ( 貌似只有少部分有用 )

Most of the standard packages are created by running catproc.sql

- 动态 ( 带参数的 SQL ) ( 顺序 : parse –> bind –> execute –> fetch )

   DBMS_SQL package 提供了 dynamic SQL .

   image

   例如 :

   image

   image

- DBMS_DDL package

- DBMS_JOB Subprograms

- DBMS_OUTPUT

   PUT, NEW_LINE, PUT_LINE, GET_LINE, GET_LINES, ENABLE/DISABLE

   image

 


1. 为什么使用包

答:在一个大型项目中,可能有很多模块,而每个模块又有自己的过程、函数等。而这些过程、函数默认是放在一起的(如在PL/SQL中,过程默认都是放在一起的,即Procedures中),这些非常不方便查询和维护,甚至会发生误删除的事件。所以通过使用包就可以分类管理过程和函数。

有点类似 object – c

包分两部分,包规范包体

2. 定义包说明
--定义包规范
create or replace package p_stu
as
    --定义结构体
    type re_stu is record(
        rname student.name%type,
        rage  student.age%type
    );
    --定义游标
    type c_stu is ref cursor;
    --定义函数
    function numAdd(num1 number,num2 number)return number;
    --定义过程
    procedure GetStuList(cid in varchar2,c_st out c_stu); 
end;
3. 定义包体
--实现包体,名称一致。
create or replace package body p_stu
as
    --游标和结构体,包规范中已声明,包体中不用再声明,直接使用。
    
    --实现方法   
    function numAdd(num1 number,num2 number)return number
    as
        num number;
    begin
        num:=num1+num2;
        return num;
    end;
    
    --实现过程
    procedure GetStuList(cid varchar2,c_st out c_stu)
    as
        r_stu re_stu; --直接使用包规范中的结构
    begin
        open c_st for select name,age from student where classid=cid;
       -- 如果已经在过程中遍历了游标,在使用这个过程的块中,将没有值。
       -- loop
       --     fetch c_st into r_stu;  
       --     exit when c_st%notfound;
       --     dbms_output.put_line('姓名='||r_stu.rname);
       -- end loop;
    end;
end;
4. 使用包
declare
    c_stu p_stu.c_stu;   --定义包中游标变量
    r_stu p_stu.re_stu;  --定义包中结构体变量
    num number;
begin
    --使用及遍历包中过程返回的结果集
    p_stu.GetStuList('C001',c_stu);
    loop
        fetch c_stu into r_stu;
        exit when c_stu%notfound;
        dbms_output.put_line('姓名='||r_stu.rname);
    end loop;
    
    --使用包中的方法
    select p_stu.numAdd(5,6) into num from dual;
    dbms_output.put_line('Num='||num);
end;

 


一、程序包的相关知识

1.定义与说明 
a. 相关对象的封装 
b. 程序包的各部分 
- 程序包规格说明 
声明子程序 
- 程序包主体 
定义子程序 
2.使用程序包的优点 
- 模块化 
- 更轻松的应用程序设计 
- 信息隐藏 
- 新增功能 
- 性能更佳 
3.公有项和私有项的区别 
公有项:在程序包说明部分定义的变量、过程、函数 
私有项:在程序包主体部分定义的变量、过程、函数 
公有项 私有项 
可以在程序包之外引用 不能在程序包之外引用 
是在程序包规格说明中定义的 是在程序包主体中定义的 
用于全局目的 用于局部目的

二、程序包创建说明

 

1.程序包规格说明 
(1)、使用Create Package命令进行创建 
(2)、包含公用对象和类型 
(3)、声明类型、常量、变量、异常、游标和子程序 
(4)、可以在没有程序包主题的情况下存在 
(5)、可以重载 
- 程序包中的多个子程序可以具有相同的名称 
- 它们的形参是不同的 
- 只能位于打包的子程序中 
- 限制 
a. 如果子程序的参数仅名称或模式不同,则不能重载 
b. 不能基于其返回类型重载子程序 
2.程序包主体 
(1)、使用Create Package body 命令进行创建 
(2)、包含子程序和游标的定义 
(3)、包含私有声明 
(4)、不能在没有程序包规格说明的情况下独立存在 
3.程序包的调用 
包名.类型名; 
包名.函数名[参数表]; 
包名..过程名[参数表]; 
(1)、 Package-name.type-name 
(2)、 Package-name.object-name 
(3)、 Package-name.subprogram-name 
其中,Package-name 是程序包名称,type-name是类型名称, 
object-name是对象名称,subprogram-name 是子程序名称 
--示例 
DBMS_output.put_line(Hello); 
(4)、对于返回参数是游标类型的调用(如:引用游标) 
set autoprint on --打开Sqlplus输出 
variable tempCur RefCursor; --定义一个宿主类型的引用游标变量 
exec StudentPackage.ReturnStudent(:tempCur); --执行带有引用游标的过程 注意使用宿主类型的变量前面要加“:”符号 
4. 有关子程序和程序包的信息 
A.数据字典 
User_objects 用于检查对象是否存在 
User_source 用于获取对象的代码 
B. 包的修改和删除 
Alter Package [Body] 包名 
Alter Package Body StudentPackage; 
Drop Package [Body] 包名 
Drop Package Body StudentPackage; 
5. 创建格式 
A.创建包规格部分 
格式:Create [or replace] Package 包名 
IS|AS 
变量声明; 
类型定义; 
异常声明; 
游标声明; 
函数说明; 
过程说明; 
Pragma restrict_references(过程名或函数名,WNDS[,WNPS][,RNDS][,RNPS]) --编译指令 限定函数的操作 
End [包名]; 
B.创建包主体部分 
格式: Create [or replace] package body 包主体名 --包主体名一定要是已经定义的包名 
IS|AS 
变量声明; --具体的实现部分 
类型定义; 
异常声明; 
游标声明; 
函数说明; 
过程定义; 
End [包主体名];

6. 示例 
示例1.创建程序包的规格说明部分  

复制代码
 1 Create or replace Package StudentPackage 
 2 is 
 3 Type curRefStudent is Ref Cursor Return Student%rowtype; 
 4 Procedure SelectStudent(FindID in Student.stuid%type); 
 5 Procedure InsertStudent(NewStudent in Student%rowType); 
 6 Procedure UpdateStudent(NewStudent in Student%rowType); 
 7 Procedure DeleteStudent(DelID in Student.stuid%type); 
 8 Procedure ReturnStudent(inOutstu in out curRefStudent); 
 9 Function RegurnRecordCount Return Number; 
10 End studentPackage; 
复制代码


示例2.创建程序包的主体部分  

复制代码
 1 Create or replace Package Body StudentPackage IS 
 2 Procedure SelectStudent (FindID in Student.stuid%type) as --注意没有Create 
 3 /*实现查询过程的定义*/ 
 4 Cursor findCur is select * from student where stuid=FindID; 
 5 Begin 
 6 For S in FindCur Loop 
 7 DBMS_output.put_line(S.stuID||' '||s.StuName||' '||S.Sex); 
 8 End Loop; 
 9 Exception 
10 When No_Data_Found Then 
11 DBMS_output.Put_Line('没有查到ID为'||FindID||'的记录!'); 
12 When Others Then 
13 DBMS_output.Put_Line('查询过程中发生意外情况'); 
14 End SelectStudent; --结束查询过程 
15 /*实现插入过程的定义*/ 
16 Procedure InsertStudent(NewStudent in Student%rowType) as 
17 iRec Integer; 
18 Not_Exists_Student Exception; --预定义异常 
19 Begin 
20 Select count(*) into iRec from student where stuid=NewStudent.stuID; 
21 IF iRec>0 Then 
22 Raise Not_Exists_Student; 
23 Else 
24 insert into student values(NewStudent.stuid,NewStudent.stuName,NewStudent.sex); 
25 commit; 
26 End IF; 
27 Exception 
28 When Not_Exists_Student Then 
29 DBMS_output.Put_Line('要插入的编号:'||NewStudent.stuid||'的记录已经存在'); 
30 When Others Then 
31 DBMS_output.Put_Line('插入记录操作过程中出现错误'); 
32 End InsertStudent;--结束插入过程 
33 /*实现更新过程的定义*/ 
34 Procedure UpdateStudent(NewStudent in Student%rowType) as 
35 iRec Integer; 
36 Begin 
37 select Count(*) into iRec From student Where stuid=NewStudent.stuid; 
38 IF iRec =0 Then 
39 DBMS_output.Put_Line('编号为:'||NewStudent.stuid||'的记录不存在,修改失败'); 
40 ELSE 
41 Update student Set Stuname=NewStudent.stuName,Sex=NewStudent.Sex 
42 WHERE stuid=NewStudent.stuID; 
43 Commit; 
44 End IF; 
45 Exception 
46 When No_Data_Found Then 
47 DBMS_output.Put_Line('编号为:'||NewStudent.stuID||'的记录不存在,修改失败'); 
48 When Others Then 
49 DBMS_output.Put_Line('执行修改操作时发生意外情况,修改未成功'); 
50 End UpdateStudent;--结束修改过程 
51 /*实现删除过程的定义*/ 
52 Procedure DeleteStudent(DelID in Student.stuid%type) as 
53 iRec Integer; 
54 Begin 
55 Select Count(*) into iRec From Student Where stuID=DelID; 
56 IF iRec=0 Then 
57 DBMS_output.Put_Line('编号为:'||DelID||'的记录不存在,删除操作时未成功'); 
58 ELSE 
59 Delete From student Where stuid=DelID; 
60 Commit; 
61 DBMS_output.Put_Line('删除成功!'); 
62 End IF; 
63 Exception 
64 When Others Then 
65 DBMS_output.Put_Line('执行删除操作时发生意外情况,删除未成功'); 
66 End DeleteStudent; 
67 /*实现参数带有游标类型定义*/ 
68 Procedure ReturnStudent(inOutstu in out curRefStudent) as 
69 Begin 
70 Open inOutstu For Select * from student; 
71 End ReturnStudent; 
72 /*实现函数定义*/ 
73 Function RegurnRecordCount Return Number as 
74 RecCount number(10); 
75 Begin 
76 Select Count(*) into RecCount From student; 
77 Return recCount; 
78 Exception 
79 When Others Then 
80 DBMS_output.Put_Line('查询表中记录数时发生意外情况'); 
81 End RegurnRecordCount; --结束函数的定义 
82 End studentPackage;--结束包 
复制代码


示例3:调用包 
1. 调用studentPackage包中的InsertStudent过程  

复制代码
1 Declare 
2 newStu Student%RowType; 
3 Begin 
4 newStu.stuID:='1001'; 
5 newStu.stuName:='张三'; 
6 newStu.sex:=''; 
7 studentPackage.InsertStudent(newStu); 
8 End; 
9 / 
复制代码


2. 调用studentPackage包中的UpdateStudent过程  

复制代码
 1 Declare 
 2 newStu Student%RowType; 
 3 Begin 
 4 newStu.stuID:='1001'; 
 5 newStu.stuName:='李四'; 
 6 newStu.sex:=''; 
 7 studentPackage.UpdateStudent(newStu); 
 8 Exception 
 9 When Dup_Val_On_Index Then 
10 DBMS_output.Put_Line('唯一约束被破坏'); 
11 When Others Then 
12 DBMS_output.Put_Line('更新过程出现错误'); 
13 End; 
14 / 
复制代码


3. 调用studentPackage包中的DeleteStudent过程  

1 Begin 
2 studentPackage.DeleteStudent('1001'); 
3 End; 
4 / 


4. 调用studentPackage包中的ReturnRecordCount函数  

1 Begin 
2 DBMS_output.put_Line(studentPackage.ReturnRecordCount); 
3 End; 
4 / 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值