SQLAlchemy, эквивалентный оператору SQL «LIKE»

87

Столбец тегов содержит такие значения, как «яблоко, банан, апельсин» и «клубника, банан, лимон». Я хочу найти эквивалентную инструкцию SQLAlchemy для

SELECT * FROM table WHERE tags LIKE "%banana%";

На что мне перейти, чтобы Class.query.filter()это сделать?

Гэри Олдфабер
источник

Ответы:

177

У каждого столбца есть like()метод, который можно использовать в query.filter(). Для данной строки поиска добавьте %символы с обеих сторон для поиска как подстроки в обоих направлениях.

tag = request.form["tag"]
search = "%{}%".format(tag)
posts = Post.query.filter(Post.tags.like(search)).all()
Даниил Клюев
источник
1
Отлично! Знаете ли вы, есть ли лучший способ отличить яблоко от ананаса, чем добавление ведущего пробела?
Гэри Олдфабер,
3
Лучшим способом было бы просто нормализовать вашу базу данных и добавить две отдельные таблицы для тегов и отношений между тегами и задачами, а затем использовать JOIN вместо LIKE. В противном случае да, похоже, вам понадобится какой-то разделитель вокруг каждого тега в строке. Ведущего места недостаточно, так как есть также ручка и карандаш с% pen%. Если вы сделаете что-то вроде "| яблоко | ананас | ручка | карандаш |" и совпадение "% | pen |%" не должно конфликтовать.
Daniel Kluev
1
С нормализацией я не совсем уверен, как у меня будет более одного тега, связанного с данной задачей, или наоборот, используя карту тегов. Решение "Toxi", похоже, группирует набор тегов как единый элемент, а не сохраняет каждый по отдельности? И метод, используемый в этом рецепте ( elixir.ematia.de/trac/wiki/Recipes/TagCloud ), похоже, позволяет использовать только один тег для каждого элемента. Какие ресурсы лучше всего подходят для освещения этой темы? Я тоже читал это ( dev.mysql.com/tech-resources/articles/… ), но не могу представить, как управлять несколькими тегами.
Гэри Олдфабер,
2
Как я уже сказал, вам нужно две таблицы. По сути, это типичное отношение «многие ко многим», поэтому вы можете следовать руководству по SQLAlchemy по нему: sqlalchemy.org/docs/… У вас будет tagsтаблица, в которой вы храните имя тега и другую информацию о теге, и у вас будет task_tagsтаблица, которая будет иметь по одной записи для каждого тега, добавленного к задаче. Таким образом, задача с двумя тегами будет иметь только две записи в task_tagsтаблице.
Daniel Kluev
12

Добавляя к приведенному выше ответу, кто бы ни ищет решение, вы также можете попробовать оператор «сопоставить» вместо «нравится». Не хочу быть предвзятым, но у меня это отлично сработало в Postgresql.

Note.query.filter(Note.message.match("%somestr%")).all()

Он наследует функции базы данных, такие как CONTAINS и MATCH . Однако он недоступен в SQLite.

Дополнительные сведения см. В разделе Общие операторы фильтров.

игм
источник
8
В чем разница между этими двумя операторами?
buhtz
@buhtz зависит от вашей базы данных, см. документы SQL-Alchemy: docs.sqlalchemy.org/en/14/core/… В Postgres вы получаете то, to_tsqueryчто позволяет вам добавлять текстовые операторы для таких вещей, как ORи AND postgresql.org/docs/current/…
Nick
8

попробуйте этот код

output = dbsession.query(<model_class>).filter(<model_calss>.email.ilike('%' + < email > + '%'))
Waruna K
источник
1

Использование PostgreSQL like( см обслуживаемого ответ выше ) как - то не работа для меня , хотя случаи соответствуют , но ilike(случай я nsensisitive как ) делает.

Константин
источник
2
ILIKE- это версия без учета регистра LIKE, поэтому ваши входные данные различались только регистром.
Мартейн Питерс
0

Если вы используете собственный sql, вы можете обратиться к моему коду, иначе просто проигнорируйте мой ответ.

SELECT * FROM table WHERE tags LIKE "%banana%";
from sqlalchemy import text

bar_tags = "banana"

# '%' attention to spaces
query_sql = """SELECT * FROM table WHERE tags LIKE '%' :bar_tags '%'"""

# db is sqlalchemy session object
tags_res_list = db.execute(text(query_sql), {"bar_tags": bar_tags}).fetchall()

Тоби
источник