Подтвердить что ты не робот

SQLAlchemy filter in_ operator

Я пытаюсь выполнить простую операцию фильтра в запросе в sqlalchemy, например:

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

где

inall - список строк Генотипы сопоставляются с таблицей:   class Genotypes (объект):       передача

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

Это кажется мне довольно простым, но я получаю следующую ошибку, когда выполняю вышеуказанный запрос, выполняя q.first():

"sqlalchemy.exc.OperationalError: (OperationalError) слишком много SQL переменные u'SELECT", а затем список из 1M элементов inallall список. Но они не должны быть переменными SQL, просто список, членство - это критерии фильтрации.

Я неправильно делаю фильтрацию?

(db является sqlite)

4b9b3361

Ответ 1

Если таблица, в которой вы получаете свой rsid, доступна в той же базе данных, я бы использовал subquery для передайте их в свой Genotypes запрос, а не передайте один миллион записей в вашем коде Python.

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

Проблема заключается в том, что для того, чтобы передать этот список SQLite (или любой базе данных), SQLAlchemy должен передать каждую запись для вашего предложения in как переменную. SQL грубо переводит:

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

Ответ 2

Ниже приведено обходное решение:

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

Это в основном заставляет запрос компилироваться как строку перед выполнением, что обходит всю проблему с переменными. Некоторые подробности об этом доступны в документах SQLAlchemy здесь.

Кстати, если вы не используете SQLite, вы можете использовать оператор ANY, чтобы передать объект списка как один параметр (см. мой ответ на этот вопрос здесь).