Ja, dit is een echte puinhoop. Zowel MySQL als PostgreSQL gebruiken hiervoor standaard backslash-escapes. Dit is erg vervelend als je de string ook weer escapet met backslashes in plaats van parametrisering, en het is ook onjuist volgens ANSI SQL:1992, waarin staat dat er standaard geen extra escape-tekens zijn bovenop de normale string-escaping, en dus geen manier om een letterlijke %
. op te nemen of _
.
Ik neem aan dat de eenvoudige backslash-replace-methode ook fout gaat als je de backslash-escapes uitschakelt (die zelf niet compatibel zijn met ANSI SQL), met behulp van NO_BACKSLASH_ESCAPE
sql_mode in MySQL of standard_conforming_strings
conf in PostgreSQL (wat de PostgreSQL-ontwikkelaars al een paar versies dreigen te doen).
De enige echte oplossing is om de weinig bekende LIKE...ESCAPE
. te gebruiken syntaxis om een expliciet escape-teken op te geven voor de LIKE
-patroon. Dit wordt gebruikt in plaats van de backslash-escape in MySQL en PostgreSQL, waardoor ze voldoen aan wat iedereen doet en een gegarandeerde manier is om de out-of-band karakters op te nemen. Bijvoorbeeld met de =
teken als een ontsnapping:
# 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+'%'))
Dit werkt op PostgreSQL-, MySQL- en ANSI SQL-compatibele databases (modulo de paramstyle natuurlijk die verandert op verschillende db-modules).
Er kan nog steeds een probleem zijn met MS SQL Server/Sybase, dat blijkbaar ook [a-z]
toestaat -stijl tekengroepen in LIKE
uitdrukkingen. In dit geval zou je ook willen ontsnappen aan de letterlijke [
teken met .replace('[', '=[')
. Volgens ANSI SQL is het escapen van een teken dat geen escape nodig heeft echter ongeldig! (Argh!) Dus hoewel het waarschijnlijk nog steeds werkt in echte DBMS'en, zou je nog steeds niet ANSI-compatibel zijn. zucht...