如何将python数组传递给oracle存储过程?

时间:2015-11-04 20:51:12

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

我有问题。当我传递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不是整数但是没有其他数字类型。提前谢谢。

2 个答案:

答案 0 :(得分:2)

尝试在过程的参数中使用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;

我希望它可以帮到你。

答案 1 :(得分:1)

当您查看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())