【问题标题】:How to pass a python array to an oracle stored procedure?如何将python数组传递给oracle存储过程?
【发布时间】:2016-12-22 01:17:16
【问题描述】:

我有问题。当我传递一个 Python 数组时:

self.notPermited = [2,3]

这是我的程序

def select_ids_entre_amistades(self,cod_us,ids_not):
    lista = []
    try:
        cursor = self.__cursor.var(cx_Oracle.CURSOR)
        print ids_not
        data = self.__cursor.arrayvar(cx_Oracle.NUMBER, ids_not)
        print data
        l_query = self.__cursor.callproc("SCHEMA.PROC_SELECT_IDS_ENT_AMISTADES", [cursor,cod_us,data])
        lista = l_query[0]
        return lista
    except cx_Oracle.DatabaseError as ex:
        error, = ex.args
        print(error.message)
        return lista

问题是当我使用这个调用该过程时:

self.select_ids_entre_amistades(int_id,self.notPermited)

我在控制台中看到以下消息:

PLS-00306:调用“PROC”时参数的数量或类型错误

在数据库中我这样创建数组对象:

CREATE TYPE SCHEMA.ARRAY_ID_FRIENDS AS TABLE OF INT;

Oracle 存储过程是这样开始的:

CREATE OR REPLACE PROCEDURE FACEBOOK.PROC_SELECT_IDS_ENT_AMISTADES
(CONSULTA OUT SYS_REFCURSOR,COD_US IN INT, IDS_FRIEND IN SCHEMA.ARRAY_ID_FRIENDS)

我不知道问题出在哪里,我相信cx_Oracle.NUMBER 不是整数,但没有其他数字类型。提前致谢。

