I found out that SQLAlchemy translates
db.query(...).filter(A.id.in_(ids))
into
SELECT ...
FROM a
WHERE a.id != a.id
To answer the OP's question of "why", here is the FAQ entry (which is always surprisingly difficult for me to find):
Why does
.col.in_([])producecol != col? Why not1=0?A little introduction to the issue. The
INoperator in SQL, given a list of elements to compare against a column, generally does not accept an empty list, that is while it is valid to say:column IN (1, 2, 3)it’s not valid to say:
column IN ()SQLAlchemy's
Operators.in_()operator, when given an empty list, produces this expression:column != columnAs of version 0.6, it also produces a warning stating that a less efficient comparison operation will be rendered. This expression is the only one that is both database agnostic and produces correct results.
For example, the naive approach of "just evaluate to false, by comparing 1=0 or 1!=1", does not handle nulls properly. An expression like:
NOT column != columnwill not return a row when
column IS NULL, but an expression which does not take the column into account, such as:NOT 1=0will return a row.
As shown in this post, you may be able to use the ANY function to avoid this, since it's syntactically valid even for an empty list (but not supported on SQLite apparently). It's probably faster for large lists too, since it does less string mangling to build the query.
The performance issue with the in_ operator has recently been fixed and the fix will probably be in SQLAlchemy 1.2.0.