Oracle PL/SQL 集合:Varray、嵌套和按表索引

⚡ 智能摘要

PL/SQL 集合是同一数据类型元素的有序分组,每个元素都通过下标访问。集合分为三种类型:Varray、嵌套表和索引表。它们的区别在于集合大小是否固定、下标的工作方式以及是否可以存储在数据库中。

  • 🧺 定义: 集合包含许多相同类型的元素,每个元素都由一个唯一的下标标识。
  • 📐 Varray: 固定上标尺寸,始终密排,数字下标,使用前必须初始化。
  • 📚 嵌套表格: 没有大小限制,可以是密集的或稀疏的,存储在系统表中,可以用 EXTEND 扩展。
  • ???? 按表格索引: 没有大小限制,下标可以是字符串或负整数,不存储在数据库中。
  • ????️ 构造函数: Varray 和嵌套表需要显式构造函数进行初始化才能引用。
  • 🛠️ 方法: COUNT、EXISTS、FIRST、LAST、EXTEND、TRIM 和 DELETE 用于管理集合。
  • 块: 批量收集功能可一步填充集合,实现快速处理。

Oracle PL/SQL 集合

什么是集合?

集合是特定数据类型的一组有序元素。它可以是简单数据类型的集合,也可以是复杂数据类型的集合,例如用户自定义数据类型或记录类型。

在一个集合中,每个元素都由一个称为元素的术语来标识。 “下标”。 每个项目都被分配一个唯一的下标,可以通过引用该唯一的下标来操作或获取数据。

当需要处理或操作大量相同类型的数据时,集合最为有用。可以使用“批量”选项对集合进行整体填充和操作。 Oracle.

集合根据结构、下标和存储方式进行分类,如下所示:

  • 索引表(也称为关联数组)
  • 嵌套表
  • 变量数组

任何时候,集合中的数据都可以用三个术语来指代:集合名称、下标和字段或列名称,例如“ ( )。您将在以下章节中了解这些收藏类别。

收藏类型概览

这三种收藏类型各有优缺点。下表将它们并列列出,然后再详细介绍每一种。

方面 瓦雷 嵌套表 按表索引
尺寸 固定上限 没有限制 没有限制
数字 数字 整数或字符串
密度 总是很稠密 密集或稀疏 总是稀疏的
存储在数据库中 没有
需要初始化 没有

变量数组

Varray 是一种数组,其数组大小固定且不能超过限制。Varray 的下标是一个数值。Varray 的属性包括:

  • 尺寸上限是固定的。
  • 从下标“1”开始按顺序填充。
  • 这种集合类型始终是稠密的;我们无法删除单个数组元素。Varray 可以整体删除,也可以从末尾进行裁剪。
  • 因为它密度很高,所以几乎没有柔韧性。
  • 当数组大小已知,并且对所有元素执行类似操作时,这种方法更为合适。
  • 集合的下标和计数始终保持稳定。
  • 必须先初始化才能使用。对未初始化的集合执行除 EXISTS 之外的任何操作都会抛出错误。
  • 它可以创建为整个数据库中可见的数据库对象,也可以创建为仅在子程序中使用的子程序对象。

下图解释了 Varray(密集型)的内存分配。

1 2 3 4 5 6 7
价值 XYZ 直流电压 斯德 CXS 维BC 新和成 QWE

VARRAY 的语法:

TYPE <type_name> IS VARRAY (<SIZE>) OF <DATA_TYPE>;
  • 在上述语法中,type_name 被声明为类型为 'DATA_TYPE' 的 VARRAY,大小限制为给定值。数据类型可以是简单数据类型,也可以是复杂数据类型。

嵌套表

嵌套表是一种数组大小不固定的集合。它具有数值下标类型。更多关于嵌套表类型的信息:

  • 嵌套表没有大小上限。
  • 由于上限不固定,每次使用前都需要使用“EXTEND”关键字扩展内存。
  • 从下标“1”开始按顺序填充。
  • 这种集合类型可以同时满足以下两个条件: 密集和稀疏我们可以将其创建为密集型,也可以随机删除单个元素,使其变为稀疏型。
  • 它为删除数组元素提供了更大的灵活性。
  • 它存储在系统生成的数据库表中,可以在选择查询中使用以获取值。
  • 下标和计数可以不同。
  • 必须先初始化才能使用。对未初始化的集合执行除 EXISTS 之外的任何操作都会抛出错误。
  • 它可以创建为整个数据库中可见的数据库对象,也可以创建为仅在子程序中使用的子程序对象。

