Oracle PL/SQL 包:类型、规范、主体 [示例]
包中的内容 Oracle?
PL/SQL 包是将相关子程序(过程/函数)逻辑分组为单个元素。包被编译并存储为数据库对象,以后可以使用。
软件包的组件
PL/SQL 包有两个组件。
- 包装规格
- 封装主体
包装规格
包规范包括所有公共的 变量、游标、对象、过程、函数和异常。
以下是包规范的一些特征。
- 所有在规范中声明的元素都可以从包外部访问。这样的元素称为公共元素。
- 包规范是一个独立元素,这意味着它可以独立存在而不需要包主体。
- 每当一个包引用了该特定会话时,就会创建该包的一个实例。
- 为会话创建实例后,在该实例中启动的所有包元素在会话结束前都有效。
句法
CREATE [OR REPLACE] PACKAGE <package_name> IS <sub_program and public element declaration> . . END <package name>
上述语法显示了包规范的创建。
封装主体
它由包规范中存在的所有元素的定义组成。它还可以包含规范中未声明的元素的定义,这些元素称为私有元素,只能从包内部调用。
以下是包体的特征。
- 它应该包含所有子程序的定义/游标 已在规范中声明。
- 它还可以拥有更多子程序或其他未在规范中声明的元素。这些被称为私有元素。
- 它是一个可信赖的对象,并且依赖于包规范。
- 每次编译规范时,包主体的状态都会变为“Invalid”。因此,每次编译规范后都需要重新编译。
- 私有元素在包体中使用之前应先定义。
- 包的第一部分是全局声明部分。这包括整个包可见的变量、游标和私有元素(前向声明)。
- 包的最后一部分是包初始化部分,每当在会话中第一次引用包时就会执行一次。
语法:
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>
- 上述语法显示了包主体的创建。
现在我们将了解如何在程序中引用包元素。
引用包元素
一旦在包中声明并定义了元素,我们就需要引用这些元素来使用它们。
可以通过调用包名称加上元素名称(以句点分隔)来引用包中的所有公共元素,即' 。 “”。
包的公共变量也可以以相同的方式用于分配和获取值,即' 。 “”。
在 PL/SQL 中创建包
在 PL/SQL 中,每当在会话中引用/调用一个包时,就会为该包创建一个新的实例。
Oracle 通过“包初始化”提供一种工具来初始化包元素或在创建此实例时执行任何活动。
这只不过是在定义所有包元素后写入包主体的一个执行块。当会话中第一次引用包时,将执行此块。
句法
CREATE [OR REPLACE] PACKAGE BODY <package_name> IS <Private element definition> <sub_program and public element definition> . BEGINE <Package Initialization> END <package_name>
- 上述语法显示了包主体中包初始化的定义。
前向声明
包中的前向声明/引用无非是单独声明私有元素并在包主体的后面部分定义它。
私有元素只有在包主体中声明后才能被引用。因此,使用前向声明。但这种用法并不常见,因为大多数情况下私有元素都是在包主体的第一部分声明和定义的。
前向声明是以下选项之一: 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>
上面的语法是前向声明。私有元素在包的前向部分单独声明,并在后向部分定义。
包中的游标使用
与其他元素不同,在包内使用光标时需要小心。
如果在包规范中或包主体的全局部分中定义了游标,则游标一旦打开就会持续存在直到会话结束。
因此,在引用游标之前,应始终使用游标属性“%ISOPEN”来验证游标的状态。
超载
重载是指拥有多个同名子程序的概念。这些子程序的参数数量、参数类型或返回类型各不相同,也就是说,名称相同但参数数量不同、参数类型不同或返回类型不同的子程序被视为重载。
当许多子程序需要执行相同的任务,但每个子程序的调用方式应该不同时,这很有用。在这种情况下,所有子程序的名称将保持相同,参数将根据调用语句进行更改。
例子1:在此示例中,我们将创建一个包来获取和设置“emp”表中员工信息的值。get_record 函数将返回给定员工编号的记录类型输出,set_record 过程将记录类型记录插入到 emp 表中。
步骤1) 封装规范创建
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 创建包含一个过程和一个函数的包规范。这两个现在是此包的公共元素。
步骤2) 包包含包主体,其中将定义所有过程和函数的实际定义。在此步骤中,创建包主体。
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:创建包主体。
- 代码行 9-16:定义规范中声明的元素“set_record”。这与在 PL/SQL 中定义独立过程相同。
- 代码行17-24: 定义元素“get_record”。与定义独立函数相同。
- 代码行25-26: 定义包初始化部分。
步骤3) 参考上面创建的包创建一个匿名块来插入和显示记录。
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: 在匿名块中填充记录类型变量的数据以调用包的“set_record”元素。
- 代码第 38 行: 已调用 guru99_get_set 包的“set_record”。现在包已实例化,并将持续到会话结束。
- 由于这是对该包的第一次调用,因此执行包初始化部分。
- 由“set_record”元素插入到表中的记录。
- 代码第 41 行: 调用“get_record”元素来显示插入的员工的详细信息。
- 在对包的“get_record”调用期间,第二次引用该包。但这次不执行初始化部分,因为包已在此会话中初始化。
- 代码行42-45: 打印员工详细信息。
包中的依赖关系
由于包是相关事物的逻辑分组,因此它具有一些依赖关系。以下是需要注意的依赖关系。
- 规范是一个独立的对象。
- 包主体依赖于规范。
- 包主体可以单独编译。每当规范编译时,主体都需要重新编译,否则它将失效。
- 包体中依赖于私有元素的子程序应该仅在私有元素声明之后定义。
- 规范和主体中引用的数据库对象在包编译时需要处于有效状态。
包装信息
一旦创建了包信息,包信息(如包源、子程序详细信息和重载详细信息)即可在 Oracle 数据定义表。
下表给出了数据定义表和表中可用的包信息。
表名 | 描述 | 询问 |
---|---|---|
所有对象 | 提供包的详细信息,如 object_id、creation_date、last_ddl_time 等。它将包含所有用户创建的对象。 | 从所有对象中选择 *,其中 object_name =' ‘ |
用户对象 | 提供包的详细信息,如 object_id、creation_date、last_ddl_time 等。它将包含当前用户创建的对象。 | 从用户对象中选择 *,其中 object_name =' ‘ |
所有来源 | 提供所有用户创建的对象的来源。 | 从 all_source 中选择 *,其中 name=' ‘ |
用户来源 | 提供当前用户创建的对象的来源。 | 从用户源中选择 *,其中名称=' ‘ |
所有程序 | 提供所有用户创建的子程序详细信息,如 object_id、过载详细信息等。 | 从所有过程选择 * 其中 object_name=' ‘ |
用户程序 | 提供当前用户创建的子程序详细信息,如 object_id、过载详细信息等。 | 从用户过程选择 * 其中 object_name=' ‘ |
UTL 文件 – 概述
UTL 文件是 Oracle 执行特殊任务。这主要用于从 PL/SQL 包或子程序读取和写入操作系统文件。它具有单独的函数来放置信息和从文件中获取信息。它还允许在本机字符集中进行读取/写入。
程序员可以使用它来写入任何类型的操作系统文件,文件将直接写入数据库服务器。写入时将提及名称和目录路径。
总结
我们现在已经了解了 PL / SQL,现在您应该可以开始进行下面的工作了。
- PL/SQL 包及其组件
- 封装的特性
- 引用和重载包元素
- 管理包中的依赖项
- 查看包信息
- 什么是UTL文件