如何使用pyodbc和MS-Access在Python cursor.execute中查看真正的SQL查询

如何使用pyodbc和MS-Access在Python cursor.execute中查看真正的SQL查询,python,sql,ms-access,pyodbc,Python,Sql,Ms Access,Pyodbc,我将以下Python代码与pyodbc一起用于MS Access库 cursor.execute("select a from tbl where b=? and c=?", (x, y)) 这没关系,但出于维护目的,我需要知道发送到数据库的完整而准确的SQL字符串。 是否可能以及如何执行?编写sql字符串,然后执行: sql='''select a from tbl where b=? and c=? ''' cursor.execute(s

我将以下Python代码与pyodbc一起用于MS Access库

cursor.execute("select a from tbl where b=? and c=?", (x, y))
这没关系,但出于维护目的,我需要知道发送到数据库的完整而准确的SQL字符串。
是否可能以及如何执行?

编写sql字符串,然后执行:

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

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

现在,您可以使用SQL语句执行任何操作

根据您使用的驱动程序,这可能是可能的,也可能是不可能的。在一些数据库中,参数被简单地替换,正如user589983的回答所表明的那样,尽管驱动程序必须做一些事情,例如引用字符串和在这些字符串中转义引号,以便生成可执行的语句

其他驱动程序将要求数据库编译prepare语句,然后要求它使用给定的值执行prepared语句。通过这种方式,使用准备好的或参数化的语句有助于避免SQL注入—在语句执行时,数据库知道您希望运行的SQL的哪些部分,以及该语句中使用的值的哪些部分


快速浏览一下,似乎不可能执行实际的SQL,但我可能错了。

驱动程序不同。以下是两个例子:

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"
答案是:没有。 我将我的问题发布在项目的主页Google代码和Google组中,答案是:

l...@deller.id.au对问题163的评论1:cursor.mogrify返回查询字符串

这里有一个链接到 pyscopg文件记录其 mogrify游标方法 记者指的是:

pyodbc不执行任何此类操作 SQL的翻译:它传递 参数化SQL直通到 ODBC驱动程序逐字记录。唯一的 所涉及的处理是翻译 从Python对象到C的参数 ODBC API支持的类型

SQL上的某些转换可能是 在之前的ODBC驱动程序中执行 已发送到服务器,例如Microsoft SQL本机客户端执行此操作,但 转换是隐藏的 pyodbc

因此,我认为情况并非如此 提供mogrify函数是可行的 在pyodbc中


为了便于调试,我创建了一个check函数,它只替换?使用查询值。。。这不是高科技,但它是有效的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))
结果是:

从dbo.MA_ItemsMonthlyBalances中选择* 其中项目=1,存储=2,财务年度=asdasd,余额年度=12331,余额=aas,余额月份=1

使用此功能,您可以登录或执行任何您想要的操作:

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

如果您只需要在函数中添加一些异常捕获功能。

我会检查光标。_last_之后执行,但是如果您希望在不更改每次执行的情况下实时打印,请尝试此monkey补丁:

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.\u query当前只调用calls.\u do\u query并返回其结果。

您可以使用print cursor.\u last\u executed获取最后执行的查询


阅读答案,您也可以使用print cursor.mogrifyquery,list在执行之前或之后查看完整的查询。

我以前在pyodbc中查看实际的SQL字符串。如果您使用不受保护的服务器连接进行开发,可能会有所帮助。

因为pyodbc在执行查询之前无法查看查询。您可以手动预填充查询,以了解查询的最终外观。它不会像实际的查询那样工作,但它帮助我找出在一个需要40多个参数的查询中是否有任何错误

query = """select * from [table_name] where a = ? and b = ?"""

parameter_list = ['dog', 'cat'] # List of parameters, a = 'dog', b = 'cat'.

query_list = list(query) # Split query string into individual characters.

# Loop through list and populate the question marks.
for i in range(len(parameter_list)):
    for idx, val in enumerate(query_list):
        if val == '?':
            query_list[idx] = str(parameter_list[i])
            break

# Rejoin the query string.
query_populate = ''.join(query_list)

#### Result ####
"""select * from [table_name] where a = dog and b = cat"""

对我来说也不太好:出于不同的原因,我在“execute”中传递变量,SQL注入,但也因为“execute”函数根据数据库类型和列类型修改SQL查询。示例:我可以传递字符串、整数或日期字段,而不用担心在查询中引用它们,它可以让您确切地看到给定查询在不执行或执行之前将执行什么命令。在MySQLdb中,即使发生异常,“上次执行”也会保留要运行的最后一个查询字符串。如果出现错误,则执行的属性_为无。[op特别指出pyodbc用于MS Access。当然不可能使用MySQL或PostgresIt。它只是意味着重新实现ODBC驱动程序执行的转换。通常这只是一些转义。cursor.mogrifyquery、list也适用于python3和PsycopG2。这种方法不适用于针对本机访问表的查询。例如查询由Access数据库引擎处理,在Wireshark中可以看到数据库文件中页的SMB/CIFS请求和响应,这远低于正在处理的SQL语句。您可以看到针对ODBC链接表的查询的SQL文本,但它是原始SQL文本 使用参数占位符,例如,从tablename中选择*,其中columnname>@P1,而不是插入参数值。