无法从使用Python游标的存储过程中返回结果

16 人关注

由于一些奇怪的原因,我无法从Python测试应用程序中的callproc调用中获得结果。MqSQL 5.2.47中的存储过程看起来像这样。

CREATE PROCEDURE `mytestdb`.`getperson` (IN personid INT)
BEGIN
   select person.person_id,
          person.person_fname,
          person.person_mi,
          person.person_lname,
          person.persongender_id,
          person.personjob_id
     from person
    where person.person_id = personid;

现在,使用PyCharm和Python 3.3,当调用这个存储过程时,我似乎无法检索到任何东西。这段代码让我得到了想要的结果。

import mysql.connector
cnx = mysql.connector.connect(user='root', host='127.0.0.1', database='mytestdb')
cnx._open_connection()
cursor = cnx.cursor()
cursor.execute("select * from person where person.person_id = 1")
people = cursor.fetchall()
for person in people:
    print(person)
cnx.close()

但是,这段代码是用cursor.fetchall()或cursor.fetchone()...

import mysql.connector
cnx = mysql.connector.connect(user='root', host='127.0.0.1', database='mytestdb')
cnx._open_connection()
cursor = cnx.cursor()
cursor.callproc("getperson", [1])
people = cursor.fetchall()
for person in people:
    print(person)
cnx.close()

...返回 "mysql.connector.errors.InterfaceError。没有可以获取的结果集。"使用cursor.execute()方法还有一个奇怪的行为,像这样...

import mysql.connector
cnx = mysql.connector.connect(user='root', host='127.0.0.1', database='mytestdb')
cnx._open_connection()
cursor = cnx.cursor()
cursor.execute("call getperson(1)")
people = cursor.fetchall()
for person in people:
    print(person)
cnx.close()

...因为它产生了 "mysql.connector.errors.InterfaceError。对有多个查询的语句使用cmd_query_iter",然后是 "mysql.connector.errors.InterfaceError。在执行多个语句时使用multi=True",尽管我只返回一个查询结果而不是多个结果集。MySQL Python连接器是否将对存储过程的执行调用视为一个双重查询?我怎样才能直接调用存储过程并得到我的结果?我真的不希望在我的代码中出现动态SQL。谢谢你的任何建议!

python
mysql
stored-procedures
gfish3000
gfish3000
发布于 2013-03-10
3 个回答
fuzic
fuzic
发布于 2013-03-10
已采纳
0 人赞同

你有没有试着挑选其中一个结果集?

for result in cursor.stored_results():
    people = result.fetchall()

可能是它为多个结果集分配,尽管你只有一个SELECTstmt。我知道在PHP的MySQLi存储过程中这样做是为了允许INOUT和OUT变量返回(同样,你没有,但也许它还是在分配)。

The complete code I'm using (which is working) is:

import mysql.connector
cnx = mysql.connector.connect(user='me',password='pw',host='localhost',database='mydb')
cnx._open_connection()
cursor = cnx.cursor()
cursor.callproc("getperson",[1])
for result in cursor.stored_results():
    people=result.fetchall()
for person in people:
    print person
cnx.close()
    
snakecharmerb
snakecharmerb
发布于 2013-03-10
0 人赞同

在调用 cursor.callproc 后获得存储过程的结果取决于这些因素。

  • whether the result of calling the procedure is assigned to an INOUT or OUT parameter
  • whether the result consists of a single row or a result set (or result sets)
  • the python package used to make the call
  • DBAPI spec cursor.callproc 有这样的说法。

    调用一个具有给定名称的存储数据库过程。参数序列必须包含该过程所期望的每个参数的一个条目。调用的结果将作为输入序列的修改副本返回。输入参数不动,输出和输入/输出参数用可能的新值替换。

    该过程也可以提供一个结果集作为输出。这必须通过标准的.fetch*()方法来实现。

    在实践中,使用 cursor.callproc 的返回值只能在存储过程返回单行时起作用,其列数与INOUT和OUT参数的数量相匹配,因此在如何处理结果方面存在一些差异。

    MySQL Connector , mysqlclient (MySQLdb) PyMySQL .

    单行结果,通过INOUT或OUT参数返回

  • MySQL Connector 作为 cursor.callproc 的返回值,返回输入序列的修改副本;该值是一个元组。

    params = [in_param, out_param1, out_param2]
    in_, out1, out2 = cursor.callproc("test_proc", params) 
    
  • mysqlclientPyMySQL require that the database is queried for the output parameters,和the results then fetched via the cursor; the value is a tuple of tuples. The parameter names to be queried are of the form '@_{procedure_name}_{params.index(param)}'

    cursor.callproc("test_proc", params)
    cursor.execute("""SELECT @_test_proc_0, @_test_proc_1""")
    result = cursor.fetchall()
    

    在一个结果集中有一条或多条记录,没有定义INOUT或OUT参数

  • MySQL Connector将结果通过游标的stored_results方法(cursor.stored_results不是DBAPI规范的一部分)。

    cursor.callproc("test_proc", params)
    results = [r.fetchall() for r in cursor.stored_results()]
    
  • mysqlclientPyMySQL通过游标的fetch*方法公开结果。

    cursor.callproc("test_proc", params)
    results = cursor.fetchall()
    

    多个结果集,没有定义INOUT或OUT参数

  • MySQL Connector将结果通过游标的stored_results method

    cursor.callproc("test_proc", params)
    results = [r.fetchall() for r in cursor.stored_results()]
    
  • mysqlclientPyMySQL要求通过游标获取每个结果集,而调用cursor.nextset来推进到下一个结果集。 注意,可能会返回一个额外的、空的结果集,这是调用过程的结果(这也会发生在前面的例子中,如果结果集是通过cursor.nextset检索的,而不是只调用cursor.fetchall一次)。

    cursor.callproc("test_proc", params)
    results = [cursor.fetchall()]
    while cursor.nextset():
        results.append(cursor.fetchall())
    
    $ mysql --version
    mysql  Ver 15.1 Distrib 10.1.41-MariaDB, for debian-linux-gnu (x86_64) using readline 5.2
    $ pip list | grep -i mysql
    mysql-connector-python 8.0.18 
    mysqlclient            1.4.6  
    PyMySQL                0.9.3  
    
  •