我想通过Python中的cx_oracle执行Oracle PL / SQL语句。代码如下所示:
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])
代码运行没有问题,但有没有机会将结果返回给Python?
答案 0 :(得分:11)
您可以将输入和输出变量绑定到块中。
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/hr@xe') 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))
脚本应该打印
Average of 23 and 55 is: 39.0
答案 1 :(得分:7)
您需要功能才能返回结果。匿名阻止不会。
您需要在数据库中create a function,例如:
create or replace function calculation return number is
c number := 0.2;
mn number := 1.5;
res number;
begin
return c + mn / 6.;
end;
/
然后使用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])
无法动态创建函数,但您的函数非常简单,您可以在select语句中执行此操作,并使用链接文档中所述的fetchall()
将结果返回给Python。 fetchall()
返回一个元组列表,所以如果你只是在一行和一列之后,你可以立即选择两者的0 th 索引。
>>> 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
>>>
您还可以使用绑定变量将变量传递到execute()
调用中,并在必要时在Python中实例化它们:
>>> 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 history@monitor>>
>>> result = cursor.fetchall()[0][0]
>>> result
0.45000000000000001
>>>
虽然在Python中完成所有这些操作可能更简单...但我认为您的实际情况更复杂?
答案 2 :(得分:0)
同意M. Wymann,我需要通过传递列表中的元素数来返回字符串。这是我的代码。
cursor = con.cursor()
for a,b,c in data:
statement='''DECLARE
t_name VARCHAR2 (50);
owner VARCHAR2 (50);
c_name VARCHAR2 (50);
O_type VARCHAR2 (50);
nullable VARCHAR2 (20);
BEGIN
SELECT t1.table_name,
t1.owner,
t1.column_name,
CASE
WHEN t1.data_type = 'NUMBER' AND t1.data_precision IS NULL
THEN
'NUMBER'
WHEN t1.data_type = 'DATE'
THEN
t1.data_type
WHEN REGEXP_REPLACE (t1.data_type, '(\d)|VAR', '') = 'CHAR'
THEN
t1.data_type || '(' || t1.DATA_LENGTH || ')'
WHEN t1.data_type = 'NUMBER'
AND t1.data_precision IS NOT NULL
AND t1.data_scale = 0
THEN
'NUMBER(' || t1.data_precision || ')'
WHEN t1.data_type = 'NUMBER'
AND t1.data_precision IS NOT NULL
AND t1.data_scale <> 0
THEN
'NUMBER(' || t1.data_precision || ',' || t1.data_scale || ')'
ELSE
'Not Handled'
END
"Oracle data type",
t1.nullable
INTO t_name,
owner,
c_name,
O_type,
nullable
FROM all_tab_columns t1
WHERE t1.table_name = :tname
AND t1.owner = :towner
AND t1.column_name = :tcolname;
:o_result :=
t_name
|| '|'
|| owner
|| '|'
|| c_name
|| '|'
|| O_type
|| '|'
|| nullable;
EXCEPTION
WHEN OTHERS
THEN
t_name := :tname;
c_name := 'NOT FOUND ';
owner := :towner;
O_type := 'NOT FOUND ';
nullable := 'NOT FOUND ';
:o_result :=
t_name
|| '|'
|| owner
|| '|'
|| c_name
|| '|'
|| O_type
|| '|'
|| nullable;
END;'''
o_result = cursor.var(cx_Oracle.STRING)`enter code here`
cursor.execute(statement, tname=a, towner=b, tcolname=c, o_result=o_result)
ObLst = o_result.getvalue().split('|')