2010-01-21 46 views
25

psycopg2是否具有用於轉義Postgres的LIKE操作數的功能?使用psycopg2轉義Postgres的SQL「LIKE」值

例如我可能要匹配字符串「所有的20%」開頭的字符串,所以我想寫的東西是這樣的:

sql = '... WHERE ... LIKE %(myvalue)s' 
cursor.fetchall(sql, { 'myvalue': escape_sql_like('20% of all') + '%' } 

有一個現有的escape_sql_like功能,我可以在這裏插入?

(類似問題How to quote a string value explicitly (Python DB API/Psycopg2),但我無法找到答案有)

回答

0

由於未能找到一個內置的功能,到目前爲止,我寫了一個很簡單:

def escape_sql_like(s): 
    return s.replace('\\', '\\\\').replace('%', '\\%').replace('_', '\\_') 
+0

你忘了「'」和'「' –

+0

@JensTimmerman這個函數只能轉義類似的標記,在結果中使用正常的字符串轉義,然後在查詢中使用它,正確的字符串轉義依賴於標準的'standard_conforming_stings'和所以最好使用庫代碼 – Jasen

23

是的,這真是一團糟。默認情況下,MySQL和PostgreSQL都使用反斜槓轉義。這是一個可怕的痛苦,如果你也用反斜槓而不是使用參數化來再次轉義字符串,並且根據ANSI SQL:1992也是不正確的,它表示在普通字符串轉義的頂部沒有額外的轉義字符,並且因此無法包含文字%_

我推測這個簡單的反斜槓替換方法也出了問題,如果你關閉反斜槓逃逸(它們本身是不符合ANSI SQL),使用MySQL的NO_BACKSLASH_ESCAPE的sql_mode或standard_conforming_strings CONF PostgreSQL中(其中,PostgreSQL的開發人員現在已經威脅要做幾個版本)。

唯一真正的解決方案是使用鮮爲人知的LIKE...ESCAPE語法爲LIKE模式指定明確的轉義字符。這在MySQL和PostgreSQL中被使用,而不是反斜槓轉義,使它們符合其他人的做法,並提供包含帶外字符的保證方式。例如與=符號作爲轉義:

# look for term anywhere within title 
term= term.replace('=', '==').replace('%', '=%').replace('_', '=_') 
sql= "SELECT * FROM things WHERE description LIKE %(like)s ESCAPE '='" 
cursor.execute(sql, dict(like= '%'+term+'%')) 

這適用於的PostgreSQL,MySQL和ANSI兼容SQL的數據庫(模這當然在不同的分貝模塊改變paramstyle)。

MS SQL Server/Sybase可能仍然存在問題,這顯然也允許LIKE表達式中的[a-z]樣式字符組。在這種情況下,您希望也可以通過.replace('[', '=[')轉義文字[。但是根據ANSI SQL轉義不需要轉義的字符是無效的! (唉!)雖然它可能仍然可以在真正的DBMS中工作,但是您仍然不符合ANSI標準。嘆息......

0

您可以創建一個Like類的子類strregister an adapter for it有它的語法正確的轉換(例如,使用escape_sql_like()你寫)。

+0

一個有趣的想法,我沒有想到,但你總是需要將轉義字符串與真正的LIKE運算符(%或_)結合起來,否則你可能已經使用過'='而不是'LIKE'。如果你這樣做,那麼我不確定這種方法的好處在於簡單的調用轉義函數的方法。 – EMP

1

我想知道是否所有上述都是真的需要。我使用的psycopg2,是能夠簡單的使用方法:

data_dict['like'] = psycopg2.Binary('%'+ match_string +'%') 
cursor.execute("SELECT * FROM some_table WHERE description ILIKE %(like)s;", data_dict) 
+3

對我不起作用 – dfrankow

+4

它可以更容易:'cursor.execute(「SELECT * FROM some_table WHERE description LIKE%s;」,['foobar%']); –

0

我做了一些修改上面的代碼執行以下操作:

def escape_sql_like(SQL): 
    return SQL.replace("'%", 'PERCENTLEFT').replace("%'", 'PERCENTRIGHT') 

def reescape_sql_like(SQL): 
    return SQL.replace('PERCENTLEFT', "'%").replace('PERCENTRIGHT', "%'") 

SQL = "SELECT blah LIKE '%OUCH%' FROM blah_tbl ... " 
SQL = escape_sql_like(SQL) 
tmpData = (LastDate,) 
SQL = cur.mogrify(SQL, tmpData) 
SQL = reescape_sql_like(SQL) 
cur.execute(SQL) 
2

您也可以看看這個問題,從不同的角度。你想要什麼?你想要一個查詢,對任何字符串參數執行LIKE通過追加'%'的參數。一個很好的方式來表達,而不訴諸功能和psycopg2擴展可能是:

sql = "... WHERE ... LIKE %(myvalue)s||'%'" 
cursor.execute(sql, { 'myvalue': '20% of all'}) 
+1

that match match string像2001年是所有恐怖主義中最糟糕的一樣 – Jasen

2

相反逃逸百分比字符,你可以改爲使用PostgreSQL的正則表達式實現的。

例如,針對系統目錄下面的查詢將提供從autovacuuming子系統不活躍的查詢的列表:

SELECT procpid, current_query FROM pg_stat_activity 
WHERE (CURRENT_TIMESTAMP - query_start) >= '%s minute'::interval 
AND current_query !~ '^autovacuum' ORDER BY (CURRENT_TIMESTAMP - query_start) DESC; 

由於該查詢語法不利用「LIKE」關鍵字,你可以做你想做的事......而不是蟒蛇和psycopg2的水域。