51

psycopg2には、PostgresのLIKEオペランドの値をエスケープする機能がありますか?

たとえば、「20%of all」という文字列で始まる文字列を照合したい場合は、次のように記述します。

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

ここにプラグインできる既存のescape_sql_like関数はありますか?

(文字列値を明示的に引用する方法(Python DB API / Psycopg2)と同様の質問ですが、答えが見つかりませんでした。)

4

12 に答える 12

35

ええ、これは本当の混乱です。デフォルトでは、MySQL と PostgreSQL の両方でバックスラッシュ エスケープが使用されます。パラメータ化を使用する代わりにバックスラッシュを使用して文字列を再度エスケープしている場合、これはひどい痛みです。また、ANSI SQL:1992 によると、これは正しくありません。これは、デフォルトでは、通常の文字列エスケープの上に余分なエスケープ文字がないことを示しています。したがって、リテラル%またはを含める方法はありません_

NO_BACKSLASH_ESCAPEMySQL で sql_mode を使用するかstandard_conforming_strings、PostgreSQL で confを使用してバックスラッシュエスケープ (ANSI SQL に準拠していない) をオフにすると、単純なバックスラッシュ置換メソッドもうまくいかないと思います(PostgreSQL 開発者はこれを行うと脅しています)。現在、いくつかのバージョンがあります)。

唯一の本当の解決策は、ほとんど知られていない構文を使用して、 -patternLIKE...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 準拠のデータベースで動作します (もちろん、さまざまな db モジュールで変更される paramstyle をモジュロします)。

MS SQL Server/Sybase にはまだ問題がある可能性があります。これ[a-z]は、式で -style 文字グループも使用できるようLIKEです。この場合、リテラル[文字も でエスケープする必要があり.replace('[', '=[')ます。ただし、ANSI SQL によると、エスケープする必要のない文字のエスケープは無効です。(うーん!) したがって、実際の DBMS で動作する可能性はありますが、ANSI に準拠しているとは言えません。はぁ...

于 2010-01-21T02:04:04.760 に答える
2

上記のすべてが本当に必要なのだろうか。私はpsycopg2を使用していて、単に使用することができました:

data_dict['like'] = psycopg2.Binary('%'+ match_string +'%')
cursor.execute("SELECT * FROM some_table WHERE description ILIKE %(like)s;", data_dict)
于 2010-06-02T06:03:40.217 に答える
2

パーセント文字をエスケープする代わりに、PostgreSQL の正規表現の実装を利用できます。

たとえば、システム カタログに対する次のクエリは、自動バキューム サブシステムからのものではないアクティブなクエリのリストを提供します。

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」キーワードを使用しないため、必要なことを行うことができます...そして、python と psycopg2 に関して水を濁すことはありません。

于 2014-02-06T18:02:26.713 に答える
1

これまで組み込み関数を見つけることができなかったので、私が書いた関数は非常に単純です。

def escape_sql_like(s):
    return s.replace('\\', '\\\\').replace('%', '\\%').replace('_', '\\_')
于 2010-01-21T01:22:11.213 に答える
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)
于 2011-08-04T04:48:28.533 に答える
-1

f文字列を使用する方が簡単で読みやすいと思います。

query = f'''SELECT * FROM table where column like '%%{my_value}%%' '''
cursor.execute(query)
于 2020-08-07T21:08:16.637 に答える