2011-10-30 8 views
119

Ho guardato through the docs e non riesco a scoprire come eseguire una query OR in SQLAlchemy. Voglio solo fare questa domanda.Utilizzo di OR in SQLAlchemy

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

dovrebbe essere qualcosa come

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

risposta

200

Dal tutorial:

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

Si noti che questo approccio supporta l'utilizzo di generatori, quindi se avete una lunga lista di cose da O, si può fare 'filtro (or_ (User.name == v per v in ('Alice', 'Bob', 'Carl'))) ' – robru

+20

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

+2

Ah grazie non ne ero a conoscenza sqlalchemy aveva quel filtro – robru

229

SQLAlchemy sovraccarica gli operatori bit per bit &, | e ~ così invece del brutto e difficile da leggere sintassi del prefisso con or_() e and_() (come in Bastien's answer) è possibile utilizzare questi operatori:

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

Nota che le parentesi sono non facoltativo a causa della precedenza degli operatori bit a bit.

Così tutta la vostra richiesta potrebbe essere la seguente:

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 del filtro in più parentesi e usare un '&' tra loro e il primo (piuttosto che usare una seconda chiamata 'filter') per lo stesso effetto? –

+13

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

17

operatore or_ può essere utile in caso di numero imprecisato di OR componenti di query.

Ad esempio, supponiamo di creare un servizio REST con pochi filtri opzionali, che dovrebbe restituire un record se uno qualsiasi dei filtri restituisce true. Dall'altro lato, se il parametro non è stato definito in una richiesta, la nostra query non dovrebbe cambiare. Senza or_ funzione dobbiamo fare qualcosa di simile:

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 or_ funzione può essere riscritto per:

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

Questo è stato molto utile. Qui è la mia applicazione per ogni 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) 
+0

Spiacente ho fatto un piccolo errore, come la seguente riga: query = select ([tableobject]). Where (and _ (* filterargs)) – delpozov

Problemi correlati