psycopg2是否有一个函数来转义Postgres的 LIKE 操作数的值?
例如,我可能希望匹配以字符串“20%of all”开头的字符串,所以我想写这样的东西:
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 :(得分:27)
是的,这真是一团糟。默认情况下,MySQL和PostgreSQL都使用反斜杠转义。如果您还使用反斜杠而不是使用参数化再次转义字符串,这是一个可怕的痛苦,根据ANSI SQL:1992,它也是不正确的,它表示在正常字符串转义的基础上默认没有额外的转义字符,并且因此无法包含文字%
或_
。
我认为如果你在MySQL中使用NO_BACKSLASH_ESCAPE
sql_mode或standard_conforming_strings
关闭反斜杠转义(它本身不符合ANSI SQL),简单的反斜杠替换方法也会出错PostgreSQL中的conf(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兼容的数据库(模块化当然是在不同的数据库模块上发生变化的模式)。
MS SQL Server / Sybase可能仍然存在问题,这显然也允许在[a-z]
表达式中使用LIKE
样式字符组。在这种情况下,您还希望使用[
转义文字.replace('[', '=[')
字符。但是根据ANSI SQL转义,不需要转义的字符无效! (唉!)虽然它可能仍然适用于真正的DBMS,但你仍然不符合ANSI标准。叹息...
答案 1 :(得分:4)
您还可以从不同角度查看此问题。你想要什么?您希望查询任何字符串参数通过在参数后附加'%'来执行LIKE。表达这一点的好方法,不需要求助于函数和psycopg2扩展,可以是:
sql = "... WHERE ... LIKE %(myvalue)s||'%'"
cursor.execute(sql, { 'myvalue': '20% of all'})
答案 2 :(得分: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'关键字,因此您可以执行您想要的操作...而不是使用python和psycopg2进行混淆。
答案 3 :(得分:2)
通过使用 Like 操作数中的%
,我可以逃脱%%
。
sql_query = "select * from mytable where website like '%%.com'"
cursor.fetchall(sql_query)
答案 4 :(得分:1)
我想知道是否真的需要以上所有内容。我正在使用psycopg2并且只能使用:
data_dict['like'] = psycopg2.Binary('%'+ match_string +'%')
cursor.execute("SELECT * FROM some_table WHERE description ILIKE %(like)s;", data_dict)
答案 5 :(得分:0)
到目前为止找不到内置函数,我写的那个很简单:
def escape_sql_like(s):
return s.replace('\\', '\\\\').replace('%', '\\%').replace('_', '\\_')
答案 6 :(得分:0)
您可以创建Like
类子类str
和register an adapter for it,使其以正确的语法转换(例如,使用您编写的escape_sql_like()
。
答案 7 :(得分: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)
答案 8 :(得分:0)
我发现了一个更好的技巧。只需将“%”附加到您的搜索query_text中即可。
con, queryset_list = psycopg2.connect(**self.config), None
cur = con.cursor(cursor_factory=RealDictCursor)
query = "SELECT * "
query += " FROM questions WHERE body LIKE %s OR title LIKE %s "
query += " ORDER BY questions.created_at"
cur.execute(query, ('%'+self.q+'%', '%'+self.q+'%'))
答案 9 :(得分:0)
如果使用的是预准备语句,则输入将包装在''
中,以防止sql注入。这很棒,但也可以防止输入+ sql串联。
最好的和最安全的方法是将%
作为输入的一部分。
cursor.execute('SELECT * FROM goats WHERE name LIKE %(name)s', { 'name': '%name%'.format(name)})
答案 10 :(得分:0)
我认为使用f字符串会更简单易读。
query = f'''SELECT * FROM table where column like '%%{my_value}%%' '''
cursor.execute(query)