Utilizzo di OR in SQLAlchemy


191

Ho esaminato i documenti e non riesco a scoprire come eseguire una query OR in SQLAlchemy. Voglio solo fare questa domanda.

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

Dovrebbe essere qualcosa di simile

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

Risposte:


322

Dal tutorial :

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

72
Nota che questo approccio supporta l'uso di generatori, quindi se hai un lungo elenco di cose da OR, puoi farlofilter(or_(User.name == v for v in ('Alice', 'Bob', 'Carl')))
robru

66
Il consiglio di @ Robru è inutilmente inefficiente. Se hai già una collezione, dovresti usare l' in_operatore in questo modo:filter(User.name.in_(['Alice', 'Bob', 'Carl']))
intgr

5
Ah grazie non sapevo che sqlalchemy avesse quel filtro
robru,

8
@intgr L'esempio mostrato da robru è ancora efficiente, se si desidera utilizzare un altro operatore anziché in_, ad esempio l'operatore LIKE.
Lhassan Baazzi,

2
@intgr La mia esperienza con Oracle mostra che una sequenza di "OR" è molto più veloce dell'uso di "IN". Anche "IN" è limitato a un set di ~ 1000 voci, mentre "OR" no.
ga

321

SQLAlchemy sovraccarica gli operatori bit per bit &, |e ~quindi invece della brutta e difficile sintassi del prefisso con or_()e and_()(come nella risposta di Bastien ) puoi usare questi operatori:

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

Si noti che le parentesi non sono opzionali a causa della precedenza degli operatori bit a bit.

Quindi l'intera query potrebbe apparire così:

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

8
+1, ma potresti invece racchiudere gli ultimi due argomenti di filtro tra più parentesi e utilizzare uno &tra loro e il primo (anziché utilizzare una seconda filterchiamata) per lo stesso effetto?
Chase Sandmann,

21
@ChaseSandmann: Sì, potresti. Ma sarebbe più leggibile? No.
ThiefMaster,

1
Sarebbe bello avere un link ai documenti SQLAlchemy qui in risposta!
Cheche,

@ThiefMaster Coincidenza che il tuo alias contiene ladro e hai Whitey Bulger nel tuo esempio?
TheRealChx101

36

or_() La funzione può essere utile in caso di numero sconosciuto di componenti di query OR.

Ad esempio, supponiamo che stiamo creando un servizio REST con pochi filtri opzionali, che dovrebbe restituire record se uno qualsiasi dei filtri restituisce true. D'altra parte, se il parametro non è stato definito in una richiesta, la nostra query non dovrebbe cambiare. Senza or_()funzione dobbiamo fare qualcosa del genere:

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

Con la or_()funzione può essere riscritto in:

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
Risposta molto utile
Ray Toal,

3

Questo è stato davvero utile. Ecco la mia implementazione per ogni data tabella:

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)

Mi dispiace di aver fatto un piccolo errore, cambiando la seguente riga: query = select ([tableobject]). Where (and _ (* filterargs))
delpozov
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.