PLS-00306和ORA-06550错误90%源于参数契约不匹配,即参数个数、类型、方向(IN/OUT)或长度与存储过程真实签名不符,需通过ALL_ARGUMENTS视图查证定义,并严格对齐调用侧的类型、方向、大小写及NULL处理。

PLS-00306 和 ORA-06550 是 Oracle 中最常被误判为“代码写错了”的错误,其实绝大多数情况根本不是语法或逻辑问题,而是调用侧与定义侧的参数契约没对齐。直接结论:90% 的这类报错,根源在参数个数、类型、方向(IN/OUT)或长度这四点之一不匹配,而不是存储过程本身有 bug。
查清存储过程真实签名,别靠记忆或文档
很多人凭印象写调用代码,或者翻旧文档——但包里过程可能已重编译、改过参数。必须查 ALL_ARGUMENTS 视图:
SELECT argument_name, position, data_type, in_out, type_owner, type_name FROM all_arguments WHERE package_name = 'PKG_QSDUBBO_NEW' AND object_name = 'PKG_QSDUBBO_NEW_GETFYZFSZ' ORDER BY position;
注意三点:
-
object_name区分大小写,必须和CREATE OR REPLACE PROCEDURE里写的完全一致 - 如果过程在包里,
package_name是包名,object_name是过程名(不是全名) -
in_out列显示IN、OUT或IN/OUT,OUT参数必须传变量,不能传常量或表达式
C# / .NET 调用时的冒号(:)和参数方向陷阱
OracleHelper 或 ODP.NET 中,FUNCTION 和 PROCEDURE 的参数写法不同,且 OUT 参数必须显式声明方向:
- 函数调用参数必须带冒号前缀,如
":P_VENDOR_CODE";存储过程参数通常不加(除非用命名绑定) -
OracleParameter构造时,OracleDbType必须和数据库中定义的类型严格对应:Varchar2对应OracleDbType.Varchar2,不能用String -
OUT参数必须指定ParameterDirection.Output,且必须设置Size(比如Varchar2(20)就得写Size = 20),否则返回值截断为单字符 - 传
null值要小心:.NET 的null传到 Oracle 可能变成空字符串或隐式转换失败,建议用DBNull.Value
PL/SQL 块内调用时,变量赋值顺序和类型推导容易翻车
直接把函数调用当表达式塞进 INSERT 或 SELECT,常触发 PLS-00306,因为 Oracle 无法在上下文中准确推导返回类型:
- 不要写
INSERT INTO t (id) VALUES (my_func()),哪怕my_func()明确返回VARCHAR2 - 改成先声明变量:
v_id VARCHAR2(32);,再赋值:v_id := my_func();,最后插入 - 所有涉及
SYS_REFCURSOR、自定义 TYPE(如TAB_CUSTOMER)或BLOB/CLOB的参数,必须用对应 descriptor 构建,不能直接传 .NET List 或 string - Oracle 11g+ 升级后出现该错,可能是
CTXSYS.SYNCNR等系统过程未重编译,需按官方补丁步骤修复
跨版本兼容性常被忽略,尤其客户端驱动与数据库小版本差
开发机用 Oracle 19c 客户端,连测试库是 12.2,看似没问题,但某些 TYPE 或 REF CURSOR 行为有细微差异,导致参数校验失败:
- 检查
sqlplus -v输出的客户端版本,和数据库SELECT * FROM v$version;对比 - ODP.NET 驱动版本必须与数据库主版本兼容(如 19c 数据库建议用 ODP.NET Core 19.11+)
- 如果用了自定义集合类型(
TYP_CUSTOMER),确保客户端连接时加载了对应 type metadata,否则ArrayDescriptor.createDescriptor()会静默失败
真正麻烦的从来不是“怎么写”,而是“哪一环悄悄变了”。参数契约一旦松动,错误就藏在最顺手的那行调用里。


















