Как увидеть реальный SQL-запрос в Python cursor.execute
Я использую следующий код в Python (с pyodbc для базы MS-Access).
cursor.execute("select a from tbl where b=? and c=?", (x, y))
Это хорошо, но для целей технического обслуживания мне нужно знать полную и точную строку SQL, отправляемую в базу данных.
Возможно ли и как?
Ответы
Ответ 1
Ответ: НЕТ.
Я отправляю свой вопрос о домашнем коде Google проекта (и в группе Google):
Комментарий № 1 по проблеме 163 по l... @deller.id.au: cursor.mogrify строка запроса возврата http://code.google.com/p/pyodbc/issues/detail?id=163
Для справки - ссылка на документация pyscopg метод "mogrify", который репортер имеет в виду: http://initd.org/psycopg/docs/cursor.html#cursor.mogrify
pyodbc не выполняет никаких таких переводы SQL: он проходит параметризованный SQL драйвер ODBC дословно. Единственный обработка связана с переводом параметры от объектов Python до C типы, поддерживаемые API ODBC.
Некоторое преобразование на SQL может быть выполняются в драйвере ODBC перед ним отправляется на сервер (например, Microsoft SQL Native Client делает это), но эти преобразования скрыты от pyodbc.
Следовательно, я думаю, что это не возможно обеспечить функцию mogrify в pyobbc.
Ответ 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"
Ответ 3
В зависимости от используемого драйвера это может быть или не быть возможно. В некоторых базах данных параметры (?
s) просто заменяются, как предполагает user589983 (хотя драйвер должен будет делать некоторые вещи, такие как цитирование строк и экранирование кавычек в этих строках, чтобы привести к выполнению этого исполняемого файла).
Другие драйверы попросят базу данных скомпилировать ( "подготовить" ) инструкцию и затем попросить ее выполнить подготовленный оператор с использованием заданных значений. Таким образом, использование подготовленных или параметризованных операторов помогает избежать SQL-инъекций - во время выполнения оператора база данных "знает", что является частью SQL, которую вы хотите запустить, и что является частью значения, которое используется в это утверждение.
Судя по быстрому уменьшению документации PyODBC, похоже, что получение фактического SQL-исполнения возможно, но я могу быть неправильно.
Ответ 4
Для debug purpuse я создал функцию проверки, которая просто заменяет? с значениями запроса... это не высокая технология:), но это работает!: 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 Storage = 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))
Если вам нужно просто добавить какое-то исключение в функцию.
Ответ 5
Вы можете использовать print cursor._last_executed
для получения последнего выполненного запроса.
Прочитайте в этом ответ, что вы также можете использовать print cursor.mogrify(query,list)
для просмотра полного запроса до или после выполнения.
Ответ 6
Я бы проверил 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 в настоящее время просто вызывает вызовы._do_query и возвращает результат.
Ответ 7
Напишите строку sql, а затем выполните ее:
sql='''select a
from tbl
where b=?
and c=? '''
cursor.execute(sql, x, y)
print 'just executed:',(sql, x,y)
Теперь вы можете делать все, что хотите, с помощью инструкции SQL.