如何将 python 数组传递给 oracle 存储过程?
How to pass a python array to an oracle stored procedure?
我有问题。当我传递 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: wrong number or types of arguments in call to '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
不是整数,但也没有其他数字类型。提前致谢。
当您查看 cx_Oracle
文档时,它说您可以像这样创建数组;
Cursor.arrayvar(dataType, value[, size])
Create an array variable associated with the cursor of the given type and size and return a variable object (Variable Objects). The value is either an integer specifying the number of elements to allocate or it is a list and the number of elements allocated is drawn from the size of the list. If the value is a list, the variable is also set with the contents of the list. If the size is not specified and the type is a string or binary, 4000 bytes (maximum allowable by Oracle) is allocated. This is needed for passing arrays to PL/SQL (in cases where the list might be empty and the type cannot be determined automatically) or returning arrays from 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())
尝试在过程的参数中使用 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;
希望对你有所帮助
我有问题。当我传递 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: wrong number or types of arguments in call to '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
不是整数,但也没有其他数字类型。提前致谢。
当您查看 cx_Oracle
文档时,它说您可以像这样创建数组;
Cursor.arrayvar(dataType, value[, size])
Create an array variable associated with the cursor of the given type and size and return a variable object (Variable Objects). The value is either an integer specifying the number of elements to allocate or it is a list and the number of elements allocated is drawn from the size of the list. If the value is a list, the variable is also set with the contents of the list. If the size is not specified and the type is a string or binary, 4000 bytes (maximum allowable by Oracle) is allocated. This is needed for passing arrays to PL/SQL (in cases where the list might be empty and the type cannot be determined automatically) or returning arrays from 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())
尝试在过程的参数中使用 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;
希望对你有所帮助