
Oracle Python 驱动(oracledb)不支持直接绑定 Python 字典或 dict_items 对象;需将字典转换为 PL/SQL 可识别的记录数组(如自定义 OBJECT 或 RECORD 类型),再通过 callproc/execute 传入。
oracle python 驱动(oracledb)不支持直接绑定 python 字典或 `dict_items` 对象;需将字典转换为 pl/sql 可识别的记录数组(如自定义 object 或 record 类型),再通过 `callproc`/`execute` 传入。
在 Oracle 数据库与 Python 协同开发中,常需将 Python 端的结构化数据(如字典)传递至 PL/SQL 进行业务逻辑处理。但需明确:oracledb 驱动原生不支持 dict 或 dict_items 的直接绑定——尝试传入 d_data.items() 会触发 DPY-3002: Python value of type "dict_items" is not supported 错误。
根本原因在于,PL/SQL 关联数组(INDEX BY VARCHAR2)虽支持字符串索引,但 oracledb 绑定机制仅兼容基于整数索引的集合(如 INDEX BY BINARY_INTEGER),且要求输入为已注册的 SQL 类型(如 OBJECT 或 RECORD 封装的嵌套表)。
✅ 正确实现路径如下:
1. 在数据库中定义可复用的数据类型
首先创建一个 PL/SQL 包,声明键值对记录类型及对应集合:
CREATE OR REPLACE PACKAGE data_types AS
TYPE key_value_pair IS RECORD (
key VARCHAR2(100),
value VARCHAR2(100)
);
TYPE key_value_list IS TABLE OF key_value_pair INDEX BY BINARY_INTEGER;
END;
/
⚠️ 注意:此处使用 INDEX BY BINARY_INTEGER(而非 VARCHAR2),因 oracledb 仅支持整数索引的集合绑定;关联数组(INDEX BY VARCHAR2)无法直接从 Python 绑定输入。
2. Python 端构造并绑定记录列表
利用 connection.gettype() 获取已注册的 SQL 类型,逐项填充键值对对象:
with connection.cursor() as cur:
d_data = {'111': 'YES', '222': 'NO', '333': 'YES'}
# 获取数据库中定义的 RECORD 类型
kvp_type = connection.gettype("DATA_TYPES.KEY_VALUE_PAIR")
kvp_list = []
for key, value in d_data.items():
kvp = kvp_type.newobject()
kvp.KEY = key
kvp.VALUE = value
kvp_list.append(kvp)
# 执行 PL/SQL 块(注意::data 是 IN 参数,类型为 key_value_list)
cur.execute("""
DECLARE
TYPE d_icusnums_type IS TABLE OF VARCHAR2(100) INDEX BY VARCHAR2(100);
d_icusnums d_icusnums_type;
BEGIN
-- 将传入的记录数组转存为关联数组
FOR i IN 1 .. :data.COUNT LOOP
d_icusnums(:data(i).KEY) := :data(i).VALUE;
END LOOP;
-- 示例:输出键数量(可通过 OUT 参数返回)
DBMS_OUTPUT.PUT_LINE('Processed ' || d_icusnums.COUNT || ' keys.');
END;
""", [kvp_list])
3. 若需返回结果,推荐使用 callfunc + OUT 参数
若 PL/SQL 需返回处理后的键列表或计数,应封装为函数并声明 OUT 参数:
CREATE OR REPLACE FUNCTION process_dict(
p_input DATA_TYPES.KEY_VALUE_LIST,
p_count OUT NUMBER
) RETURN SYS.DBMS_DEBUG_VC2COLL AS
l_keys SYS.DBMS_DEBUG_VC2COLL := SYS.DBMS_DEBUG_VC2COLL();
BEGIN
p_count := p_input.COUNT;
FOR i IN 1..p_input.COUNT LOOP
l_keys.EXTEND;
l_keys(l_keys.COUNT) := p_input(i).KEY;
END LOOP;
RETURN l_keys;
END;
/
Python 调用示例:
count = cur.var(int)
keys = cur.callfunc(
"process_dict",
oracledb.DB_TYPE_DBMS_DEBUG_VC2COLL,
[kvp_list, count]
)
print("Keys:", keys) # ['111', '222', '333']
print("Count:", count.getvalue()) # 3
? 关键注意事项:
- 必须预先在数据库中创建 OBJECT 或 RECORD 类型(key_value_pair),不能仅用匿名块内声明类型;
- gettype() 的参数名区分大小写,需与数据库中实际定义的全大写名称一致(如 "DATA_TYPES.KEY_VALUE_PAIR");
- INDEX BY VARCHAR2 类型无法作为绑定参数输入,所有输入集合必须基于 BINARY_INTEGER 索引;
- 生产环境建议将逻辑封装为存储过程/函数,便于复用、测试与权限管理。
通过上述方式,即可安全、高效地在 Python 与 PL/SQL 间传递字典语义的数据,并支持双向交互与复杂业务处理。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











