2013-04-23 13 views
11

Sto cercando di fare un'operazione semplice filtro su una query in SQLAlchemy, in questo modo:SQLAlchemy operatore di filtro IN_

q = session.query(Genotypes).filter(Genotypes.rsid.in_(inall)) 

dove

inall è una lista di stringhe genotipi è mappato a un tavolo : genotipi di classe (oggetto): passaggio

Genotypes.mapper = mapper(Genotypes, kg_table, properties={'rsid': getattr(kg_table.c, 'rs#')}) 

Questo sembra abbastanza semplice per me, ma ho la f Errore di opo quando eseguo la query precedente facendo q.first():

"sqlalchemy.exc.OperationalError: (OperationalError) too many SQL variables u'SELECT" followed by a list of the 1M items in the inall list. But they aren't supposed to be SQL variables, just a list whose membership is the filtering criteria.

sto facendo il filtraggio in modo errato?

(il db è sqlite)

risposta

14

Se la tabella dove hai trovato i tuoi rsid s da è disponibile nello stesso database userei un subquery di passare loro nella vostra Genotypes richiesta, piuttosto che passare il milione voci in giro nel tuo codice Python.

sq = session.query(RSID_Source).subquery() 
q = session.query(Genotypes).filter(Genotypes.rsid.in_(sq)) 

Il problema è che, al fine di trasmettere tale elenco per SQLite (o qualsiasi database, in realtà), SQLAlchemy deve passare su ogni voce per il in clausola come una variabile. Lo SQL traduce approssimativamente:

-- Not valid SQLite SQL 
DECLARE @Param1 TEXT; 
SET @Param1 = ?; 
DECLARE @Param2 TEXT; 
SET @Param2 = ?; 
-- snip 999,998 more 

SELECT field1, field2, -- etc. 
FROM Genotypes G 
WHERE G.rsid IN (@Param1, @Param2, /* snip */) 
1

La soluzione qui di seguito ha funzionato per me:

q = session.query(Genotypes).filter(Genotypes.rsid.in_(inall)) 
query_as_string = str(q.statement.compile(compile_kwargs={"literal_binds": True})) 
session.execute(query_as_string).first() 

Questo costringe in sostanza la query per compilare come una stringa prima dell'esecuzione, che bypassa l'intera questione variabili. Alcuni dettagli su questo sono disponibili nei documenti di SQLAlchemy here.

BTW, se non si utilizza SQLite è possibile utilizzare l'operatore ANY per passare l'oggetto elenco come un singolo parametro (vedere la risposta a questa domanda here).

Problemi correlati