Escape SQL "LIKE" значение для Postgres с psycopg2
Имеет ли psycopg2 функцию для ускорения значения операнда LIKE для Postgres?
Например, мне может понадобиться сопоставить строки, начинающиеся со строки "20% всех", поэтому я хочу написать что-то вроде этого:
sql = '... WHERE ... LIKE %(myvalue)s'
cursor.fetchall(sql, { 'myvalue': escape_sql_like('20% of all') + '%' }
Есть ли существующая функция escape_sql_like, которую я мог бы подключить сюда?
(Аналогичный вопрос Явным образом цитирую строковое значение (Python DB API/Psycopg2), но я не смог найти ответ есть.)
Ответы
Ответ 1
Да, это настоящий беспорядок. Оба MySQL и PostgreSQL используют для этого по умолчанию обратную косую черту. Это ужасная боль, если вы снова избегаете строки с помощью обратных косых черт вместо использования параметризации, а также неверны в соответствии с ANSI SQL: 1992, в котором говорится, что по умолчанию нет лишних символов escape поверх нормального экранирования строки и следовательно, нет возможности включить литерал %
или _
.
Я бы предположил, что простой метод обратной косой черты также ошибочен, если вы отключите обратные слэши-экраны (которые сами не соответствуют ANSI SQL), используя NO_BACKSLASH_ESCAPE
sql_mode в MySQL или standard_conforming_strings
conf в PostgreSQL ( которые разработчики PostgreSQL угрожают сделать для нескольких версий сейчас).
Единственное реальное решение - использовать малоизвестный синтаксис LIKE...ESCAPE
для указания явного escape-символа для LIKE
-pattern. Это используется вместо обратного слэша в MySQL и PostgreSQL, что делает их совместимыми с тем, что делают все остальные, и дает гарантированный способ включения внеполосных символов. Например, с знаком =
в качестве escape:
# 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 (по модулю, который, конечно же, изменяется на разных модулях db).
По-прежнему может возникнуть проблема с MS SQL Server/Sybase, которая, по-видимому, также допускает [a-z]
-символьные группы символов в выражениях LIKE
. В этом случае вы также захотите избежать символа [
с .replace('[', '=[')
. Однако, согласно ANSI SQL, экранирование символов, которые не требуют экранирования, недействительно! (Argh!) Поэтому, хотя он, вероятно, все еще будет работать через настоящие СУБД, вы все равно не будете ANSI-совместимым. Вздох...
Ответ 2
Вы также можете взглянуть на эту проблему под другим углом. Что ты хочешь? Вам нужен запрос, который для любого строкового аргумента выполняет LIKE, добавляя "%" к аргументу. Хороший способ выразить это, не прибегая к функциям и расширениям psycopg2, может быть:
sql = "... WHERE ... LIKE %(myvalue)s||'%'"
cursor.execute(sql, { 'myvalue': '20% of all'})
Ответ 3
Вместо того, чтобы избегать символа процента, вместо этого вы можете использовать реализацию регулярного выражения PostgreSQL.
Например, следующий запрос к системным каталогам предоставит список активных запросов, которые не относятся к подсистеме автовыпускания:
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.
Ответ 4
Мне удалось избежать %
с помощью %%
в операнде LIKE.
sql_query = "select * from mytable where website like '%%.com'"
cursor.fetchall(sql_query)
Ответ 5
Интересно, действительно ли все это необходимо. Я использую psycopg2 и просто могу использовать:
data_dict['like'] = psycopg2.Binary('%'+ match_string +'%')
cursor.execute("SELECT * FROM some_table WHERE description ILIKE %(like)s;", data_dict)
Ответ 6
Не удалось найти встроенную функцию, написанную мной, довольно просто:
def escape_sql_like(s):
return s.replace('\\', '\\\\').replace('%', '\\%').replace('_', '\\_')
Ответ 7
Вы можете создать подклассы Like
str
и зарегистрировать адаптер для него, чтобы преобразовать его в правильном синтаксисе (например, используя escape_sql_like()
, который вы написали).
Ответ 8
Я сделал некоторые изменения в приведенном выше коде, чтобы сделать следующее:
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)
Ответ 9
Я нашел лучший взломать. Просто добавьте "%" к вашему поисковому запросу.
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+'%'))