What happens when you do a SQL query where the IN
clause is empty?
For example:
SELECT user WHERE id IN ();
Will MySQL
Here is another variation of always false statement for empty lists that preserves both logic and the notion of actual column in the query.
Incorrect id in ()
can be rewritten into:
where id <> id;
Similarly incorrect negative condition id not in ()
can be transformed by custom query building code into:
where id = id;
This approach is safer than id not in (NULL) as it doesn't evaluate to NULL.
But beware that this would filter out of the result the rows where id is null
. This may be considered a feature in some cases.
Espesially useful with complex stacked query building logic where nested builder is not aware how the resulting subquery could be used above.
This gives me 0 results as well:
SELECT id FROM User
WHERE id IN (NULL);
Tried on MYSQL 5.6
If you are using that query in an application and you pass dynamically a list of objects to the query, I should not call to the database to do a select with an impossible value, I should return an empty list without calling to the database query, directly.
Because it has no sense to do a query that you know that is empty before calling it.
The closest approximation of this query with valid syntax is:
SELECT user FROM tbl1 WHERE id IN (SELECT id FROM tbl1 WHERE FALSE);
which unconditionally returns an empty result set. The subquery in the bracket always returns an empty set, and no value can be found in an empty set, since an empty set contains no values.
If you use AUTO_INCREMENT for id (1,2,3, ..) and if array is empty, you can add one item [0]. So it will be
if (empty($arr)) {
$arr[] = 0;
}
SELECT user WHERE id IN (0);
And there will be no mysql parse error. This case is very usefull in subqueries - when your main query is not dependent on subquery results.
Better way - don't call the query if array is empty.
$data = null;
if (!empty($arr)) {
$data = ... call query
}
Use an always false statement
Before creating the SQL, check for the array size.
If the size is 0, generate the where statement as 1 = 2
, as in:
SELECT * FROM USERS WHERE name in ()
becomes
SELECT * FROM USERS WHERE 1 = 2
For "not in" on an empty array, generate an always true statement as in:
SELECT * FROM USERS WHERE name not in ()
becomes
SELECT * FROM USERS WHERE 1 = 1
This should work for more complex queries as:
SELECT * FROM USERS WHERE (name in () OR name = 'Alice')
becomes
SELECT * FROM USERS WHERE (1 = 2 OR name = 'Alice')