Oracle存储过程中定义数组类型输入参数需先创建SQL集合类型(如CREATE TYPE string_array AS TABLE OF VARCHAR2(4000)),再在存储过程参数中声明为IN string_array;C#端须用Oracle.ManagedDataAccess配置OracleParameter,设置UdtTypeName为全大写类型名、CollectionType为PLSQLAssociativeArray,并确保用户具备EXECUTE权限。

Oracle 存储过程中怎么定义数组类型的输入参数?
Oracle 本身没有原生的“数组”类型供 PL/SQL 过程直接接收 C# 传入的 int[] 或 string[],必须借助自定义集合类型(TYPE ... AS TABLE OF ...)。这是整个方案的前提,跳过这步,C# 端再怎么封装都会报 ORA-06550: PLS-00306: wrong number or types of arguments。
你需要先在数据库中创建一个 schema 级别的集合类型:
CREATE OR REPLACE TYPE string_array AS TABLE OF VARCHAR2(4000);
或用于数字:
CREATE OR REPLACE TYPE number_array AS TABLE OF NUMBER;
注意:类型必须是 CREATE TYPE 创建的、可被存储过程参数引用的 SQL 类型(不是 PL/SQL 中的 INDEX BY TABLE),且需确保执行存储过程的用户有该类型的 EXECUTE 权限。
C# 中如何把 string[] 映射为 Oracle 的 string_array?
Oracle 官方驱动(Oracle.ManagedDataAccess)不支持直接将 .NET 数组绑定到自定义集合类型。必须手动构造 OracleParameter 并设置 OracleDbType 为对应集合类型名,同时用 UdtTypeName 指向数据库中的类型全名(含 schema)。
关键点:
- 如果类型在当前用户下创建,
UdtTypeName写"STRING_ARRAY"即可;若在其他 schema(如HR.STRING_ARRAY),必须写完整名称(大小写敏感) -
Value必须是Array实例(如new string[] { "a", "b" }),不能是List<string></string>或其它包装类 - 驱动版本需 ≥ 19.10(旧版对 UDT 支持不稳定,易抛
ORA-03113或空指针)
示例代码片段:
var param = new OracleParameter("p_names", OracleDbType.Varchar2)
{
CollectionType = OracleCollectionType.PLSQLAssociativeArray,
UdtTypeName = "STRING_ARRAY",
Value = new string[] { "Alice", "Bob" }
};
为什么用了 PLSQLAssociativeArray 还是报错?
常见错误是混淆了两种 Oracle 集合机制:TABLE OF(SQL 类型,用于存储过程 IN 参数)和 ASSOCIATIVE ARRAY(PL/SQL 类型,仅能在 PL/SQL 块内使用)。C# 绑定的是前者,但参数声明写成了后者,就会失败。
检查你的存储过程签名是否正确:
CREATE OR REPLACE PROCEDURE process_names(p_names IN string_array) AS ...
而不是:
CREATE OR REPLACE PROCEDURE process_names(p_names IN string_array INDEX BY PLS_INTEGER) AS ...
后者是 PL/SQL 关联数组,C# 无法直接传递。另外,确保连接字符串中启用了 Unicode=true(尤其含中文时),否则 Varchar2 数组元素可能被截断或乱码。
有没有更轻量、不用建库类型的方法?
有,但属于权衡方案:用逗号分隔字符串 + REGEXP_SUBSTR 在 PL/SQL 里拆分。适用于数据量小、元素不含逗号/引号的场景。
C# 端只需传普通 Varchar2 参数:
cmd.Parameters.Add(new OracleParameter("p_csv", string.Join(",", names)));
PL/SQL 侧拆分(性能差,不推荐用于 >100 元素):
SELECT TRIM(REGEXP_SUBSTR(p_csv, '[^,]+', 1, LEVEL)) FROM DUAL CONNECT BY REGEXP_SUBSTR(p_csv, '[^,]+', 1, LEVEL) IS NOT NULL;
真正要稳定处理数组,还是得走 UDT 路线——类型定义一次,复用所有过程,且 Oracle 能做批量绑定优化。别省那几条 CREATE TYPE 语句。
最容易被忽略的是权限和大小写:UdtTypeName 错一个字母、少一个 schema 前缀,或者用户没被授予 GRANT EXECUTE ON STRING_ARRAY TO your_user,都会静默失败成参数类型不匹配。











