2013-04-23 17 views
11

Próbuję wykonać proste działanie filtru na kwerendzie w SQLAlchemy, tak:SQLAlchemy operator filtr in_

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

gdzie

inall jest listą ciągów genotypy są odwzorowywane na stole : klasy genotypy (object): wprost

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

To wydaje się dość proste do mnie, ale ja dostaję f ollowing błąd podczas wykonywania powyższej kwerendy wykonując 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.

robię filtrowanie nieprawidłowo?

(db jest SQLite)

Odpowiedz

14

Jeśli tabela gdzie otrzymujesz swoje rsid s od jest dostępny w tej samej bazie danych bym użyć subquery przekazać je w zapytaniu Genotypes zamiast przekazując milion wpisy w twoim kodzie Pythona.

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

Problem jest, że w celu przekazania tej listy do SQLite (lub dowolnej bazy danych, naprawdę), SQLAlchemy musi przejść przez każdego wpisu na swojej klauzuli in jako zmiennej. SQL przekłada grubsza:

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

Poniższa obejście pracował dla mnie:

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

To w zasadzie wymusza kwerendy skompilować jako ciąg przed realizacją, która omija cały zmiennych problemu. Niektóre szczegóły na ten temat są dostępne w dokumentach SQLAlchemy: here.

BTW, jeśli nie używasz SQLite, możesz użyć operatora ANY, aby przekazać obiekt listy jako pojedynczy parametr (zobacz moją odpowiedź na to pytanie here).