web-dev-qa-db-ja.com

Python pyodbcとMS-Accessを使用したcursor.executeで実際のSQLクエリを表示する方法

Python(MS-Accessベースのpyodbcを使用))で次のコードを使用します。

cursor.execute("select a from tbl where b=? and c=?", (x, y))

Okですが、メンテナンスのために、データベースに送信される完全かつ正確なSQL文字列を知る必要があります。
それは可能ですか?

42
philnext

答えはいいえだ。私の質問はプロジェクトのホームGoogleコード(およびGoogleグループ)に投稿します。答えは次のとおりです。

L ... @ deller.id.auによるissue 163のコメント#1:cursor.mogrify return query string http://code.google.com/p/pyodbc/issues/detail?id=16

ここで参照できるのは、レポーターが参照している「mogrify」カーソルメソッドのpyscopgドキュメントへのリンクです。 http://initd.org/psycopg/docs/cursor.html#cursor.mogrify

pyodbcはこのようなSQLの変換を実行しません。パラメーター化されたSQLをそのままODBCドライバーにそのまま渡します。関係する唯一の処理はPython ODBC API。

SQLの一部の変換は、サーバーに送信される前にODBCドライバーで実行される場合があります(Microsoft SQL Native Clientはこれを行います)が、これらの変換はpyodbcから隠されます。

したがって、pyodbcでmogrify関数を提供することは現実的ではないと思います。

6
philnext

ドライバーによって異なります。以下に2つの例を示します。

import MySQLdb
mc = MySQLdb.connect()
r = mc.cursor()
r.execute('select %s, %s', ("foo", 2))
r._executed
"select 'foo', 2"

import psycopg2
pc = psycopg2.connect()
r = pc.cursor()
r.execute('select %s, %s', ('foo', 2))
r.query
"select E'foo', 2"
42
samplebias

_print cursor._last_executed_を使用して、最後に実行されたクエリを取得できます。

this を読んで、print cursor.mogrify(query,list)を使用して、実行前または実行後に完全なクエリを表示することもできます。

8
joseph

デバッグ目的のために、私は単に置換するチェック関数を作成しましたか?クエリ値で...それは高度な技術ではありません:)が、それは動作します! :D

def check_sql_string(sql, values):
    unique = "%PARAMETER%"
    sql = sql.replace("?", unique)
    for v in values: sql = sql.replace(unique, repr(v), 1)
    return sql

query="""SELECT * FROM dbo.MA_ItemsMonthlyBalances
                   WHERE Item = ? AND Storage = ? AND FiscalYear = ? AND BalanceYear = ? AND Balance = ? AND BalanceMonth = ?"""
values = (1,2,"asdasd",12331, "aas)",1)

print(check_sql_string(query,values))

結果:

SELECT * FROM dbo.MA_ItemsMonthlyBalances WHERE Item = 1 AND St​​orage = 2 AND FiscalYear = 'asdasd' AND BalanceYear = 12331 AND Balance = 'aas')AND BalanceMonth = 1

これにより、ログを記録したり、必要なことを実行したりできます。

rowcount = self.cur.execute(query,values).rowcount
logger.info(check_sql_string(query,values))

必要に応じて、関数にキャッチする例外を追加します。

3
piertoni

使用するドライバーに応じて、これは可能または不可能です。一部のデータベースでは、パラメーター(?s)は、user589983の答えが示すように単純に置き換えられます(ただし、ドライバーは、実行可能なステートメントを生成するために、文字列を引用したり、それらの文字列内の引用符をエスケープしたりする必要があります)。

他のドライバーは、データベースにステートメントをコンパイル(「準備」)するように要求し、指定された値を使用して準備済みステートメントを実行するように要求します。このようにして、準備済みまたはパラメーター化されたステートメントを使用すると、SQLインジェクションを回避できます-ステートメントの実行時に、データベースは、実行するSQLの一部と、使用する値の一部を「認識」しますその声明。

PyODBCドキュメンテーション をざっと読んで判断すると、実際のSQLを実行することは可能であるようには見えませんが、私は間違っているかもしれません。

2
dcrosta

後でcursor._last_executedをチェックしますが、実行するたびに変更せずにリアルタイムで印刷したい場合は、このモンキーパッチを試してください。

def log_queries(cur):
    def _query(q):
        print q # could also use logging
        return cur._do_query(q)
    cur._query = _query

conn = MySQLdb.connect( read_default_file='~/.my.cnf' )
cur = conn.cursor()
log_queries(cur)
cur.execute('SELECT %s, %s, %s', ('hello','there','world'))

MySQLdbに非常に依存しています(それ以降のバージョンでは機能しなくなる可能性があります)。現在、cur._queryは単にcalls._do_queryを呼び出し、その結果を返すため、機能します。

1
steveayre