SQLAlchemy equivalente à instrução SQL “LIKE”

87

Uma coluna de tags tem valores como "maçã banana laranja" e "morango banana limão". Eu quero encontrar a declaração equivalente SQLAlchemy para

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

O que devo passar Class.query.filter()para fazer isso?

Gary Oldfaber
fonte

Respostas:

177

Cada coluna possui um like()método, que pode ser usado em query.filter(). Dada uma string de pesquisa, adicione um %caractere em cada lado para pesquisar como uma substring em ambas as direções.

tag = request.form["tag"]
search = "%{}%".format(tag)
posts = Post.query.filter(Post.tags.like(search)).all()
Daniel Kluev
fonte
1
Perfeito! Você sabe se há uma maneira melhor de distinguir entre maçã e abacaxi do que adicionar um espaço principal?
Gary Oldfaber
3
A melhor maneira seria apenas normalizar seu banco de dados e adicionar 2 tabelas separadas para tags e relações tag-para-tarefa, e então usar JOINs em vez de LIKE. Caso contrário, sim, parece que você terá que ter algum tipo de separador ao redor de cada tag na string. O espaço não é suficiente, pois também há caneta e lápis, com% pen%. Se você fizer algo como "| maçã | abacaxi | caneta | lápis |" e corresponder a "% | pen |%" não deve colidir.
Daniel Kluev
1
Com a normalização, não tenho certeza de como terei mais de uma tag associada a uma determinada tarefa ou vice-versa usando o mapa de tags. A solução "Toxi" parece agrupar a coleção de tags como um único item, em vez de armazenar cada uma individualmente? E o método usado nesta receita ( elixir.ematia.de/trac/wiki/Recipes/TagCloud ) parece permitir apenas uma tag por item. Quais recursos seriam os melhores para elucidar este tópico? Eu li isso ( dev.mysql.com/tech-resources/articles/… ) também, mas não consigo imaginar como gerenciar várias tags.
Gary Oldfaber
2
Como eu disse, você precisa de duas tabelas. Basicamente, é uma relação típica de muitos para muitos, então você pode seguir o guia do SQLAlchemy sobre ele: sqlalchemy.org/docs/… Você terá uma tagstabela, onde você armazena o nome da tag e outras informações da tag, e você terá uma task_tagstabela, que terá um registro para cada tag adicionada à tarefa. Portanto, a tarefa com 2 tags terá apenas 2 registros na task_tagstabela.
Daniel Kluev
12

Somando-se a resposta acima, quem procura uma solução, você também pode tentar o operador 'combinar' em vez de 'gostar'. Não quero ser tendencioso, mas funcionou perfeitamente para mim no Postgresql.

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

Ele herda funções de banco de dados como CONTAINS e MATCH . No entanto, não está disponível no SQLite.

Para obter mais informações, acesse Operadores de filtro comuns

igsm
fonte
8
Qual é a diferença entre esses dois operadores?
buhtz
@buhtz depende de suas backend ver docs SQL-Alchemy DB: docs.sqlalchemy.org/en/14/core/... Em Postgres você começa to_tsqueryo que permite que você adicione operadores de texto para coisas como ORe AND postgresql.org/docs/current/...
Nick
8

tente este código

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

Usar o PostgreSQL like( veja a resposta aceita acima ) de alguma forma não funcionou para mim, embora os casos correspondam , mas ilike(case i nsensisitive como ) sim.

Konstantin
fonte
2
ILIKEé a versão LIKEque não diferencia maiúsculas de minúsculas de , portanto, suas entradas diferem apenas no caso.
Martijn Pieters
0

Se você usa sql nativo, pode consultar meu código, caso contrário, ignore minha resposta.

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
fonte