当前位置: 首页 > 知识库问答 >
问题:

cx_Oracle如何将复合/复杂数组传递给PLSQL过程?

翟宏放
2023-03-14

根据本指南,我能够将简单数据类型(如cx_Oracle.NUMBER)的关联数组传递给PL/SQL过程。

CREATE OR REPLACE PACKAGE test
IS
    TYPE t_ids IS TABLE OF NUMBER INDEX BY PLS_INTEGER;
    PROCEDURE foo(p_ids_i IN t_ids);
END;
/

可以这么说:

ids = cursor.arrayvar(cx_Oracle.NUMBER, [1,2,3])
cursor.callproc('test.foo', [ids])

但是,我想调用下面的过程foo,取而代之的是复杂类型。

CREATE OR REPLACE PACKAGE test
IS
    TYPE r_foo IS RECORD (id NUMBER, name VARCHAR2(10));
    TYPE t_complex IS TABLE OF r_foo INDEX BY PLS_INTEGER;
    PROCEDURE foo(p_ids_i IN t_complex);
END;
/

我尝试过各种方法,比如:

# Raises NotSupportedError: Variable_TypeByPythonType(): unhandled data type
foos = cursor.arrayvar((cx_Oracle.NUMBER, cx_Oracle.STRING), [(1, 'foo'), (2, 'bar')])

# Raises NotSupportedError: Variable_MakeArray(): type does not support arrays
foos = cur.arrayvar(cx_Oracle.OBJECT, [(1, 'foo'), (2, 'bar')])

以下是失败的:

# Raises DatabaseError: ORA-04043: object TEST.R_FOO does not exist
record_type = conn.gettype('TEST.R_FOO')

看起来您可以在包之外创建一个类型并引用它。

CREATE TYPE t_foo IS TABLE OF NUMBER; -- Not an Associative Array

引用它:

t = conn.gettype('T_FOO')

但是,您不允许在包之外创建关联数组的RECORD。我可以用对象替换RECORD,但是我想不出任何东西可以替换关联数组,这是cx_Oracle可以传入或传出的唯一集合类型。

完整代码:

PL/SQL:


-- returns 12.1.0.2.0
SELECT VERSION FROM v$instance;

CREATE OR REPLACE PACKAGE test
IS
    TYPE r_foo IS RECORD (id NUMBER, name VARCHAR2(10));
    TYPE t_complex IS TABLE OF r_foo INDEX BY PLS_INTEGER;
    PROCEDURE foo(p_ids_i IN t_complex);
END;
/

CREATE OR REPLACE PACKAGE BODY test
IS
    PROCEDURE foo(p_ids_i IN t_complex)
    IS
    BEGIN
        FOR i IN p_ids_i.FIRST .. p_ids_i.LAST LOOP
            DBMS_OUTPUT.PUT_LINE(p_ids_i(i).id || ' ' || p_ids_i(i).name);
        END LOOP;
    END;
END;
/

-- The following works as expected.
DECLARE
    l_complex test.t_complex;
BEGIN
    l_complex(1).id := 1;
    l_complex(1).name := 'Matthew';

    l_complex(2).id := 2;
    l_complex(2).name := 'Moisen';

    test.foo(l_complex);
END;

蟒蛇:

import cx_Oracle

print cx_Oracle.version  # 5.3
print cx_Oracle.clientversion() # (12, 1, 0, 2, 0)

conn = cx_Oracle.connect('username/password@sid')
cur = conn.cursor()

result = cur.execute("SELECT * FROM user_source WHERE name = 'TEST' and type = 'PACKAGE'")

# This prints the package spec successfully
for row in result:
    print row

# Raises DatabaseError: ORA-04043: object TEST.R_FOO does not exist
conn.gettype('TEST.R_FOO')

# Raises DatabaseError: ORA-04043: object TEST.T_COMPLEX does not exist
conn.gettype('TEST.T_COMPLEX')

# This raises the appropriate exception saying I called the procedure
# incorrectly, demonstrating that I have access to it.
cur.callproc('TEST.FOO', [])

在将$Oracle_HOME等设置为我的12c客户端并重新安装cx_Oracle之后,我可以做得更进一步,但仍然在append操作中出错。

import cx_Oracle

conn = cx_Oracle.connect('username/password@sid')

# This no longer raises an error
recordTypeObj = conn.gettype('TEST.R_FOO')
tableTypeObj = conn.gettype('TEST.T_COMPLEX')
rec = recordTypeObj.newobject()
tab = tableTypeObj.newobject()

# This works fine
rec.ID = 1
rec.NAME = "foo"

# This fails with 
# cx_Oracle.NotSupportedError: Object_ConvertFromPython(): unhandled data type 250
tab.append(rec)

共有1个答案

闻人升
2023-03-14

cx_Oracle5.3及更高版本支持这一点。您必须使用支持这种事情的“对象”语法。

import cx_Oracle

conn = cx_Oracle.Connection("cx_Oracle/dev@localhost/orcl")
recordTypeObj = conn.gettype("TEST.R_FOO")
tableTypeObj = conn.gettype("TEST.T_COMPLEX")

tab = tableTypeObj.newobject()

rec = recordTypeObj.newobject()
rec.ID = 1
rec.NAME = "foo"
tab.append(rec)

rec = recordTypeObj.newobject()
rec.ID = 2
rec.NAME = "bar"
tab.append(rec)

cursor = conn.cursor()
cursor.callproc("test.foo", [tab])
 类似资料:
  • 问题内容: 我在形成文字时可能做错了。假设我有一个简单的存储过程,如下所示: 的定义为: 执行这样的查询: 产生以下结果集: 代替: 我的文字是否有问题,还是应该以其他方式访问该字段?感谢您的任何建议。 问题答案: 指定输入的方式看起来不错,因为使用行和数组构造器语法可以观察到相同的行为: 和: 产生: 如果添加: 在循环内部,输出为: 表明您实际上正在获取一个元组,其中“ message”是您期

  • 问题内容: 我有以下指令: 这是对象结构: 我希望它根据对象内部的数据生成一个链接。 不幸的是,由于我无法访问该对象的任何内部值,因此它不起作用,但是如果我将其传递给一个简单的数据结构,例如: 我可以使用访问它。 这是我的指令代码: 谢谢 问题答案: 在Angularjs官方网站上阅读说明: @或@attr- 将本地范围属性绑定到DOM属性的值。由于DOM属性是字符串,因此结果始终是字符串。如果未

  • 问题内容: 这个问题已经在这里有了答案 : PHP-将PDO与IN子句数组一起使用 (8个答案) 5年前关闭。 我目前有一个值数组(business_id) 可以说 使用这些值中的每一个从数据库中获取每个business_id的关联行信息的最佳方法是什么。 可以一一查询是我的问题。显然,你可以做 问题答案: 通常的SQL注入警告仍然适用,您可能需要先循环遍历id以进行验证或转义。另外,如果希望使用

  • 问题内容: 我已经成功地建立了一个快速测试,以创建一个“类似REST的”服务,该服务返回序列化为JSON的对象,并且这非常容易且快速(基于本文)。 但是,虽然返回桃子一样的JSON格式的对象很容易,但我还没有看到任何处理非原语输入参数的示例。如何传递复杂的对象作为参数?我正在使用Apache CXF,但也欢迎使用其他框架(例如杰克逊)的示例:) 客户端可能类似于构建javascript对象,将其传

  • 问题内容: 这个问题已经在这里有了答案 : 如何将变量和数据从PHP传递到JavaScript? (20个答案) 5年前关闭。 我正在尝试将PHP数组变量转换为JavaScript变量。 这是我的代码: 我无法获得PHP数组的价值。 我该如何解决这个问题? 问题答案: 在下面的示例中,您具有一个PHP数组,然后首先通过一个PHP数组创建一个JavaScript数组:

  • 问题内容: 我想将两个数组形式的java发送到oracle存储过程。第一个数组是字符串数组,第二个是字符数组,我怎样才能做到这一点? 问题答案: 这是一个如何做的例子。 以下脚本在数据库中设置表,类型和存储过程。该过程采用数组类型的参数,并将数组的每一行插入表中: 然后,Java代码演示如何将数组传递到此存储过程中: 如果先运行SQL脚本,然后运行Java类,然后查询表,则应该发现所有数据都已插入