Sim, isso é uma verdadeira bagunça. Tanto o MySQL quanto o PostgreSQL usam escapes de barra invertida para isso por padrão. Isso é uma dor terrível se você também estiver escapando a string novamente com barras invertidas em vez de usar parametrização, e também está incorreto de acordo com ANSI SQL:1992, que diz que, por padrão, não há caracteres de escape extras em cima do escape normal de string e portanto, não há como incluir um literal
%
ou _
. Eu presumo que o método simples de substituição de barra invertida também dê errado se você desativar os escapes de barra invertida (que não são compatíveis com ANSI SQL), usando
NO_BACKSLASH_ESCAPE
sql_mode no MySQL ou standard_conforming_strings
conf no PostgreSQL (o que os desenvolvedores do PostgreSQL vêm ameaçando fazer há algumas versões). A única solução real é usar o pouco conhecido
LIKE...ESCAPE
sintaxe para especificar um caractere de escape explícito para o LIKE
-padronizar. Isso é usado em vez do escape de barra invertida no MySQL e no PostgreSQL, tornando-os conforme o que todos os outros fazem e dando uma maneira garantida de incluir os caracteres fora de banda. Por exemplo, com o =
sinal como uma fuga:# 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+'%'))
Isso funciona em bancos de dados compatíveis com PostgreSQL, MySQL e ANSI SQL (módulo o paramstyle, é claro, que muda em diferentes módulos db).
Ainda pode haver um problema com o MS SQL Server/Sybase, que aparentemente também permite
[a-z]
-style grupos de caracteres em LIKE
expressões. Nesse caso, você também deseja escapar do literal [
caractere com .replace('[', '=[')
. No entanto, de acordo com o ANSI SQL, o escape de um caractere que não precisa de escape é inválido! (Argh!) Portanto, embora provavelmente ainda funcione em DBMSs reais, você ainda não seria compatível com ANSI. suspirar...