8

我想通过 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?

4

3 回答 3

14

您可以像这样将输入和输出变量绑定到块。

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))
  1. 对输入和输出变量使用 PL/SQL 块中的常规绑定表示法 (:)
  2. 对于输出变量,从光标(适当的类型)获取变量
  3. 在执行调用中,为输入变量和 (2) 中的变量提供值作为参数
  4. 从输出变量中检索值

脚本应该打印

Average of 23 and 55 is: 39.0
于 2016-08-26T05:59:32.627 回答
7

您需要一个函数来返回结果。匿名块不会。

您需要在数据库中创建一个函数,例如:

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

然后更改您的 Python 代码以调用该函数,使用,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索引。

>>> 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 中完成所有这些操作可能更简单......我假设您的实际情况更复杂?

于 2013-08-16T08:58:09.730 回答
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('|')
于 2019-05-16T05:55:28.743 回答