Oracle PL/SQL 包:类型、规范、主体 [示例]

包中的内容 Oracle?
Oracle PL / SQL 包是一个逻辑组ping 相关的 子程序 将(过程/函数)合并成一个单独的元素。该包会被编译并存储为数据库对象,以便后续重用。
软件包的组件
PL/SQL 包包含两个组件。
- 包装规格
- 封装主体
包装规格
软件包规范包含所有公共组件的声明 变量, 游标对象、过程、函数和 例外.
以下是该封装规格的一些特点。
- 规范中声明的元素可以从包外部访问。这类元素被称为公共元素。
- 包规范是一个独立元素,这意味着它可以单独存在,而无需包主体。
- 每当引用一个软件包时,都会为该特定会话创建一个该软件包的实例。
- 为会话创建实例后,在该实例中启动的所有包元素在会话结束前都有效。
句法
CREATE [OR REPLACE] PACKAGE <package_name> IS <sub_program and public element declaration> . . END <package name>
以上语法展示了如何创建软件包规范。
封装主体
包体包含包规范中所有元素的定义。它还可以包含规范中未声明的元素的定义;这些元素称为私有元素,只能从包内部调用。
以下是包装体的特征。
- 它应该包含规范中声明的所有子程序/游标的定义。
- 它还可以包含规范中未声明的更多子程序或其他元素。这些被称为私有元素。
- 这是一个依赖对象,它依赖于包规范。
- 每次编译规范时,包体的状态都会变为“无效”。因此,每次编译规范后都需要重新编译包体。
- 私有元素在包体中使用之前应先定义。
- 包体的第一部分是全局声明部分。这包括变量、游标和私有元素(前向声明),这些元素对整个包都是可见的。
- 包的最后一部分是包初始化部分,每当会话中首次引用该包时,该部分都会执行一次。
语法:
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> . BEGIN <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)创建软件包规格
下面的屏幕截图显示了正在创建的 guru99_get_set 包规范。 Oracle.
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
Code 说明
- Code 第 1-5 行: 创建了包含一个过程和一个函数的 guru99_get_set 包规范。这两个过程和函数现在是该包的公共元素。
步骤2) 该包包含一个包体,其中定义了所有过程和函数的实际定义。在此步骤中,将创建包体。
下面的屏幕截图显示了 guru99_get_set 包体的定义。 Oracle.
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; BEGIN dbms_output.put_line('Control is now executing the package initialization part'); END guru99_get_set; /
输出:
Package body created
Code 说明
- Code 第7行: 创建包主体。
- Code 第 9-16 行: 定义规范中声明的元素“set_record”。这与在PL/SQL中定义独立过程相同。
- Code 第 17-24 行: 定义元素“get_record”。这与定义一个独立函数的效果相同。
- Code 第 25-26 行: 定义包初始化部分。
步骤3) 创建一个匿名块,通过引用上面创建的包来插入和显示记录。
下面的屏幕截图显示了调用该包的匿名代码块及其输出。 Oracle.
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:=1004; l_emp_rec.emp_name:='CCC'; l_emp_rec.salary:=20000; l_emp_rec.manager:='BBB'; guru99_get_set.set_record(l_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:'||l_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
Code 说明:
- Code 第 34-37 行: 在匿名块中填充记录类型变量的数据,以调用包的“set_record”元素。
- Code 第38行: 已调用 guru99_get_set 包的 'set_record' 函数。现在该包已实例化,并将持续到会话结束。由于这是首次调用该包,因此会执行包初始化部分,并通过 'set_record' 函数将记录插入到表中。
- Code 第41行: 调用“get_record”元素以显示插入员工的详细信息。此调用期间第二次引用了该包,但由于该包已在此会话中初始化,因此不会再次执行初始化部分。
- Code 第 42-45 行: 打印员工详细信息。
包中的依赖关系
由于该软件包是一个逻辑组ping 它与一些相关事物存在依赖关系。以下是需要注意的依赖关系。
- 规范是一个独立对象。
- 封装体取决于具体规格。
- 包体可以单独编译。每当规范编译完毕后,包体也需要重新编译,因为它会失效。
- 包体中依赖于私有元素的子程序应该只在私有元素声明之后定义。
- 规范和正文中引用的数据库对象在包编译时必须处于有效状态。
包装信息
包创建完成后,包信息(例如包源、子程序详细信息和重载详细信息)即可在以下位置找到: Oracle 数据字典表。
下表给出了数据字典表以及每个表中可用的包信息。
| 表名 | 描述 | 询问 |
|---|---|---|
| 所有对象 | 提供包的详细信息,例如 object_id、creation_date、last_ddl_time 等。它包含所有用户创建的对象。 | 从所有对象中选择 *,其中 object_name =' ‘ |
| 用户对象 | 提供包的详细信息,例如 object_id、creation_date、last_ddl_time 等。它包含当前用户创建的对象。 | 从用户对象中选择 *,其中 object_name =' ‘ |
| 所有来源 | 提供所有用户创建的对象的来源。 | 从 all_source 中选择 *,其中 name=' ‘ |
| 用户来源 | 提供当前用户创建的对象的来源。 | 从用户源中选择 *,其中名称=' ‘ |
| 所有程序 | 提供所有用户创建的子程序详细信息,例如 object_id、重载详细信息等。 | SELECT * FROM all_procedures Where object_name=' ' |
| 用户程序 | 提供当前用户创建的子程序详细信息,如 object_id、过载详细信息等。 | SELECT * FROM user_procedures Where object_name=' ' |
UTL_FILE – 概述
UTL_FILE 是由 UTL_FILE 提供的独立实用程序包。 Oracle 它用于执行特殊任务。主要用于从 PL/SQL 包或子程序中读取和写入操作系统文件。它具有用于向文件中写入信息和从文件中读取信息的独立函数。它还允许使用本机字符集进行读写操作。
程序员可以使用此功能编写任何类型的操作系统文件,文件将直接写入数据库服务器。文件名和目录路径在编写时已指定。





