Python列表传入Oracle PL/SQL存储过程触发PLS-00306错误求助
问题原因分析
你遇到的PLS-00306错误主要有两个核心原因:
- 调用存储过程时未指定完整的包名+过程名(仅写
PROCEDURE_1,Oracle无法定位到包内的过程); - 你定义的
MY_ARRAY_TYPE是PL/SQL私有关联数组(索引表),这种类型仅在PL/SQL内部可见,无法通过Python数据库驱动(如cx_Oracle)直接传递普通列表进行映射。
解决方案
方案一:改用SQL级嵌套表类型(推荐,性能更优)
先创建SQL层面可见的集合类型,再调整存储过程和Python代码:
- 创建SQL级数组类型
CREATE OR REPLACE TYPE MY_SQL_ARRAY_TYPE IS TABLE OF NUMBER; /
- 修改包与存储过程(使用SQL级类型,同时改用批量插入提升效率)
CREATE OR REPLACE PACKAGE procedure_1_pkg AS PROCEDURE procedure_1(my_array MY_SQL_ARRAY_TYPE); END procedure_1_pkg; / CREATE OR REPLACE PACKAGE BODY procedure_1_pkg AS PROCEDURE procedure_1(my_array MY_SQL_ARRAY_TYPE) IS BEGIN -- 批量插入替代循环,性能提升明显 FORALL i IN 1..my_array.COUNT INSERT INTO TABLE_1(id) VALUES(my_array(i)); END procedure_1; END procedure_1_pkg; /
- 调整Python代码(转换列表为Oracle数组并调用)
import cx_Oracle # 建立连接(替换为你的连接信息) conn = cx_Oracle.connect("用户名/密码@数据库地址:端口/服务名") cur = conn.cursor() MY_ARRAY = [1, 2, 3, 4] # 将Python列表转换为Oracle可识别的数组类型 oracle_array = cur.arrayvar(cx_Oracle.NUMBER, MY_ARRAY) # 调用完整路径的存储过程 cur.callproc('procedure_1_pkg.procedure_1', parameters=[oracle_array]) conn.commit() cur.close() conn.close()
方案二:不修改原存储过程,用PL/SQL块中转
如果不想改动现有存储过程,可以通过Python执行PL/SQL块,先将列表元素赋值给关联数组,再调用目标过程:
import cx_Oracle conn = cx_Oracle.connect("用户名/密码@数据库地址:端口/服务名") cur = conn.cursor() MY_ARRAY = [1, 2, 3, 4] # 定义PL/SQL块,完成关联数组初始化与过程调用 plsql_block = """ DECLARE v_array procedure_1_pkg.MY_ARRAY_TYPE; BEGIN -- 给关联数组赋值 FOR i IN 1..:arr_count LOOP v_array(i) := :arr_elements(i); END LOOP; -- 调用包内存储过程 procedure_1_pkg.procedure_1(v_array); END; """ # 绑定参数:数组长度与元素列表 cur.execute(plsql_block, arr_count=len(MY_ARRAY), arr_elements=MY_ARRAY) conn.commit() cur.close() conn.close()
内容的提问来源于stack exchange,提问作者Eric
相关产品推荐
相关产品推荐

