首页 > 解决方案 > Python:遍历用户定义的 Oracle PL/SQL 类型

问题描述

我正在尝试使用完全通过 api 访问的 Oracle 系统(不能直接访问表)。Oracle 端是这样构建的:

create or replace package Chb_pythontest
  authid definer
as
  type Python_test_rec is record
  (
    Io_var    number,
    Var1      number
  );
  type Python_test_tab is table of Python_test_rec
    index by binary_integer;

  procedure Test_output_collection (Io_id            in     number,
                                    Out_test_table      out Python_test_tab);
end Chb_pythontest;

使用此 Python 代码可以正常工作:

conn = co.connect(CONN_STR)
with conn.cursor() as cursor:
    collection_type = conn.gettype("CHB_PYTHONTEST.PYTHON_TEST_TAB")
    collection = collection_type.newobject()
    cursor.callproc("Chb_pythontest.Test_output_collection", [1, collection])          

    ix = collection.first()
    while ix is not None:
        record = collection.getelement(ix)
        print("Rownum: ", ix)
        print(">> IO_VAR -> ", record.IO_VAR)
        print(">> VAR1 -> ", record.VAR1)
        ix = collection.next(ix)

它显然知道记录元素中有一个 IO_VAR 和 VAR1 ,但这只是因为我明确地引用了它们。我发现没有办法动态地迭代它。将其转换为列表或字典将是理想的。

我需要创建自己的迭代器还是可以使用 cx_oracle 或类似工具来完成?

标签: pythonoraclecx-oracle

解决方案


您目前可以迭代 cx_Oracle 对象属性,但它是一个私有方法,所以它有点小技巧。如果您反省一下cx_Oracle.Objectwith:

dir(collection.getelement(1))

您可以看到所有可用的方法。我们在这里感兴趣的是__getattribute__()- 传入一个属性名称,您可以动态获取值,而不是使用object.ATTRIBUTENAME.

我们还需要对象类型(在本例中为 IO_VAR 和 VAR1)中的属性名称(“列”)。你可以从collection_type.element_type.attributes.

将所有这些放在一起,我们可以在打印循环中运行它,就像您的代码一样:

for r in range(1,collection.size()):
    record = collection.getelement(r)
    print(f"Rownum: {r}")
    for k in collection_type.element_type.attributes:
        print(f">> {k.name} -> {record.__getattribute__(k.name)}")

或者将整个集合变成一个字典列表(具有相当繁琐的列表/字典理解)。

pycollection = [{k.name: collection.aslist()[r].__getattribute__(k.name) for k in collection_type.element_type.attributes} for r in range(collection.size())]
print(pycollection)

大集合可能会有点慢;可能有更好的选择,我不知道。


推荐阅读