下图解释了嵌套表(稠密表和稀疏表)的内存分配。空白元素区域表示稀疏元素。

1 2 3 4 5 6 7
值(密集) XYZ 直流电压 斯德 CXS 维BC 新和成 QWE
值(稀疏) QWE ASD 阿富汗 ASD 黄万华

嵌套表的语法:

TYPE <type_name> IS TABLE OF <DATA_TYPE>;
  • 在上述语法中,type_name 被声明为类型为 'DATA_TYPE' 的嵌套表集合。数据类型可以是简单类型,也可以是复杂类型。

按表索引

索引表是一种数组大小不固定的集合。与其他集合类型不同,索引表的下标可以由用户定义。索引表的属性包括:

  • 下标可以是整数或字符串。创建集合时应指定下标类型。
  • 这些集合不是按顺序存储的。
  • 它们在本质上总是稀疏的。
  • 数组大小不固定。
  • 它们无法存储在数据库列中。它们是在特定会话中创建和使用的。
  • 它们在维护下标方面提供了更大的灵活性。
  • 下标可以是负序列。
  • 它们更适合在同一子程序中使用的相对较小的集合值。
  • 它们无需在使用前进行初始化。
  • 它们不能作为数据库对象创建;它们只能在子程序内部创建。
  • BULK COLLECT 不能与此集合类型一起使用,因为必须为每个记录显式指定下标。

下图解释了索引表(稀疏表)的内存分配。空白元素区域表示稀疏元素。

下标 (varchar) 第一 第二 第三 第四 第五 第六 第七
值(稀疏) QWE ASD 阿富汗 ASD 黄万华

索引表的语法:

TYPE <type_name> IS TABLE OF <DATA_TYPE> INDEX BY VARCHAR2 (10);
  • 在上述语法中,type_name 被声明为类型为 'DATA_TYPE' 的索引表集合。下标变量被指定为 VARCHAR2 类型,最大长度为 10。

集合中的构造函数和初始化概念

构造函数是由提供的内置函数。 Oracle 与对象或集合同名的构造函数。每当会话中首次引用对象或集合时,这些构造函数都会首先执行。集合上下文中构造函数的重要细节:

  • 对于集合,必须显式调用这些构造函数来初始化集合。
  • Varray 和嵌套表都需要通过这些构造函数进行初始化,然后才能在程序中引用它们。
  • 构造函数隐式地扩展了集合(Varray 除外)的内存分配,因此它也可以向集合分配变量。
  • 通过构造函数赋值永远不会使集合变为稀疏集合。

收集方法

Oracle 它提供了许多用于操作和处理集合的函数。这些函数用于确定和修改集合的不同属性。下表列出了不同的函数及其说明。

付款方式 描述 句法
存在(n) 返回布尔值。如果第 n 个元素存在,则返回 TRUE,否则返回 FALSE。EXISTS 函数只能用于未初始化的集合。 .EXISTS(元素位置)
COUNT个 返回集合中元素的总数。 。数数
极限 返回集合的最大大小。对于 Varray,返回固定大小;对于嵌套表和索引表,返回 NULL。 。限制
第一 返回集合中第一个下标的值。 。第一的
LAST 返回集合中最后一个下标的值。 。最后的
先前 (n) 返回第 n 个元素的前一个下标。如果没有前一个下标,则返回 NULL。 .PRIOR(n)
下一个(n) 返回第 n 个元素的下一个下标。如果没有下标,则返回 NULL。 .NEXT(n)
延伸 扩展集合末尾的一个元素。 。延长
延伸(n) 在集合末尾扩展 n 个元素。 .EXTEND(n)
扩展 (n,i) 在集合末尾添加第 i 个元素的 n 个副本。 .EXTEND(n,i)
TRIM 从集合末尾移除一个元素。 。修剪
修剪(n) 从集合末尾移除 n 个元素。 .TRIM(n)
删除 删除集合中的所有元素,使其变为空。 。删除
删除(n) 删除第 n 个元素。如果第 n 个元素为 NULL,则不执行任何操作。 .删除(n)
删除 (m,n) 删除集合中第 m 个元素到第 n 个元素。 .删除(m,n)

