Oracle PL/SQL Package:类型、规范、主体 [示例]
Oracle 中的 Package 是什么?
PL/SQL package 是将相关的子程序(过程/函数)逻辑分组到单个元素中。Package 被编译并存储为数据库对象,以后可以使用。
Package 的组成部分
PL/SQL package 有两个组成部分。
- Package 规范
- Package 主程序
Package 规范
Package 规范包含所有公共 变量、游标、对象、过程、函数和异常的声明。
以下是 Package 规范的几个特点。
- 在规范中声明的所有元素都可以从 Package 外部访问。这些元素称为公共元素。
- Package 规范是一个独立的对象,这意味着它可以独立存在而无需 Package 主程序。
- 每当引用一个 Package 时,都会为该特定会话创建一个 Package 的实例。
- 在会话创建实例后,该实例中初始化的所有 Package 元素在会话结束前都有效。
语法
CREATE [OR REPLACE] PACKAGE <package_name> IS <sub_program and public element declaration> . . END <package name>
上述语法显示了 Package 规范的创建。
Package 主程序
它包含 Package 规范中存在的所有元素的定义。它还可以包含规范中未声明的元素的定义,这些元素称为私有元素,只能从 Package 内部调用。
以下是 Package 主程序的特点。
- 它应包含规范中声明的所有子程序/游标的定义。
- 它还可以包含未在规范中声明的更多子程序或其他元素。这些称为私有元素。
- 它是一个依赖对象,依赖于 Package 规范。
- 每当规范被编译时,Package 主程序的状态会变为“无效”。因此,每次编译规范后都需要重新编译它。
- 私有元素在使用前必须在 Package 主程序中定义。
- Package 的第一部分是全局声明部分。这包括对整个 Package 可见的变量、游标和私有元素(前向声明)。
- Package 的最后一部分是 Package 初始化部分,它在会话首次引用 Package 时执行一次。
语法
CREATE [OR REPLACE] PACKAGE BODY <package_name> IS <global_declaration part> <Private element definition> <sub_program and public element definition> . <Package Initialization> END <package_name>
- 上述语法显示了 Package 主程序的创建。
现在我们将学习如何在程序中引用 Package 元素。
引用 Package 元素
一旦元素在 Package 中声明和定义,我们就需要引用这些元素才能使用它们。
Package 的所有公共元素都可以通过调用 Package 名称后跟元素名称,并用句点分隔来引用,即“
Package 的公共变量也可以用相同的方式使用,用于分配和获取值,即“
在 PL/SQL 中创建 Package
在 PL/SQL 中,每当在会话中引用/调用 Package 时,都会为该 Package 创建一个新的实例。
Oracle 提供了一种设施,可以在创建实例时初始化 Package 元素或执行任何活动,通过“Package 初始化”。
这不过是一个执行块,写在 Package 主程序中,定义完所有 Package 元素之后。每当在会话中首次引用 Package 时,都会执行此块。
语法
CREATE [OR REPLACE] PACKAGE BODY <package_name> IS <Private element definition> <sub_program and public element definition> . BEGINE <Package Initialization> END <package_name>
- 上述语法显示了 Package 主程序中 Package初始化的定义。
前向声明
Package 中的前向声明/引用不过是单独声明私有元素,并在 Package 主程序的后续部分中定义它。
私有元素只有在 Package 主程序中已声明的情况下才能引用。为此,使用了前向声明。但它不太常用,因为在大多数情况下,私有元素在 Package 主程序的第一部分声明和定义。
前向声明是 Oracle 提供的一种选项,它不是强制性的,是否使用取决于程序员的要求。
语法
CREATE [OR REPLACE] PACKAGE BODY <package_name> IS <Private element declaration> . . . <Public element definition that refer the above private element> . . <Private element definition> . BEGIN <package_initialization code>; END <package_name>
上述语法显示了前向声明。私有元素在 Package 的前向部分单独声明,并在后续部分定义。
Package 中游标的使用
与其他元素不同,在使用 Package 中的游标时需要小心。
如果游标在 Package 规范或 Package 主程序的全局部分定义,那么一旦打开,游标将一直存在直到会话结束。
因此,在引用游标之前,应始终使用游标属性 '%ISOPEN' 来验证游标的状态。
重载
重载是拥有多个同名子程序的概念。这些子程序将通过参数的数量、参数的类型或返回类型来区分彼此,即同名但参数数量不同、参数类型不同或返回类型不同的子程序被视为重载。
当许多子程序需要执行相同任务,但调用它们的方式应该不同时,这很有用。在这种情况下,所有子程序的名称将保持相同,并且参数将根据调用语句进行更改。
示例 1:在此示例中,我们将创建一个 Package 来获取和设置 'emp' 表中员工信息的值。get_record 函数将为给定的员工编号返回记录类型输出,set_record 过程将记录类型记录插入到 emp 表中。
步骤 1) 创建 Package 规范
CREATE OR REPLACE PACKAGE guru99_get_set IS PROCEDURE set_record (p_emp_rec IN emp%ROWTYPE); FUNCTION get record (p_emp no IN NUMBER) RETURN emp%ROWTYPE; END guru99_get_set: /
输出
Package created
代码解释
- 代码第 1-5 行:为 guru99_get_set 创建 Package 规范,包含一个过程和一个函数。这两个现在是此 Package 的公共元素。
步骤 2) Package 包含 Package 主程序,其中将定义所有过程和函数的实际定义。在此步骤中,创建了 Package 主程序。
CREATE OR REPLACE PACKAGE BODY guru99_get_set IS PROCEDURE set_record(p_emp_rec IN emp%ROWTYPE) IS PRAGMA AUTONOMOUS_TRANSACTION; BEGIN INSERT INTO emp VALUES(p_emp_rec.emp_name,p_emp_rec.emp_no; p_emp_rec.salary,p_emp_rec.manager); COMMIT; END set_record; FUNCTION get_record(p_emp_no IN NUMBER) RETURN emp%ROWTYPE IS l_emp_rec emp%ROWTYPE; BEGIN SELECT * INTO l_emp_rec FROM emp where emp_no=p_emp_no RETURN l_emp_rec; END get_record; BEGUN dbms_output.put_line(‘Control is now executing the package initialization part'); END guru99_get_set: /
输出
Package body created
代码解释
- 代码第 7 行:创建 Package 主程序。
- 代码第 9-16 行:定义规范中声明的元素 'set_record'。这与在 PL/SQL 中定义独立过程相同。
- 代码第 17-24 行:定义元素 'get_record'。这与定义独立函数相同。
- 代码第 25-26 行:定义 Package 初始化部分。
步骤 3) 创建一个匿名块,通过引用上面创建的 Package 来插入和显示记录。
DECLARE l_emp_rec emp%ROWTYPE; l_get_rec emp%ROWTYPE; BEGIN dbms output.put line(‘Insert new record for employee 1004'); l_emp_rec.emp_no:=l004; l_emp_rec.emp_name:='CCC'; l_emp_rec.salary~20000; l_emp_rec.manager:=’BBB’; guru99_get_set.set_record(1_emp_rec); dbms_output.put_line(‘Record inserted'); dbms output.put line(‘Calling get function to display the inserted record'): l_get_rec:=guru99_get_set.get_record(1004); dbms_output.put_line(‘Employee name: ‘||l_get_rec.emp_name); dbms_output.put_line(‘Employee number:‘||l_get_rec.emp_no); dbms_output.put_line(‘Employee salary:‘||l_get_rec.salary'); dbms output.put line(‘Employee manager:‘||1_get_rec.manager); END: /
输出
Insert new record for employee 1004 Control is now executing the package initialization part Record inserted Calling get function to display the inserted record Employee name: CCC Employee number: 1004 Employee salary: 20000 Employee manager: BBB
代码解释
- 代码第 34-37 行:在匿名块中填充记录类型变量的数据,以调用 Package 的 'set_record' 元素。
- 代码第 38 行:调用 guru99_get_set Package 的 'set_record'。现在 Package 已实例化,并将一直存在直到会话结束。
- 由于这是第一次调用 Package,Package 初始化部分将被执行。
- 记录由 'set_record' 元素插入到表中。
- 代码第 41 行:调用 'get_record' 元素以显示已插入员工的详细信息。
- 在 'get_record' 调用 Package 时,Package 被第二次引用。但这次初始化部分不会执行,因为 Package 已在该会话中初始化。
- 代码第 42-45 行:打印员工详细信息。
Package 中的依赖关系
由于 Package 是相关事物的逻辑分组,因此它存在一些依赖关系。以下是需要注意的依赖关系。
- 规范是独立的对象。
- Package 主程序依赖于规范。
- Package 主程序可以单独编译。每当规范被编译时,主程序都需要重新编译,因为它会变得无效。
- Package 主程序中依赖于私有元素的子程序只能在私有元素声明之后定义。
- 在 Package 编译时,规范和主程序中引用的数据库对象必须处于有效状态。
Package 信息
一旦创建了 Package 信息,Package 信息,如 Package 源代码、子程序详细信息和重载详细信息,就可在 Oracle 数据定义表中获得。
下表给出了数据定义表和表中可用的 Package 信息。
表名 | 描述 | 查询 |
---|---|---|
ALL_OBJECT | 提供 Package 的详细信息,如 object_id、creation_date、last_ddl_time 等。它将包含所有用户创建的对象。 | SELECT * FROM all_objects where object_name ='<package_name>’ |
USER_OBJECT | 提供 Package 的详细信息,如 object_id、creation_date、last_ddl_time 等。它将包含当前用户创建的对象。 | SELECT * FROM user_objects where object_name ='<package_name>’ |
ALL_SOURCE | 提供所有用户创建的对象的源代码。 | SELECT * FROM all_source where name='<package_name>’ |
USER_SOURCE | 提供当前用户创建的对象的源代码。 | SELECT * FROM user_source where name='<package_name>’ |
ALL_PROCEDURES | 提供所有用户创建的子程序详细信息,如 object_id、重载详细信息等。 | SELECT * FROM all_procedures Where object_name='<package_name>’ |
USER_PROCEDURES | 提供当前用户创建的子程序详细信息,如 object_id、重载详细信息等。 | SELECT * FROM user_procedures Where object_name='<package_name>’ |
UTL FILE – 概述
UTL File 是 Oracle 提供的用于执行特殊任务的独立实用程序包。它主要用于从 PL/SQL 包或子程序读取和写入操作系统文件。它具有将信息放入文件和从文件获取信息的专用函数。它还允许以本地字符集进行读/写。
程序员可以使用它来写入任何类型的操作系统文件,文件将直接写入数据库服务器。在写入时将指定名称和目录路径。
摘要
我们已经学习了 PL/SQL 中的 Package,现在您应该能够进行以下操作。
- PL/SQL Package 及其组成部分
- Package 的特点
- 引用和重载 Package 元素
- 管理 Package 中的依赖关系
- 查看 Package 信息
- UTL File 是什么