SQLAlchemy equivalente a la instrucción "LIKE" de SQL

85

Una columna de etiquetas tiene valores como "manzana plátano naranja" y "fresa plátano limón". Quiero encontrar la declaración equivalente de SQLAlchemy a

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

¿A qué debo pasar Class.query.filter()para hacer esto?

Gary Oldfaber
fuente

Respuestas:

173

Cada columna tiene un like()método, que se puede utilizar en query.filter(). Dada una cadena de búsqueda, agregue un %carácter a cada lado para buscar como una subcadena en ambas direcciones.

tag = request.form["tag"]
search = "%{}%".format(tag)
posts = Post.query.filter(Post.tags.like(search)).all()
Daniel Kluev
fuente
1
¡Perfecto! ¿Sabe si hay una mejor manera de distinguir entre manzana y piña que agregando un espacio inicial?
Gary Oldfaber
3
La mejor manera sería simplemente normalizar su base de datos y agregar 2 tablas separadas para etiquetas y relaciones de etiqueta a tarea, y luego usar JOINs en lugar de LIKE. De lo contrario, sí, parece que tendrá que tener algún tipo de separador alrededor de cada etiqueta en la cadena. El espacio inicial no es suficiente, ya que también hay bolígrafo y lápiz, con% pen%. Si haces algo como "| manzana | piña | bolígrafo | lápiz |" y coincide con "% | pen |%" no debe colisionar.
Daniel Kluev
1
Con la normalización, no estoy muy seguro de cómo tendré más de una etiqueta asociada con una tarea determinada, o viceversa usando el mapa de etiquetas. ¿La solución "Toxi" parece agrupar la colección de etiquetas como un solo elemento, en lugar de almacenar cada una individualmente? Y el método utilizado en esta receta ( elixir.ematia.de/trac/wiki/Recipes/TagCloud ) parece permitir solo una etiqueta por artículo. ¿Qué recursos serían los mejores para dilucidar este tema? También he leído esto ( dev.mysql.com/tech-resources/articles/… ), pero no puedo imaginarme cómo administrar varias etiquetas.
Gary Oldfaber
2
Como dije, necesitas dos mesas. Básicamente, es una relación típica de muchos a muchos, por lo que puede seguir la guía de SQLAlchemy: sqlalchemy.org/docs/ ... Tendrá una tagstabla, donde almacena el nombre de la etiqueta y otra información de la etiqueta, y tendrá una task_tagstabla, que tendrá un registro por cada etiqueta agregada a la tarea. Entonces, la tarea con 2 etiquetas solo tendrá 2 registros en la task_tagstabla.
Daniel Kluev
11

Además de la respuesta anterior, quien busque una solución, también puede probar el operador 'coincidir' en lugar de 'me gusta'. No quiero ser parcial, pero funcionó perfectamente para mí en Postgresql.

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

Hereda funciones de base de datos como CONTAINS y MATCH . Sin embargo, no está disponible en SQLite.

Para obtener más información, vaya a Operadores de filtros comunes

igsm
fuente
8
¿Cuál es la diferencia entre estos dos operadores?
Buhtz
@buhtz depende de su base de datos, consulte los documentos de SQL-Alchemy: docs.sqlalchemy.org/en/14/core/… En Postgres, obtiene lo to_tsqueryque le permite agregar operadores de texto para cosas como ORy AND postgresql.org/docs/current/…
Nick
7

prueba este código

output = dbsession.query(<model_class>).filter(<model_calss>.email.ilike('%' + < email > + '%'))
waruna k
fuente
1

El uso de PostgreSQL like( véase la respuesta aceptada por encima ) de alguna manera no me funcionó aunque los casos emparejados , pero ilike(caso i nsensisitive como ) lo hace.

Konstantin
fuente
2
ILIKEes la versión que no distingue entre mayúsculas y minúsculas LIKE, por lo que sus entradas diferían solo en mayúsculas y minúsculas.
Martijn Pieters
0

Si usa sql nativo, puede consultar mi código; de lo contrario, simplemente ignore mi respuesta.

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()

Toby
fuente