oracle中无“关联数组”,只有index by table(索引表,支持字符串/数字下标,仅pl/sql内存使用)和nested table(数据库级有序集合,下标从1开始,可持久化、支持sql操作),二者语法、初始化、存储位置及使用场景截然不同,不可混用。

Oracle里没有“关联数组”,只有INDEX BY TABLE和NESTED TABLE
Oracle PL/SQL 中没有真正意义上的“关联数组”(如 PHP 的 array 或 Python 的 dict),常被误称为“关联数组”的其实是 INDEX BY TABLE(索引表),而 NESTED TABLE 是另一种集合类型,本质是**有序、可变长、存储在数据库表中的嵌套表**,它不支持键名访问,只支持下标(从 1 开始)或 SQL 操作。两者语法、生命周期、存储位置和使用场景完全不同,混用会导致编译错误或运行时异常。
定义和初始化 INDEX BY TABLE(常被误叫“关联数组”)
如果你需要类似“键-值”映射的内存结构(比如用字符串作下标),必须用 INDEX BY 声明,且只能在 PL/SQL 块、过程、函数内使用,不能作为表列类型:
DECLARE
TYPE t_emp_map IS TABLE OF VARCHAR2(100) INDEX BY VARCHAR2(10);
l_emps t_emp_map;
BEGIN
l_emps('E001') := 'Alice';
l_emps('E002') := 'Bob';
DBMS_OUTPUT.PUT_LINE(l_emps('E001')); -- 输出 Alice
END;
-
INDEX BY VARCHAR2(n)或INDEX BY PLS_INTEGER才合法;INDEX BY NUMBER会报错 - 不能用
NOT NULL约束在元素级别(类型定义里不允许) - 不能直接用 SQL 查询(比如
SELECT * FROM TABLE(l_emps)不行),它是纯 PL/SQL 内存结构 - 未赋值的键访问会触发
NO_DATA_FOUND异常,需用EXISTS()判断:IF l_emps.EXISTS('E999') THEN ...
定义和初始化 NESTED TABLE(真正的数据库级集合类型)
NESTED TABLE 是 Oracle 的持久化集合类型,必须先在 SQL 层定义为对象类型或嵌套表类型,再用于表列或 PL/SQL 变量。它不支持字符串下标,所有访问都基于位置(1-based):
-- 1. 创建嵌套表类型(SQL 层)
CREATE OR REPLACE TYPE t_phone_list AS TABLE OF VARCHAR2(20);
<p>-- 2. 在表中使用(可选)
CREATE TABLE employees (
emp_id NUMBER,
phones t_phone_list
) NESTED TABLE phones STORE AS phones_nt;</p><p>-- 3. PL/SQL 中声明并初始化
DECLARE
l_phones t_phone_list := t_phone_list(); -- 必须显式调用构造函数
BEGIN
l_phones.EXTEND; l_phones(1) := '+86-13800138000';
l_phones.EXTEND; l_phones(2) := '+86-13900139000';
-- 或批量初始化:l_phones := t_phone_list('+86-138...', '+86-139...');
END;</p>
- 声明变量时必须用构造函数初始化(空括号
t_phone_list()或带值t_phone_list('a','b')),否则为NULL,调用EXTEND会报ORA-06531: Reference to uninitialized collection -
NESTED TABLE可以用 SQL 操作:SELECT COLUMN_VALUE FROM TABLE(l_phones) - 作为表列时,需配合
STORE AS子句指定存储段,否则建表失败 - 不支持
INDEX BY,下标只能是正整数,且必须已EXTEND或预置
什么时候该用哪个?关键区别在生命周期和上下文
如果只是临时存点键值对做逻辑判断(比如缓存 ID → 名称映射),用 INDEX BY TABLE;如果要存进数据库字段、参与 SQL JOIN、或需跨事务持久化,必须用 NESTED TABLE 类型 + 构造函数初始化。二者不能互相赋值,也不能用相同语法初始化——把 NESTED TABLE 当成“高级数组”去用字符串下标,一定会卡在编译阶段。
最常被忽略的一点:PL/SQL 中声明的 NESTED TABLE 变量,即使类型已定义,也必须显式构造(哪怕为空),否则连 COUNT 都会报错;而 INDEX BY TABLE 变量声明即可用,但越界访问不报错而是抛异常,得靠 EXISTS 主动防护。











