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. 定义包说明
PL/SQL Package
说明
3. 定义包体
PL/SQL Package
包体
4. 使用包
PL/SQL Package
使用

 


一、程序包的相关知识

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.创建程序包的规格说明部分  

PL/SQL Package --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.创建程序包的主体部分  

PL/SQL Package --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过程  

PL/SQL Package --invoke1
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过程  

PL/SQL Package --invoke2
 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过程  

PL/SQL Package --invoke3
1 Begin 

2 studentPackage.DeleteStudent('1001'); 

3 End; 

4 / 


4. 调用studentPackage包中的ReturnRecordCount函数  

PL/SQL Package --invoke4
1 Begin 

2 DBMS_output.put_Line(studentPackage.ReturnRecordCount); 

3 End; 

4 / 

你可能感兴趣的:(package)