pl/sql中无原生多维数组,仅支持嵌套关联数组(index by table套index by table),需显式初始化每层、分两层遍历并检查exists,大数据量或复杂查询应改用gtts或json。
pl/sql 里没有真正意义上的“多维数组”,只有嵌套的关联数组
pl/sql 原生不支持像 java 或 python 那样的二维数组语法(比如 arr[i][j])。所谓“多维”,实际是用关联数组(index by table)套关联数组:外层数组的每个元素本身又是另一个 index by table。这本质是“数组的数组”,不是内存连续的多维结构。
常见错误是直接写 tab(i)(j) := val 却没初始化内层数组——PL/SQL 不会自动创建子表,运行时抛 ORA-06531: Reference to uninitialized collection。
- 必须显式初始化每一层:
tab(i) := inner_type(); - 键类型要一致:外层常用
PLS_INTEGER或VARCHAR2,内层键类型可不同,但需在定义时明确 - 性能上,嵌套越深,访问开销越大;频繁
EXTEND内层数组可能触发隐式复制(尤其含大对象时)
声明嵌套关联数组的关键语法和类型约束
不能直接在变量声明里写两层 INDEX BY。必须先定义内层类型,再用它定义外层元素类型。
例如想建一个“部门 →(员工ID → 薪资)”结构:
TYPE salary_map_t IS TABLE OF NUMBER INDEX BY PLS_INTEGER; TYPE dept_salaries_t IS TABLE OF salary_map_t INDEX BY VARCHAR2(10);
这里 salary_map_t 是内层类型,dept_salaries_t 是外层类型。注意:INDEX BY 只能出现在 TYPE 定义中,不能用于变量声明右侧。
- 外层键若用
VARCHAR2,长度必须指定(如VARCHAR2(10)),否则编译报错 - 内层类型不能是
RECORD的直接INDEX BY,需先封装为自定义类型 - 不支持用
%ROWTYPE直接做索引键,键只能是标量类型
遍历嵌套关联数组时如何避免 NO_DATA_FOUND 和越界
嵌套结构的遍历必须分两层:先用 FIRST/NEXT 遍历外层键,对每个外层键再检查内层是否已初始化、再遍历其键。跳过未初始化的内层,否则触发 NO_DATA_FOUND 异常。
典型安全遍历模式:
DECLARE
l_dept_key VARCHAR2(10) := dept_salaries.FIRST;
BEGIN
WHILE l_dept_key IS NOT NULL LOOP
IF dept_salaries(l_dept_key).COUNT > 0 THEN -- 确保内层非空且已初始化
DECLARE
l_emp_id PLS_INTEGER := dept_salaries(l_dept_key).FIRST;
BEGIN
WHILE l_emp_id IS NOT NULL LOOP
DBMS_OUTPUT.PUT_LINE('Dept ' || l_dept_key || ', Emp ' || l_emp_id || ': ' || dept_salaries(l_dept_key)(l_emp_id));
l_emp_id := dept_salaries(l_dept_key).NEXT(l_emp_id);
END LOOP;
END;
END IF;
l_dept_key := dept_salaries.NEXT(l_dept_key);
END LOOP;
END;
-
COUNT只返回已赋值元素个数,不能代替EXISTS判断某键是否存在 - 内层键若为
PLS_INTEGER,用FIRST/NEXT更安全;若为VARCHAR2,需确保键值实际存在,否则EXISTS必须前置检查 - 不要依赖
FOR i IN 1..COUNT,关联数组下标不保证连续
替代方案:什么时候该放弃嵌套关联数组?
当数据量大、需要排序、频繁范围查询或跨会话共享时,嵌套关联数组反而成为负担。它的内存驻留、无持久化、无索引特性会暴露短板。
- 纯内存缓存少量配置?用嵌套关联数组没问题
- 要按薪资区间查员工?改用全局临时表(
GTTS)+ 索引更高效 - 需 JSON 输出?用
JSON_OBJECT+ 嵌套JSON_ARRAYAGG比手撸嵌套循环清晰得多 - Oracle 21c+ 可考虑
KEY_VALUE类型或原生 JSON 表函数,减少手动管理键值逻辑
嵌套的“方便”只在小规模、强结构、短生命周期场景成立;一旦涉及任意键查找、动态深度或调试追踪,键路径丢失和异常堆栈模糊就会立刻拖慢排查节奏。










