是的,这确实是个麻烦。MySQL和PostgreSQL都默认使用反斜线转义来处理这个问题。如果你也用反斜线来转义字符串而不是使用参数化,这是一个可怕的痛苦,而且根据ANSI SQL:1992,这也是不正确的,它说在正常的字符串转义之上默认没有额外的转义字符,因此没有办法包括一个字面的
%
或
_
。
我想,如果你关闭了反斜线escapes(其本身不符合ANSI SQL),使用MySQL中的
NO_BACKSLASH_ESCAPE
sql_mode或PostgreSQL中的
standard_conforming_strings
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标准的数据库上都可以使用(当然,在不同的数据库模块上,paramstyle会有变化)。
MS SQL Server/Sybase可能还有一个问题,它显然也允许在LIKE表达式中使用[a-z]风格的字符组。在这种情况下,你会希望用.replace('[', '=[')来转义字面的[字符。然而,根据ANSI SQL的规定,转义一个不需要转义的字符是无效的。(因此,尽管它可能仍然可以在真正的DBMS中工作,但你仍然不符合ANSI标准。