【问题讨论】:

    标签: python-2.7 stored-procedures cx-oracle


    【解决方案1】:

    尝试在过程的参数中使用 plsql 数组,然后传递 sql 数组的内容。最后一个将用于将sql语句插入到程序中。它解决了我使用 oracle 数据库 11g 的问题,因为在 12g 中您不需要将内容传递给 sql 数组。这可能是代码:

    def select_ids_entre_amistades(self,cod_us,ids_not):
        lista = []
        try:
            cursor = self.__cursor.var(cx_Oracle.CURSOR)
            varray = self.__cursor.arrayvar(cx_Oracle.NUMBER,ids_not)
            l_query = self.__cursor.callproc("PACKFACE.P_SELECT_IDBFRIENDS", [cursor, cod_us, varray])
            lista = l_query[0]
            return lista
        except cx_Oracle.DatabaseError as ex:
            error, = ex.args
            self.guardar_errores('dato ' + str(error.message))
            return lista
    

    还有这样的存储过程: 首先你创建一个类型

    CREATE OR REPLACE TYPE LIST_IDS AS TABLE OF INT;
    

    第二次创建你的包

    CREATE OR REPLACE PACKAGE PACKFACE IS
    TYPE LISTADO_IDS IS TABLE OF INT INDEX BY PLS_INTEGER;
    PROCEDURE P_SELECT_IDBFRIENDS (CONSULTA OUT SYS_REFCURSOR,COD_US IN INT,IDS_NOT IN LISTADO_IDS);
    END;
    

    最后创建包体

    CREATE OR REPLACE PACKAGE BODY PACKFACE IS
        PROCEDURE P_SELECT_IDBFRIENDS (CONSULTA OUT SYS_REFCURSOR,COD_US IN INT, IDS_NOT IN LISTADO_IDS) 
        IS
            num_array LIST_IDS;
        BEGIN
            num_array:=LIST_IDS();
            for i in 1 .. IDS_NOT.count
            loop
                num_array.extend(1);
                num_array(i) := IDS_NOT(i);
            end loop; 
            OPEN CONSULTA FOR 
            SELECT * FROM T_TABLE WHERE ID IN (SELECT COLUMN_VALUE FROM TABLE(num_array));
        END;
    END;
    

    希望对你有帮助。

    【讨论】:

      【解决方案2】:

      当您查看cx_Oracle 文档时,它说您可以像这样创建数组;

       Cursor.arrayvar(dataType, value[, size])
      

      创建一个与给定类型和大小的游标关联的数组变量,并返回一个变量对象(Variable Objects)。该值可以是一个整数,指定要分配的元素数量,或者它是一个列表,分配的元素数量是从列表的大小中得出的。如果值是一个列表,该变量也被设置为列表的内容。如果未指定大小且类型为字符串或二进制,则分配 4000 字节(Oracle 允许的最大值)。这是将数组传递给 PL/SQL(在列表可能为空且无法自动确定类型的情况下)或从 PL/SQL 返回数组时所必需的。

      只要数组类型与您的PL/SQL 过程的参数兼容,您就可以传递您的数组。这是一个创建数组的简单示例。

      >>> myarray=cursor.arrayvar(cx_Oracle.NUMBER,range(0,10))
      >>> myarray
      <cx_Oracle.NUMBER with value [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]>
      

      这里有一个link(属于2005似乎已经过时,不确定)展示了如何在PL/SQL边创建数组。

      编辑:

      我在下面添加了一个完整的示例,展示了如何传递arrayvar 和其他变量类型。我使用 Oracle 10g 和 Python 2.7 测试了代码。我希望这会有所帮助。

      from __future__ import print_function
      import cx_Oracle as cxo
      
      conn = cxo.connect("<YOUR TNS STRING>")
      
      cursor = conn.cursor()
      ref_cursor = cursor.var(cxo.CURSOR)
      cod_us = cursor.var(cxo.NUMBER, 10)
      ids_friend = cursor.arrayvar(cxo.NUMBER, range(0, 10))
      ids_friend_sum = cursor.var(cxo.NUMBER)
      cursor.execute('''
      DECLARE
      
      TYPE REF_CURSOR IS REF CURSOR;
      TYPE ARRAY_ID_FRIENDS IS TABLE OF INT INDEX BY BINARY_INTEGER;
      
          FUNCTION test(CONSULTA OUT REF_CURSOR,
                         COD_US IN INT,
                         IDS_FRIEND IN ARRAY_ID_FRIENDS) RETURN NUMBER
          IS
              sum_ NUMBER:=0;
          BEGIN
              OPEN CONSULTA FOR SELECT 1 FROM DUAL UNION SELECT 2 FROM DUAL;
      
              FOR i in IDS_FRIEND.FIRST..IDS_FRIEND.LAST LOOP
                  sum_:=sum_+IDS_FRIEND(i);
              END LOOP;
              RETURN sum_;
          END;
      
      BEGIN
          :ids_friend_sum:=test(:ref_cursor,:cod_us,:ids_friend);
      END;
      
      
      ''', {"ref_cursor": ref_cursor, "cod_us": cod_us, "ids_friend": ids_friend,
            "ids_friend_sum": ids_friend_sum})
      
      print("ref cursor=", end=" ")
      for rec in ref_cursor.getvalue():
          print(rec, end="\t")
      print("\nids_friend_sum=", ids_friend_sum.getvalue())
      

      【讨论】:

      • 如果我传递一个变量而不是 range(0,10),我该如何更改?请帮帮我。
      • 你可以创建列表,arrayvar cursor.arrayvar(cx_Oracle.[DataType], [...]) e.g. cursor.arrayvar(cx_Oracle.DATETIME, [dt1, dt2])
      • 是的,我这样做了: varray=cursor.arrayvar(cx_Oracle.NUMBER, ids_not) 之后我调用 cursor.callproc("PROC_SELECT_IDS_", [cursor,cod_us,varray]),ids_not 有[10.0,20.0],也是 varray,但错误继续 PLS-00306: number o types of arguments PROC_SELECT_IDS_
      • 我不确定,但您可以像 cursor=connection.cursor() 一样创建光标,而不是 cursor=self.__cursor.var(cx_Oracle.CURSOR)。请试试这个。
      • 我修改了没有 varray 的代码,它运行正常。问题出在可变数组中。我通过 binary_integer 阅读了有关索引的信息,但我不明白如何声明。我这样做了:创建类型 ARRAY_ID_FRIENDS 作为数字表;
      猜你喜欢
      • 2014-02-26
      • 2012-02-10
      • 1970-01-01
      • 2011-10-23
      • 1970-01-01
      • 2011-03-03
      • 2012-03-30
      • 2016-02-02
      • 1970-01-01
      相关资源
      最近更新 更多