2011-03-10 26 views
29

我在Python中使用以下代碼(使用pyodbc作爲MS-Access基礎)。如何在Python中查看真正的SQL查詢cursor.execute

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

沒關係,但出於維護的目的,我需要知道發送到數據庫的完整準確的SQL字符串。
這是可能的和如何?

回答

4

答案是:NO。 我後我的項目」家谷歌代碼(並在谷歌集團)問題的答案是:由l對問題163

評論#1 ... // @ deller.id.au:光標。 mogrify返回查詢字符串 http://code.google.com/p/pyodbc/issues/detail?id=163

僅供參考這裏是他們的 的 pyscopg文檔的鏈接「mogrify」光標方法,該 記者指的是: http://initd.org/psycopg/docs/cursor.html#cursor.mogrify

pyodbc不執行ny SQL的翻譯:它將參數化的SQL直接傳遞給 ODBC驅動程序逐字地傳遞 。涉及的唯一 處理是將參數從Python對象轉換爲ODBC API支持的C 類型。

在SQL中的一些轉變可能是在ODBC驅動程序執行 之前 被髮送到服務器(例如,Microsoft SQL 本機客戶端做到這一點),但這些 轉變是從 pyodbc隱藏。

因此,我認爲它不是 是可行的,以在pyodbc中提供一個mogrify函數 。

+1

這當然是可能的。這只是意味着重新實現由ODBC驅動程序執行的轉換。通常這只是一些逃避。 –

-1

編寫的SQL字符串,然後執行它:

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

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

現在你可以做任何你想要的SQL語句。

+4

不是很好,以避免SQL注入... – FerranB

+0

對我來說也不好:我在'執行'由於不同的原因,SQL注入,但也因爲'執行'功能根據數據庫修改SQL查詢類型和列類型。示例:我可以傳遞字符串或整數或日期字段,而不用擔心在查詢中引用它們。 – philnext

2

根據您使用的驅動程序,這可能會也可能不會。在一些數據庫中,參數(? s)被簡單地替換,正如user589983的答案所表明的那樣(儘管驅動程序將不得不做一些事情,比如引用字符串並在這些字符串中轉義引號,以便產生可執行的語句)。

其他驅動程序會要求數據庫編譯(「準備」)該語句,然後要求它使用給定的值執行準備好的語句。通過這種方式,使用準備或參數化語句有助於避免SQL注入 - 在語句執行時,數據庫「知道」您希望運行的SQL的一部分,以及內部使用的值的一部分該聲明。

通過快速瀏覽PyODBC documentation來判斷,似乎沒有獲得執行的實際SQL是可能的,但我可能是錯誤的。

+0

是的,今天我看不到在文檔中的信息。 – philnext

33

它因司機而異。這裏有兩個例子:

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" 
+6

在psycopg2還有光標的'mogrify()'方法,它可以讓你看到什麼命令將被給定的查詢,而無需(或之前)執行它執行。 – kindall

+5

在MySQLdb中**'_ last_executed'**保存最後一個查詢字符串,即使在發生異常時也能運行。如果錯誤,屬性** _執行**爲無。 [http://stackoverflow.com/a/7190914/653372] – nergeia

+0

運算特別說pyodbc的MS Access。不是MySQL或Postgres的 – ThatAintWorking

2

調試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項= 1和存儲= 2且FiscalYear = 'asdasd' AND BalanceYear = 12331和平衡= 'AAS')AND BalanceMonth = 1

有了這個,你可以登錄或做任何你想要的:

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

如果你只需要添加一些異常捕獲到的功能。

1

我回頭檢查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並返回結果。

3

您可以使用print cursor._last_executed得到最後執行的查詢。

this中閱讀您還可以使用print cursor.mogrify(query,list)在執行之前或之後查看完整查詢。

相關問題