sqlalchemy filtruje wiele kolumn

82

Jak połączyć dwie kolumny i zastosować filtr? Na przykład chcę wyszukiwać w obu kolumnach „imię” i „nazwisko” w tym samym czasie. Oto, jak to robiłem, przeszukując tylko jedną kolumnę:

query = meta.Session.query(User).filter(User.firstname.like(searchVar))
teggy
źródło
4
Myślałem, że to pytanie pasuje do problemu, który mam, ale odpowiedzi nie dotyczą mojego konkretnego scenariusza. Jeśli firstname to „joe”, a lastname to „smith”, szukam instrukcji filtru, która będzie pasować, gdy podana wartość searchVar to „joe smith”. Oznacza to, że pola należy połączyć (z dodaną spacją) przed wykonaniem testu. Wydaje się, że scenariusz bardzo realny.
Groovee60
1
@ Groovee60 To jest dokładnie to, czego szukam. Byłbym wdzięczny, gdybyś mógł udostępnić swoje rozwiązanie, jeśli takie znalazłeś.
Lilylakshi

Odpowiedzi:

84

Można to zrobić na kilka sposobów:

Korzystanie filter()( i operator)

query = meta.Session.query(User).filter(
    User.firstname.like(search_var1),
    User.lastname.like(search_var2)
    )

Korzystanie filter_by()( i operator)

query = meta.Session.query(User).filter_by(
    firstname.like(search_var1),
    lastname.like(search_var2)
    )

Łańcuch filter()lub filter_by()( i operator)

query = meta.Session.query(User).\
    filter_by(firstname.like(search_var1)).\
    filter_by(lastname.like(search_var2))

Korzystanie or_(), and_()oraznot()

from sqlalchemy import and_, or_, not_

query = meta.Session.query(User).filter(
    and_(
        User.firstname.like(search_var1),
        User.lastname.like(search_var2)
    )
)
Vlad Bezden
źródło
2
Czy są jakieś godne uwagi różnice w wydajności dla tych różnych podejść?
Miek
2
Większość różnych podejść kończy się generowaniem tego samego zapytania, więc w większości przypadków nie zobaczysz różnicy w wydajności.
Asa Stallard
Jestem nieco zdezorientowany. W filter_bydocs powiedzieć , że jest to argument za filtrowanie słów kluczowych: query(Foo).filter_by(bar='baz'). Jak to się ma do składni, której użyłeś w swojej odpowiedzi powyżej?
tel
76

Możesz po prostu zadzwonić filterwiele razy:

query = meta.Session.query(User).filter(User.firstname.like(searchVar1)). \
                                 filter(User.lastname.like(searchVar2))
David Johnstone
źródło
36
czy jest jakaś różnica w wydajności między używaniem wielu filter()metod a użyciem kombinacji wielu warunków (przez or_lub and_) w jednym filter, na dużych tabelach mysql?
exAres
6
Czy wiele filterpołączeń działałoby jak logiczne, ANDa nie OR?
danodonovan
6
Nie sądzę - kiedy spojrzysz na str (User.filter (cond1) .filter (cond2)) generuje końcowy sql z tylko warunkami "i" ed.
Shankar ARUL
60

Możesz użyć or_funkcji SQLAlchemy do wyszukiwania w więcej niż jednej kolumnie (podkreślenie jest konieczne, aby odróżnić ją od własnej w Pythonie or).

Oto przykład:

from sqlalchemy import or_
query = meta.Session.query(User).filter(or_(User.firstname.like(searchVar),
                                            User.lastname.like(searchVar)))
gclj5
źródło
7
Możesz użyć |operatora zamiast or_, w ten sposób - (User.firstname.like(searchVar)) | (User.lastname.like(searchVar))jednak powinieneś uważać na |pierwszeństwo, bez nawiasów może to dać BARDZO nieoczekiwane wyniki, gdy zostanie zmieszane z operatorami porównania.
Daniel Kluev
1
Nie powinno być filter.or_( case1, case 2)?
fedorqui 'SO przestać szkodzić'
2
To jest złe, ponieważ pytanie dotyczy ORM, ale link prowadzi do wyrażeń.
user2846569
1
Używałem wielu instrukcji filtrujących, przed którymi dramatycznie zwiększyło się opóźnienie. Zmieniłem to na or_ i wraca DUŻO szybciej. Dziękuję @ gclj5
Jimmy,
2

Ogólny fragment kodu, który będzie działał dla wielu kolumn. Można to również wykorzystać, jeśli istnieje potrzeba warunkowego zaimplementowania funkcji wyszukiwania w aplikacji.

search_key = "abc"
search_args = [col.ilike('%%%s%%' % search_key) for col in ['col1', 'col2', 'col3']]
query = Query(table).filter(or_(*search_args))
session.execute(query).fetchall()

Zanotuj %% ważne jest, aby pominąć% formatowania zapytania.

Azharullah Shariff
źródło