示例 1:子程序级别的记录类型

在这个例子中,我们将看到如何使用“填充集合”来填充集合。批量收集以及如何引用收集的数据。

使用 BULK COLLECT 填充的 PL/SQL 集合示例

DECLARE
TYPE emp_det IS RECORD
(
EMP_NO NUMBER,
EMP_NAME VARCHAR2(150),
MANAGER NUMBER,
SALARY NUMBER
);
TYPE emp_det_tbl IS TABLE OF emp_det;
guru99_emp_rec emp_det_tbl:= emp_det_tbl();
BEGIN
INSERT INTO emp (emp_no,emp_name, salary, manager) VALUES (1000,'AAA',25000,1000);
INSERT INTO emp (emp_no,emp_name, salary, manager) VALUES (1001,'XXX',10000,1000);
INSERT INTO emp (emp_no, emp_name, salary, manager) VALUES (1002,'YYY',15000,1000);
INSERT INTO emp (emp_no,emp_name,salary, manager) VALUES (1003,'ZZZ',7500,1000);
COMMIT;
SELECT emp_no,emp_name,manager,salary BULK COLLECT INTO guru99_emp_rec
FROM emp;
dbms_output.put_line ('Employee Detail');
FOR i IN guru99_emp_rec.FIRST..guru99_emp_rec.LAST
LOOP
dbms_output.put_line ('Employee Number: '||guru99_emp_rec(i).emp_no);
dbms_output.put_line ('Employee Name: '||guru99_emp_rec(i).emp_name);
dbms_output.put_line ('Employee Salary:'|| guru99_emp_rec(i).salary);
dbms_output.put_line('Employee Manager Number:'||guru99_emp_rec(i).manager);
dbms_output.put_line('--------------------------------');
END LOOP;
END;
/

Code 说明

  • Code 第 2-8 行: 记录类型 'emp_det' 表声明包含列 emp_no、emp_name、manager 和 salary,数据类型分别为 NUMBER、VARCHAR2、NUMBER 和 NUMBER。
  • Code 第9行: 创建记录类型为“emp_det”的集合“emp_det_tbl”。
  • Code 第10行: 将变量“guru99_emp_rec”声明为“emp_det_tbl”类型,并使用空构造函数对其进行初始化。
  • Code 第 12-15 行: 将示例数据插入“emp”表。
  • Code 第16行: 提交插入事务。
  • Code 第17行: 使用“BULK COLLECT”从“emp”表中批量提取记录并填充集合变量。变量“guru99_emp_rec”现在包含表“emp”中的所有记录。
  • Code 第 19-26 行: 设置“FOR”循环,逐条打印集合中的所有记录。集合方法 FIRST 和 LAST 分别用作下限和上限。 循环.

输出: 执行上述代码后,将得到以下输出。

Employee Detail
Employee Number: 1000
Employee Name: AAA
Employee Salary: 25000
Employee Manager Number: 1000
----------------------------------------------
Employee Number: 1001
Employee Name: XXX
Employee Salary: 10000
Employee Manager Number: 1000
----------------------------------------------
Employee Number: 1002
Employee Name: YYY
Employee Salary: 15000
Employee Manager Number: 1000
----------------------------------------------
Employee Number: 1003
Employee Name: ZZZ
Employee Salary: 7500
Employee Manager Number: 1000
----------------------------------------------

常见问题

Varray 的大小有限制,并且始终是稠密的。嵌套表没有大小限制,可以是稀疏的,并且可以扩展,这使得它更适合处理不断增长或存在数据缺口的情况。

因为它是一个内存中的关联数组,而不是一个存储的表。下标充当查找键,因此可以使用字符串或负整数,这对于会话内的键值查找非常有用。

未初始化的 Varray 或嵌套表在原子上是空的,因此引用其中的元素会引发错误。调用构造函数会分配内存,之后才能使用 EXTEND 和赋值语句添加数据。

是的。考虑到数据大小是否固定、数据是否存储以及是否需要字符串键,人工智能可以指出 Varray、嵌套表或索引表,并解释其中的权衡取舍。

BULK COLLECT 将所有行加载到集合中,只需在 SQL 和 PL/SQL 引擎之间进行一次上下文切换,而不是像传统方式那样每行切换一次,这样可以大大降低大型结果集的开销。

总结一下这篇文章: