【问题标题】:How to create Oracle user defined type in python cx_Oracle?如何在 python cx_Oracle 中创建 Oracle 用户定义类型?
【发布时间】:2017-01-25 12:38:18
【问题描述】:

Python 3.4.3、cx_Oracle 5.2 11g、Oracle DB 11.2.0.1

你好! 我想通过cx_Oracle从python获取数据泵作业的状态。

为了解决这个问题,我打电话给 Oracle dbms_datapump.get_status procedure:

DBMS_DATAPUMP.GET_STATUS( 
    handle IN NUMBER, 
    mask IN BINARY_INTEGER, 
    timeout IN NUMBER DEFAULT NULL, 
    job_state OUT VARCHAR2, 
    status OUT ku$_Status1120);

来自pythoncx_Oracle:

get_status_params = {'handle': job_handler,
                     'mask': 1,
                     'timeout': -1,
                     'job_state': job_state,
                     'status': ??????
                     }
cursor.callproc('dbms_datapump.get_status', keywordParameters=get_status_params)

Oracle 中的结构 ku$_Status1120:

CREATE TYPE sys.ku$_Status1120 IS OBJECT
(
    mask NUMBER, 
    wip ku$_LogEntry1010, 
    job_description ku$_JobDesc1020, 
    job_status ku$_JobStatus1120,
    error ku$_LogEntry1010 
)

job_status 以 oracle 为例:

CREATE TYPE sys.ku$_JobStatus1120 IS OBJECT
        (
            job_name        VARCHAR2(30),           
            operation       VARCHAR2(30),           
            job_mode        VARCHAR2(30),           
            bytes_processed NUMBER,                 
            total_bytes     NUMBER,                 
            percent_done    NUMBER,                 
            degree          NUMBER,                 
            error_count     NUMBER,                 
            state           VARCHAR2(30),           
            phase           NUMBER,                 
            restart_count   NUMBER,                 
            worker_status_list ku$_WorkerStatusList1120,                                                        
            files           ku$_DumpFileSet1010    
    )

如何在 Python 中重复 Oracle 类型 sys.ku$_Status1120?

【问题讨论】:

    标签: python cx-oracle


    【解决方案1】:

    我有一篇关于使用 cx_Oracle 实现 CRUD 功能的简短文章,在 insert segment 中,我使用以下内容来检索返回子句的值。

    new_id = cur.var(cx_Oracle.NUMBER)
    
    statement = 'insert into cx_people(name, age, notes) values (:1, :2, :3) returning id into :4'
    cur.execute(statement, ('Sandy', 31, 'I like horses', new_id))
    
    sandy_id = new_id.getvalue()
    

    对于单个值cur.var(cx_Oracle.NUMBER) 和数组cur.arrayvar(cx_Oracle.NUMBER,1000),我使用了相同的方法,但没有来自procudures 的参数;

    我没有专门使用cx_Oracle.OBJECT 类型,但我认为它的工作原理与其他类型类似。

    文档:cx_Oracle.OBJECT 和 Variable.getvalue

    试试这个

    job_status_out = cursor.var(cx_Oracle.OBJECT)
    
    get_status_params = {'handle': job_handler,
                         'mask': 1,
                         'timeout': -1,
                         'job_state': job_state,
                         'status': job_status_out
                         }
    cursor.callproc('dbms_datapump.get_status', keywordParameters=get_status_params)
    
    job_status = job_status_out.getvalue()
    

    最坏的情况,如果您在从 cur.var(cx_Oracle.NUMBER) 变量中获取值时遇到问题;您可以将dbms_datapump.get_status 包装在一个 pl/sql 函数中,该函数将值作为字符串返回并调用它。我知道这行得通。

    【讨论】:

    • 谢谢!我以前尝试使用 cursor.var(cx_Oracle.OBJECT) 。结果:job_status_out = cursor.var(cx_Oracle.OBJECT) TypeError:期望对象变量的类型名称。当我尝试其他解决方案时,我会发表评论。
    • cx_Oracle 开发版中增加了对绑定对象的支持。是的,您确实需要将 typename= 添加到上面提到的 cursor.var() 语句中。
    • 今天我尝试了 job_status = cursor.var(cx_Oracle.OBJECT, typename='ku$_Status1010')。 cursor.callproc('dbms_datapump.get_status', keywordParameters=get_status_params) cx_Oracle.NotSupportedError: Variable_TypeByValue(): unhandled data type cx_Oracle.OBJECTVAR
    【解决方案2】:

    这个答案是我给出的另一个答案的替代品。假设返回类型没有任何问题,另一个答案是更好的解决方案。

    此解决方案适用于任何可以对数据库进行 SQL 调用的语言。因此,即使您使用的应用程序语言不支持调用 PL/SQL 函数,您仍然可以获得所需的内容。

    如果您无法从 Oracle 数据库中获取某些内容,例如自定义类型或复杂数据集,您可以编写 pipelined table function。

    流水线表函数允许您在 pl/sql 端执行所需的任何操作,并以您选择的表格格式格式化/返回结果。

    然后在应用层,你可以从这个函数中选择,就像它是一个表格一样。

    我有 a post here 解释如何在 NodeJS 调用中使用它,但我已修改此示例以使用 Python。

    在 PL/SQL 中:

    (这不一定是在一个包里,这只是我使用的例子)

    /* defined in package spec */
    TYPE SearchType IS RECORD (
     member_id NUMBER,
     dino_name VARCHAR2(400) );
    
     TYPE SearchTypeSet IS TABLE OF SearchType;
    
    
    /* defined in package body */
    FUNCTION text_only(
      member_id_p IN INTEGER,
      search_string IN VARCHAR2)
      RETURN SearchTypeSet PIPELINED
    IS
     retSet SearchType;
    BEGIN
      FOR v_rec IN (
         SELECT member_id,
                dino_name
           FROM dd_members
          WHERE contains (about_yourself, 
                             search_string) > 0
            AND member_id != member_id_p) LOOP
                retSet.dino_name := v_rec.dino_name;
         retSet.member_id := v_rec.member_id;
         pipe ROW (retSet);
      END LOOP;
      RETURN;
    END;
    

    然后它是来自应用程序的简单选择语句。

    在 Python 中:

    cur = con.cursor()
    statement = 'SELECT member_id, dino_name FROM TABLE(text_only(:memberId, :keywords)) ORDER BY dino_name'
    cur.execute(statement, (35, 'Rocks'))
    res = cur.fetchall()
    print (res)
    

    对于您的具体问题,您可以将对 dbms_datapump.get_status 的调用包装在流水线函数中,而不是在示例中使用 select。

    【讨论】:

      猜你喜欢
      • 2021-11-04
      • 2010-11-01
      • 2021-11-21
      • 1970-01-01
      • 1970-01-01
      • 2019-08-04
      • 2012-01-08
      相关资源
      最近更新 更多