SQLAlchemy odpowiednik instrukcji SQL „LIKE”

85

Kolumna tagów zawiera wartości takie jak „jabłko-banan-pomarańcza” i „truskawka-banan-cytryna”. Chcę znaleźć równoważną instrukcję SQLAlchemy

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

Co mam przejść, aby Class.query.filter()to zrobić?

Gary Oldfaber
źródło

Odpowiedzi:

173

Każda kolumna ma like()metodę, której można użyć w query.filter(). Mając wyszukiwany ciąg, dodaj %znak po obu stronach, aby wyszukiwać jako podciąg w obu kierunkach.

tag = request.form["tag"]
search = "%{}%".format(tag)
posts = Post.query.filter(Post.tags.like(search)).all()
Daniel Kluev
źródło
1
Idealny! Czy wiesz, czy istnieje lepszy sposób na odróżnienie jabłka od ananasa niż dodanie spacji wiodącej?
Gary Oldfaber
3
Najlepszym sposobem byłoby po prostu znormalizowanie bazy danych i dodanie 2 oddzielnych tabel dla tagów i relacji tag-zadanie, a następnie użycie JOIN zamiast LIKE. W przeciwnym razie tak, wydaje się, że będziesz musiał mieć jakiś separator wokół każdego znacznika w ciągu. Wiodąca przestrzeń nie wystarczy, ponieważ jest też długopis i ołówek, z% pióra%. Jeśli zrobisz coś w stylu „| jabłko | ananas | długopis | ołówek |” i dopasuj "% | pen |%" to nie powinno kolidować.
Daniel Kluev
1
W przypadku normalizacji nie jestem do końca pewien, w jaki sposób będę miał więcej niż jeden tag powiązany z danym zadaniem lub odwrotnie, używając mapy tagów. Wydaje się, że rozwiązanie „Toxi” grupuje kolekcję tagów jako pojedynczy element, zamiast przechowywać je oddzielnie? Wydaje się, że metoda zastosowana w tym przepisie ( elixir.ematia.de/trac/wiki/Recipes/TagCloud ) zezwala tylko na jeden tag na element. Jakie zasoby byłyby najlepsze do wyjaśnienia tego tematu? Przeczytałem to ( dev.mysql.com/tech-resources/articles/ ... ), ale nie potrafię sobie wyobrazić, jak zarządzać wieloma tagami.
Gary Oldfaber
2
Jak powiedziałem, potrzebujesz dwóch tabel. Zasadniczo jest to po prostu typowa relacja wiele do wielu, więc możesz postępować zgodnie z przewodnikiem SQLAlchemy na ten temat: sqlalchemy.org/docs/ ... Będziesz mieć tagstabelę, w której będziesz przechowywać nazwę znacznika i inne informacje o znaczniku, a także task_tagstabelę, która będzie miał jeden rekord dla każdego tagu dodanego do zadania. Zatem zadanie z 2 tagami będzie miało tylko 2 rekordy w task_tagstabeli.
Daniel Kluev
11

Dodając do powyższej odpowiedzi, ktokolwiek szuka rozwiązania, możesz również spróbować operatora „dopasuj” zamiast „lubię”. Nie chcę być stronniczy, ale w Postgresql to działało idealnie.

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

Dziedziczy funkcje bazy danych, takie jak CONTAINS i MATCH . Jednak nie jest dostępny w SQLite.

Więcej informacji można znaleźć w sekcji Wspólne operatory filtrów

igsm
źródło
8
Jaka jest różnica między tymi dwoma operatorami?
buhtz
@buhtz zależy od twojego zaplecza DB, zobacz SQL-Alchemy docs: docs.sqlalchemy.org/en/14/core/… W Postgres otrzymujesz, to_tsqueryktóry pozwala dodawać operatory tekstowe dla rzeczy takich jak ORi AND postgresql.org/docs/current/ ...
Nick
7

wypróbuj ten kod

output = dbsession.query(<model_class>).filter(<model_calss>.email.ilike('%' + < email > + '%'))
waruna k
źródło
1

Korzystanie z PostgreSQL like( Akceptowane odpowiedź powyżej ) jakoś nie działa na mnie chociaż przypadki dopasowane , ale ilike(przypadek I nsensisitive jak ) robi.

konstantin
źródło
2
ILIKEjest wersją programu bez rozróżniania wielkości liter LIKE, więc dane wejściowe różniły się tylko w przypadku.
Martijn Pieters
0

Jeśli używasz natywnego sql, możesz odwołać się do mojego kodu, w przeciwnym razie po prostu zignoruj ​​moją odpowiedź.

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
źródło