16

奇妙な理由で、Pythonテストアプリでcallproc呼び出しの結果を取得できません。MqSQL5.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;
END

さて、Python 3.3でPyCharmを使用すると、このストアドプロシージャを呼び出すときに何も取得できないようです。このコードは私に望ましい結果をもたらします:

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を使用する」が生成されるため複数の結果セットではなく、1つのクエリ結果のみを返します。MySQL Pythonコネクタは、ストアドプロシージャの実行呼び出しを二重クエリとして扱いますか?ストアドプロシージャを呼び出して結果を取り戻すにはどうすればよいですか?コードに動的SQLを含めたくありません。アドバイスをありがとう!

4

3 に答える 3

19

結果セットの1つを選んでみましたか?

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

SELECTstmtが1つしかない場合でも、複数の結果セットに割り当てられている可能性があります。PHPのMySQLiストアドプロシージャでは、これを実行してINOUT変数とOUT変数を返すことができます(これも、どちらもありませんが、とにかく割り当てられている可能性があります)。

私が使用している(機能している)完全なコードは次のとおりです。

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()
于 2013-03-10T08:36:52.640 に答える
8

呼び出し後にストアドプロシージャの結果を取得するcursor.callprocかどうかは、次の要因によって異なります。

  • プロシージャーを呼び出した結果がINOUTパラメーターに割り当てられているかOUTパラメーターに割り当てられているか
  • 結果が単一の行で構成されているか、結果セット(または結果セット)で構成されているか
  • 呼び出しに使用されるpythonパッケージ

DBAPI仕様には、次のように書かれていcursor.callprocます。

指定された名前でストアドデータベースプロシージャを呼び出します。パラメータのシーケンスには、プロシージャが予期する引数ごとに1つのエントリが含まれている必要があります。呼び出しの結果は、入力シーケンスの変更されたコピーとして返されます。入力パラメーターは変更されず、出力パラメーターと入出力パラメーターは新しい値に置き換えられます。

この手順では、結果セットを出力として提供することもできます。次に、これを標準の.fetch *()メソッドで使用できるようにする必要があります。

実際には、の戻り値の使用はcursor.callproc、プロシージャが単一の行を返し、列の数がINOUTおよびOUTパラメータの数と一致する場合にのみ機能するため、結果の処理方法には多少のばらつきがあります。


これらのケースが主要なMySQLPythonコネクタパッケージ(MySQL Connectormysqlclient(MySQLdb)、およびPyMySQL )によってどのように処理されるかを次に示します。

INOUTまたはOUTパラメーターを介して返される単一行の結果

  • MySQL Connectorcursor.callprocは、入力シーケンスの変更されたコピーを;の戻り値として返します。値はタプルです。

    params = [in_param, out_param1, out_param2]
    in_, out1, out2 = cursor.callproc("test_proc", params) 
    
  • mysqlclientPyMySQLでは、データベースで出力パラメーターを照会し、カーソルを介して結果をフェッチする必要があります。値はタプルのタプルです。照会するパラメーター名は、次の形式です。'@_{procedure_name}_{params.index(param)}'

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

単一の結果セット内の1つ以上の行、INOUTまたはOUTパラメーターが定義されていない

  • MySQL Connectorは、カーソルのstored_resultsメソッドを介して結果を公開します(cursor.stored_resultsDBAPI仕様の一部ではありません)

    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メソッドを介して結果を公開します

    cursor.callproc("test_proc", params)
    results = [r.fetchall() for r in cursor.stored_results()]
    
  • mysqlclientPyMySQLでは、 cursor.nextsetを呼び出して次の結果セットに進むときに、各結果セットをカーソル経由でフェッチする必要があります。プロシージャを呼び出した結果として、余分な空の結果セットが返される場合があることに注意してください(これは、結果セットが1回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  
于 2019-12-31T15:53:26.857 に答える
0

この方法で試してみませんか

cursor.callproc("getperson", ['1'])
于 2013-03-10T08:22:58.180 に答える