VARRAY声明必须指定编译期固定最大长度,运行时不可超限,否则报ORA-22165;其本质是上限可控、顺序敏感、存储紧凑的集合类型,适用于有明确业务上限的场景。
PL/SQL 里 VARRAY 声明必须指定最大长度,不能“可变”
oracle 的 varray 名字有误导性——它不是运行时自由伸缩的数组,而是一个**编译期固定上限、运行时可少用但不可超限**的集合类型。你声明时写的那个数字(比如 varray(10))是硬限制,插入第 11 个元素会直接报错 ora-22165: given index [11] greater than specified size [10]。
常见错误是以为 VARRAY 类似 Java 的 ArrayList 或 Python 列表,试图动态 EXTEND 超出声明长度,或者在类型定义里写 VARRAY(*) ——这语法根本不存在,会报 PLS-00103。
- 声明格式唯一合法:
TYPE t_name IS VARRAY(n) OF element_type;,n必须是正整数常量(不能是变量或表达式) - 实际使用时元素个数可以 VARRAY(100) 但只存 3 个),但绝不能 > n
- 如果真需要动态扩容,该用
NESTED TABLE,不是VARRAY
什么时候该用 VARRAY,而不是 NESTED TABLE?
VARRAY 的核心价值在「顺序敏感 + 长度可控 + 存储紧凑」,典型场景是:电话号码列表(最多 5 个)、订单明细行(业务规则限定最多 20 行)、配置项枚举值(固定几项)。
它在数据库中以连续方式存储(类似 C 数组),查询时一次性加载,访问下标快;而 NESTED TABLE 是分散存储、带系统生成的唯一 ID,适合无序、可能大量增长的集合。
- 选
VARRAY:数据有明确业务上限、频繁按索引访问(如arr(1))、需保持插入顺序且不常增删中间项 - 避坑点:别用它存日志、交易流水这类天然无上限的数据——哪怕你设成
VARRAY(9999),也掩盖不了设计缺陷 - 兼容性注意:
VARRAY可以作为表列类型,但某些旧版 JDBC 驱动对它的支持不稳定,生产环境建议先测getArray()行为
VARRAY 初始化和赋值的三个关键动作
声明类型只是第一步,真正用起来要过三关:初始化、填充、访问。漏掉初始化(比如只声明变量不调用构造函数)会导致 ORA-06531: Reference to uninitialized collection。
- 类型定义后,变量声明需显式初始化:
my_arr t_phone_list := t_phone_list();(空构造)或t_phone_list('138...', '139...')(带初值) - 往已初始化的
VARRAY添加元素只能用EXTEND,但每次只能加一个,且总数不能超限:my_arr.EXTEND; my_arr(my_arr.COUNT) := '150...'; - 访问必须用有效下标(从 1 开始!),
my_arr(0)或my_arr(my_arr.COUNT+1)都报ORA-06532: Subscript outside of limit
嵌套表转 VARRAY 时最容易忽略的长度校验
当从查询结果(比如 SELECT CAST(COLLECT(...) AS t_varray_type))构造 VARRAY 时,如果集合元素数量超过类型定义的上限,语句直接失败,不会截断也不会警告。
这在批量导入或报表聚合时很危险——你以为 COLLECT 安全,其实它把校验甩给了类型定义。
- 安全做法:先用
COUNT(*)检查源数据量是否 ≤VARRAY上限,再执行CAST - 替代方案:改用
NESTED TABLE类型接收COLLECT结果,后续再按需截取前 N 项转VARRAY - 调试技巧:对疑似超限的查询,临时加
HAVING COUNT(*) > 10(假设你的VARRAY是(10))快速定位问题数据
真正麻烦的不是语法怎么写,而是得想清楚:这个“上限”是数据库约束,还是业务规则?如果是后者,约束应该落在应用层或检查约束上,而不是靠 VARRAY 硬扛。










