次のように、sqlalchemyのクエリで簡単なフィルター操作を実行しようとしています。
_q = session.query(Genotypes).filter(Genotypes.rsid.in_(inall))
_
どこ
inallは、Genotypesがテーブルにマップされている文字列のリストです:クラスGenotypes(object):pass
_Genotypes.mapper = mapper(Genotypes, kg_table, properties={'rsid': getattr(kg_table.c, 'rs#')})
_
これは私には簡単に思えますが、q.first()
を実行して上記のクエリを実行すると、次のエラーが発生します。
"sqlalchemy.exc.OperationalError:(OperationalError)SQL変数が多すぎるu'SELECT"に続いて、inallリスト内の1Mアイテムのリスト。しかし、それらはSQL変数ではなく、メンバーシップがフィルタリング基準であるリストにすぎません。
フィルタリングを正しく行っていませんか?
(dbはsqliteです)
rsid
sを取得するテーブルが同じデータベースで使用可能な場合、 subquery を使用して、それらをGenotypes
クエリに渡すのではなく、 Pythonコード内の100万エントリ。
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 */)
以下の回避策は私のために働きました:
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のドキュメント here にあります。
ところで、SQLiteを使用していない場合は、ANY演算子を使用して、リストオブジェクトを単一のパラメーターとして渡すことができます(この質問に対する私の回答をご覧ください here )。