用psycopg2转义Postgres中的SQL "LIKE"值
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)的问题类似,但我在那儿没找到答案。)
13 个回答
如果你在使用预处理语句,那么输入的数据会被包裹在''
中,这样可以防止SQL注入攻击。这是个好方法,但也会限制你把输入和SQL语句直接拼接在一起。
解决这个问题最好的方法就是把%
(s)作为输入的一部分传入。
cursor.execute('SELECT * FROM goats WHERE name LIKE %(name)s', { 'name': '%{}%'.format(name)})
我可以通过在LIKE操作符中使用%%
来转义%
。
sql_query = "select * from mytable where website like '%%.com'"
cursor.fetchall(sql_query)
是的,这真是一团糟。MySQL和PostgreSQL默认都使用反斜杠来转义字符。如果你还要用反斜杠再次转义字符串,而不是使用参数化,这就会变得非常麻烦。而且根据ANSI SQL:1992的规定,默认情况下没有额外的转义字符,所以也就没有办法直接包含字面上的%
或_
。
我猜如果你关闭了反斜杠转义(这本身就不符合ANSI SQL),使用MySQL中的NO_BACKSLASH_ESCAPE
sql_mode或者PostgreSQL中的standard_conforming_strings
配置,简单的反斜杠替换方法也会出问题(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中可能仍然会有问题,因为它们似乎也允许在LIKE
表达式中使用[a-z]
风格的字符组。在这种情况下,你还需要用.replace('[', '=[')
来转义字面上的[
字符。不过根据ANSI SQL,转义一个不需要转义的字符是无效的!(真让人抓狂!)所以虽然在真实的数据库管理系统中可能仍然能工作,但你依然不符合ANSI标准。唉……