如何在python cx_Oracle中创建Oracle用户定义的类型?

时间:2015-12-24 08:12:38

标签: python cx-oracle

Python 3.4.3cx_Oracle 5.2 11gOracle DB 11.2.0.1

您好! 我想从python到cx_Oracle获取datapump作业的状态。

要解决此问题,我致电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);

来自python cx_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

2 个答案:

答案 0 :(得分:2)

我简要介绍了如何使用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)的处理的参数;

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

文档:cx_Oracle.OBJECTVariable.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函数中,该函数将值作为字符串返回并调用它。我知道这很有效。

答案 1 :(得分:1)

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

此解决方案适用于任何可以对数据库进行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)

对于您的特定问题,您可以将调用包含在流水线函数中,而不是使用示例中的select。