Как увидеть настоящий SQL-запрос в Python cursor.execute, используя pyodbc и MS-Access - PullRequest
40 голосов
/ 11 марта 2011

Я использую следующий код в Python (с pyodbc для базы MS-Access).

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

Это нормально, но в целях обслуживания мне нужно знать полную и точную строку SQL, отправляемую вбазы данных.
Возможно ли это и как?

Ответы [ 7 ]

39 голосов
/ 11 марта 2011

Отличается в зависимости от водителя.Вот два примера:

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"
7 голосов
/ 24 февраля 2017

Вы можете использовать print cursor._last_executed для получения последнего выполненного запроса.

Прочтите этот ответ, который вы также можете использовать print cursor.mogrify(query,list), чтобы увидеть полный запрос до или после выполнения.

6 голосов
/ 16 марта 2011

Ответ: НЕТ.Я размещаю свой вопрос в домашнем коде 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, поддерживаемые ODBC API.

Некоторое преобразование SQL может быть выполнено в драйвере ODBC перед его отправкой на сервер (например, собственный клиент Microsoft SQL).делает это), но эти преобразования скрыты от pyodbc.

Следовательно, я думаю, что не представляется возможным обеспечить функцию mogrify в pyodbc.

3 голосов
/ 27 февраля 2014

Для отладки я создал функцию проверки, которая просто заменяет?со значениями запроса ... это не высокие технологии :) но это работает!: 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))

Если вам нужно просто добавить несколько исключений, перехватывающих функцию.

2 голосов
/ 02 декабря 2016

Я бы проверил 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 в настоящее время просто вызывает call._do_query и возвращает его результат.

2 голосов
/ 11 марта 2011

В зависимости от используемого вами драйвера, это может быть или не быть возможным. В некоторых базах данных параметры (? s) просто заменяются, как предполагает ответ user589983 (хотя драйверу придется делать некоторые вещи, например заключать в кавычки строки и экранировать кавычки в этих строках, чтобы получить исполняемый оператор) .

Другие драйверы попросят базу данных скомпилировать («подготовить») инструкцию, а затем попросят ее выполнить подготовленную инструкцию, используя заданные значения. Таким образом, использование подготовленных или параметризованных операторов помогает избежать SQL-инъекций - во время выполнения оператора база данных «знает», что является частью SQL, который вы хотите запустить, и что является частью значения, используемого внутри это утверждение.

Судя по быстрому просмотру документации PyODBC , не представляется возможным получить реальный SQL, но я могу ошибаться.

0 голосов
/ 11 марта 2011

Напишите строку sql и затем выполните ее:

sql='''select a 
       from tbl 
       where b=? 
       and c=? '''

cursor.execute(sql, x, y)
print 'just executed:',(sql, x,y)

Теперь вы можете делать все, что захотите, с оператором SQL.

...