SQLAlchemy IN clause
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.
Introduction
In SQLAlchemy, the SQL IN clause is expressed with the .in_() method. You use it when a column should match any value from a list, tuple, subquery, or other selectable source.
Basic ORM Example
With a mapped model:
This generates SQL conceptually similar to:
The same pattern works with string columns, enums, and other comparable types.
Core Table Example
You do not need the ORM to use IN. SQLAlchemy Core looks similar:
The important idea is the same: call .in_(...) on the column expression.
Use not_in Logic with ~
To express NOT IN, invert the expression:
That is the normal SQLAlchemy style for negating the IN predicate.
IN with a Subquery
The right-hand side does not have to be a Python list. It can also be a subquery:
This corresponds to the SQL pattern:
This is useful when the membership set comes from the database itself.
Empty Lists Need Attention
An important edge case is an empty Python list:
SQLAlchemy handles this case safely, but the resulting query will be designed to match no rows. That is usually correct behavior, though it can surprise people who expected a syntax error or special-case handling.
Sometimes it is still clearer to branch explicitly in application code if an empty list means "skip the query entirely."
Performance Considerations
Small IN lists are common and fine. Very large lists can make queries bulky and sometimes slower, depending on the database. If the list is extremely large, alternatives may be better:
- temporary tables
- joins
- bulk-loaded staging tables
So .in_() is great for ordinary filtering, but not automatically the best answer for massive membership sets.
SQLAlchemy Still Uses Bound Parameters
One advantage of .in_() is that you stay inside SQLAlchemy's normal parameter handling instead of building SQL strings manually. That keeps the query safer and more portable across database backends.
So even though the generated SQL looks familiar, it is still being built through SQLAlchemy expressions rather than string concatenation.
Common Pitfalls
The biggest pitfall is forgetting the underscore and writing .in(...) instead of .in_(...). In SQLAlchemy, the method name is in_.
Another common mistake is building raw SQL strings manually instead of using bound parameters through SQLAlchemy expressions. .in_() lets SQLAlchemy handle that safely.
People also overlook the empty-list case. Even though SQLAlchemy handles it, you should still decide whether "no values" means "no rows" or "skip this filter" in your application logic.
That decision is business logic, not only SQL syntax, and making it explicit usually keeps query code easier to reason about.
Summary
- Use
.in_(...)to express a SQLINcondition in SQLAlchemy. - The right-hand side can be a Python sequence or a subquery.
- Negate it with
~column.in_(...)forNOT IN. - Empty lists are handled safely but still deserve explicit application-level thought.
- For very large value sets, consider whether a join or staging table would be more efficient.
Related reading
- SQLAlchemy ORDER BY DESCENDING?
- SQLAlchemy print the actual query
- sqlalchemy unique across multiple columns
- SQLAlchemy What's the difference between flush and commit?
- sqlite3.ProgrammingError Incorrect number of bindings supplied. The current statement uses 1, and there are 74 supplied
- SSL InsecurePlatform error when using Requests package
- sqlalchemy.exc.NoSuchModuleError Can't load plugin sqlalchemy.dialectspostgres
- SqlCommand Close and Dispose - which to call?

System Design Fundamentals
Build a strong foundation in designing scalable, reliable distributed systems.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.