SQLAlchemy'de VEYA kullanma


191

Dokümanlar üzerinden baktım ve nasıl SQLAlchemy bir OR sorgusu yapmak öğrenmek için görünmüyor. Sadece bu sorguyu yapmak istiyorum.

SELECT address FROM addressbook WHERE city='boston' AND (lastname='bulger' OR firstname='whitey')

Gibi bir şey olmalı

addr = session.query(AddressBook).filter(City == "boston").filter(????)

Yanıtlar:


322

Gönderen öğretici :

from sqlalchemy import or_
filter(or_(User.name == 'ed', User.name == 'wendy'))

72
Bu yaklaşımın jeneratörleri kullanmayı desteklediğini unutmayın, bu nedenle VEYA için uzun bir listeniz varsa yapabilirsinizfilter(or_(User.name == v for v in ('Alice', 'Bob', 'Carl')))
robru

66
@ Robru'nun tavsiyesi gereksiz yere verimsizdir. Zaten bir koleksiyonunuz varsa, in_operatörü şu şekilde kullanmalısınız :filter(User.name.in_(['Alice', 'Bob', 'Carl']))
intgr

5
Ah teşekkürler ben sqlalchemy bu filtre vardı farkında değildi
robru

8
@intgr inru yerine başka bir operatör, örneğin LIKE operatörü kullanmak istiyorsanız, robru tarafından gösterilen örnek hala etkilidir.
Lhassan Baazzi

2
@intgr Oracle ile yaşadığım deneyim "OR" dizisinin "IN" kullanmaktan çok daha hızlı olduğunu gösteriyor. Ayrıca "IN" ~ 1000 giriş kümesi ile sınırlıdır, ancak "OR" ile sınırlı değildir.
ga

321

SQLAlchemy bitsel operatörleri boğan &, |ve ~böylece yerine çirkin ve zor okuma önek sözdizimi ile or_()ve and_()(olduğu gibi Bastien cevabı ) Bu kullanabilirsiniz:

.filter((AddressBook.lastname == 'bulger') | (AddressBook.firstname == 'whitey'))

Bitsel işleçlerin önceliği nedeniyle parantezlerin isteğe bağlı olmadığını unutmayın .

Yani tüm sorgunuz şöyle görünebilir:

addr = session.query(AddressBook) \
    .filter(AddressBook.city == "boston") \
    .filter((AddressBook.lastname == 'bulger') | (AddressBook.firstname == 'whitey'))

8
+1, ancak bunun yerine, son iki filtre bağımsız değişkenini daha fazla parantez içine alabilir ve aynı etki için &bunlarla ilk arasında (ikinci filterçağrı kullanmak yerine ) kullanabilir misiniz?
Chase Sandmann

21
@ChaseSandmann: Evet yapabilirsin. Ama daha okunabilir olur mu? Hayır.
ThiefMaster

1
Yanıt olarak burada SQLAlchemy belgelerine bir bağlantı olması harika olurdu!
Cheche

@ThiefMaster Takma adınızın hırsız içerdiğine ve örneğinizde Whitey Bulger'a mı rastladınız ?
TheRealChx101

36

or_() işlevinin bilinmeyen sayıda OR sorgu bileşeni olması durumunda faydalı olabilir.

Örneğin, birkaç isteğe bağlı filtreye sahip bir REST hizmeti oluşturduğumuzu varsayalım, bu filtrelerden herhangi biri doğruysa kayıt döndürmelidir. Diğer tarafta, parametre bir istekte tanımlanmadıysa, sorgumuz değişmemelidir. or_()İşlev olmadan böyle bir şey yapmalıyız:

query = Book.query
if filter.title and filter.author:
    query = query.filter((Book.title.ilike(filter.title))|(Book.author.ilike(filter.author)))
else if filter.title:
    query = query.filter(Book.title.ilike(filter.title))
else if filter.author:
    query = query.filter(Book.author.ilike(filter.author))

İle or_()işleve bunun için tekrar yazılabilir:

query = Book.query
not_null_filters = []
if filter.title:
    not_null_filters.append(Book.title.ilike(filter.title))
if filter.author:
    not_null_filters.append(Book.author.ilike(filter.author))

if len(not_null_filters) > 0:
    query = query.filter(or_(*not_null_filters))

1
Çok yararlı cevap
Ray Toal

3

Bu gerçekten yardımcı oldu. İşte herhangi bir tablo için benim uygulama:

def sql_replace(self, tableobject, dictargs):

    #missing check of table object is valid
    primarykeys = [key.name for key in inspect(tableobject).primary_key]

    filterargs = []
    for primkeys in primarykeys:
        if dictargs[primkeys] is not None:
            filterargs.append(getattr(db.RT_eqmtvsdata, primkeys) == dictargs[primkeys])
        else:
            return

    query = select([db.RT_eqmtvsdata]).where(and_(*filterargs))

    if self.r_ExecuteAndErrorChk2(query)[primarykeys[0]] is not None:
        # update
        filter = and_(*filterargs)
        query = tableobject.__table__.update().values(dictargs).where(filter)
        return self.w_ExecuteAndErrorChk2(query)

    else:
        query = tableobject.__table__.insert().values(dictargs)
        return self.w_ExecuteAndErrorChk2(query)

# example usage
inrow = {'eqmtvs_id': eqmtvsid, 'datetime': dtime, 'param_id': paramid}

self.sql_replace(tableobject=db.RT_eqmtvsdata, dictargs=inrow)

Üzgünüm küçük bir hata yaptım, aşağıdaki satırı değiştirin: query = select ([tableobject]). Nerede (ve _ (* filterargs))
delpozov
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.