Test whether a value matches any value in a list or subquery. IN is shorthand for multiple OR equality conditions; NOT IN is the negation.
Tests whether a value matches any value in a list or subquery result, evaluating to TRUE if a match is found. IN is more readable than multiple OR conditions and often optimized similarly to EXISTS. Subqueries in IN can be slow with large result sets.
| Database System | Support Status | Since Version | Notes |
|---|---|---|---|
| MySQL | ✓ Supported | all | Standard IN/NOT IN. Key gotcha: NOT IN with a subquery that returns any NULL will return no rows — because NULL != anything is UNKNOWN, not FALSE. Use NOT EXISTS instead when the subquery might return NULLs. IN list size is limited by max_allowed_packet. |
| PostgreSQL | ✓ Supported | all | Standard IN/NOT IN. Same NULL trap: NOT IN with a NULL in the list or subquery returns no rows. Use NOT EXISTS for safety. PostgreSQL also supports = ANY(array) and <> ALL(array) as alternatives. IN with large static lists can be slower than = ANY(ARRAY[...]). |
| SQL Server | ✓ Supported | all | Standard IN/NOT IN. Same NULL trap with NOT IN. No array type, so = ANY(array) is not available. IN list maximum is not explicitly documented but very large lists may cause parameter sniffing issues — a table variable or temp table is better for lists over ~1000 values. |
| Oracle | ✓ Supported | all | Standard IN/NOT IN. Same NULL trap. IN list is limited to 1000 elements per expression — a hard limit. For larger lists, use IN with a subquery or a collection type. NOT EXISTS is recommended over NOT IN for correlated subqueries. |
| SQLite | ✓ Supported | all | Standard IN/NOT IN. Same NULL trap with NOT IN. No array type. IN with a subquery is fully supported. No hard limit on IN list size (subject to SQLITE_MAX_VARIABLE_NUMBER, default 999 bound parameters). |
The NULL trap is the universal gotcha: NOT IN (subquery) returns zero rows if the subquery returns any NULL. This affects all engines identically. Use NOT EXISTS instead of NOT IN when the list or subquery may contain NULLs. Oracle's hard 1000-element IN list limit is unique and produces a runtime error, not a compile-time warning.
Standard IN/NOT IN. Key gotcha: NOT IN with a subquery that returns any NULL will return no rows — because NULL != anything is UNKNOWN, not FALSE. Use NOT EXISTS instead when the subquery might return NULLs. IN list size is limited by max_allowed_packet.
Standard IN/NOT IN. Same NULL trap: NOT IN with a NULL in the list or subquery returns no rows. Use NOT EXISTS for safety. PostgreSQL also supports = ANY(array) and <> ALL(array) as alternatives. IN with large static lists can be slower than = ANY(ARRAY[...]).
Standard IN/NOT IN. Same NULL trap with NOT IN. No array type, so = ANY(array) is not available. IN list maximum is not explicitly documented but very large lists may cause parameter sniffing issues — a table variable or temp table is better for lists over ~1000 values.
Standard IN/NOT IN. Same NULL trap. IN list is limited to 1000 elements per expression — a hard limit. For larger lists, use IN with a subquery or a collection type. NOT EXISTS is recommended over NOT IN for correlated subqueries.
Standard IN/NOT IN. Same NULL trap with NOT IN. No array type. IN with a subquery is fully supported. No hard limit on IN list size (subject to SQLITE_MAX_VARIABLE_NUMBER, default 999 bound parameters).