2013-08-16 15 views
5

Desidero eseguire un'istruzione Oracle PL/SQL tramite cx_oracle in Python. Codice assomiglia a questo:Restituisce variabile da cx_Oracle Chiamata PL/SQL in Python

db = cx_Oracle.connect(user, pass, dsn_tns) 
cursor = db.cursor() 

... 

sel = """ 
DECLARE 
    c NUMBER := 0.2; 
    mn NUMBER := 1.5; 
    res NUMBER; 
BEGIN 
    res := c+mn/6.; 
END; 
""" 
try: 
    cursor.execute(sel) 
    print "PL/SQL successful executed ..." 
except cx_Oracle.DatabaseError as e: 
    err, = e.args 
    print "\n".join([str(err.code),err.message,err.context]) 

Il codice è in esecuzione senza problemi, ma c'è qualche possibilità di ottenere il risultato di nuovo a Python?

risposta

7

È necessario un per restituire un risultato. Un blocco anonimo non lo farà.

È necessario create a function nel database, per esempio:

create or replace function calculation return number is 
    c number := 0.2; 
    mn number := 1.5; 
    res number; 
begin 
    return c + mn/6.; 
end; 
/

quindi modificare il codice Python per chiamare la funzione, utilizzando, callfunc()

db = cx_Oracle.connect(user, pass, dsn_tns) 
cursor = db.cursor() 

try: 
    result = cursor.callfunc('calculation', float) 
    print result 
except cx_Oracle.DatabaseError as e: 
    err, = e.args 
    print "\n".join([str(err.code),err.message,err.context]) 

Non è possibile creare una funzione al volo ma la tua funzione è abbastanza semplice da poter essere eseguita in una istruzione select e utilizzare fetchall() come descritto nella documentazione collegata per restituire il risultato a Python. fetchall() restituisce un elenco di tuple, quindi se si è solo dopo una riga e una colonna è possibile selezionare immediatamente l'indice 0 th di entrambi.

>>> import cx_Oracle 
>>> db = cx_Oracle.connect('****','****','****') 
>>> cursor = db.cursor() 
>>> SQL = """select 0.2 + 1.5/6. from dual""" 
>>> try: 
...  cursor.execute(SQL) 
...  result = cursor.fetchall()[0][0] 
... except cx_Oracle.DataBaseError, e: 
...  pass 
... 
<__builtin__.OracleCursor on <cx_Oracle.Connection to ****@****>> 
>>> result 
0.45000000000000001 
>>> 

È inoltre possibile passare le variabili nelle vostre execute() chiamata variabili utilizzando bind e quindi li un'istanza in Python, se necessario:

>>> c = 0.2 
>>> mn = 1.5 
>>> SQL = """select :c + :mn/6. from dual""" 
>>> bind_vars = { 'c' : c, 'mn' : mn } 
>>> cursor.execute(SQL, bind_vars) 
<__builtin__.OracleCursor on <cx_Oracle.Connection to [email protected]>> 
>>> result = cursor.fetchall()[0][0] 
>>> result 
0.45000000000000001 
>>> 

Anche se potrebbe essere più semplice di fare tutto questo in Python ... Suppongo che la tua situazione attuale sia più complicata?

+0

E 'possibile creare la funzione temporaneamente "al volo" in modo che la base di dati dimenticare dopo aver chiamato db.Close()? –

+0

Si prega di consultare il mio aggiornamento @ user1946052. – Ben

+0

La tabella "duale" ha qualche significato o è una sorta di segnaposto? –

8

È possibile associare le variabili di input e output al blocco in questo modo.

import cx_Oracle 

SQL_BLOCK = ''' 
DECLARE 
    v_first NUMBER; 
    v_second NUMBER; 
    v_result NUMBER; 
BEGIN 
    v_first := :i_first; -- (1) 
    v_second := :i_second; -- (1) 

    v_result := (v_first + v_second)/2; 

    :o_result := v_result; -- (1) 
END; 
''' 

with cx_Oracle.connect('hr/[email protected]') as db: 
    cur = db.cursor() 
    o_result = cur.var(cx_Oracle.NUMBER) # (2) 
    cur.execute(SQL_BLOCK, i_first=23, i_second=55, o_result=o_result) # (3) 
    res = o_result.getvalue() # (4) 
    print('Average of 23 and 55 is: {}'.format(res)) 
  1. usando la notazione regolare bind (:) nella/blocco SQL PL per entrambe le variabili di ingresso e uscita
  2. Per variabili di uscita ottenere una variabile dal cursore (del tipo appropriato)
  3. nella esecuzione chiamare fornire i valori per le variabili di ingresso e la variabile da (2) come parametri
  4. recuperare il valore delle variabili di uscita

Lo script dovrebbe stampare

Average of 23 and 55 is: 39.0 
Problemi correlati