What is the difference between IN
and ANY
operator in PostgreSQL?
The working mechanism of both seems to be the same. Can anyone explain this with an example?
(Strictly speaking, IN
and ANY
are Postgres "constructs" or "syntax elements", rather than "operators".)
Logically, quoting the manual:
IN
is equivalent to= ANY
.
But there are two syntax variants of IN
and two variants of ANY
. Details:
IN
taking a set is equivalent to = ANY
taking a set, as demonstrated here:
But the second variant of each is subtly different. The second variant of the ANY
construct takes an array (must be an actual array type), while the second variant of IN
takes a comma-separated list of values. This leads to different restrictions in passing values and can also lead to different query plans in special cases:
- Index not used with
=any()
but used within
- Pass multiple sets or arrays of values to a function
- How to match elements in an array of composite type?
ANY
is more versatile
The ANY
construct is far more versatile, as it can be combined with various operators, not just =
. Example:
SELECT 'foo' LIKE ANY('{FOO,bar,%oo%}');
For a big number of values, providing a set scales better for each:
Related:
Inversion / opposite / exclusion
"Find rows where id
is in the given array":
SELECT * FROM tbl WHERE id = ANY (ARRAY[1, 2]);
Inversion: "Find rows where id
is not in the array":
SELECT * FROM tbl WHERE id <> ALL (ARRAY[1, 2]);
SELECT * FROM tbl WHERE id <> ALL ('{1, 2}'); -- equivalent array literal
SELECT * FROM tbl WHERE NOT (id = ANY ('{1, 2}'));
All three equivalent. The first with ARRAY constructor, the other two with array literal. The type of the untyped array literal is derived from (known) element type to the left.
In other constellations (typed array value / you want a different type / ARRAY constructor for a non-default type) you may need to cast explicitly.
Rows with id IS NULL
do not pass either of these expressions. To include NULL
values additionally:
SELECT * FROM tbl WHERE (id = ANY ('{1, 2}')) IS NOT TRUE;
SELECT * from mytable where id in (1, 2, 3)
will always result in the same rows as SELECT * from mytable where id = ANY('{1, 2, 3}')
, even if they potentially might have different query plans. –
Kelbee ANY
cannot be combined with the !=
operator. I don't think it's documented, but select * from foo where id != ANY (ARRAY[1, 2])
is not the same as select * from foo where id NOT IN (1, 2)
. On the other hand, select * from foo where NOT (id = ANY (ARRAY[1, 2]))
works as expected. –
Quadruplicate ANY
can be combined with the !=
operator. But there is more to it. I added a chapter above. (Note that <>
is the operator in standard SQL - though !=
is accepted as well in Postgres.) –
Disingenuous NULL
values work? Would WHERE id = ANY (ARRAY[1, 2]) OR id IS NULL;
work just as well? –
Pluralism (id = ...) IS NOT TRUE
works because id = ...
only evaluates to TRUE
if there is an actual match. Outcomes FALSE
or NULL
pass our test. See: https://mcmap.net/q/28734/-best-way-to-check-for-quot-empty-or-null-value-quot. Your added expression tests for something else. This would be equivalent WHERE id <> ALL (ARRAY[1, 2]) OR id IS NULL;
–
Disingenuous =ANY('{1, 2, 3}')
, but I just tried to do both WHERE key = ANY ('{1, 3, 5, ...49}')
as well as WHERE key IN (1, 3, 5, ...49)
on a big table and the EXPLAIN
output is absolutely the same and it uses index scan. Even more, it says =ANY
in the explain output even for IN
. I'm on PostgreSQL 12.4 –
Chokecherry It's said that index is not used ...
? I am not saying anything of the sort. If you mean "Index not used with =any() but used with in", that's just the title of a related question - linking to my related answer. –
Disingenuous NOT IN
. I'll have to test. But not now ... –
Disingenuous There are two obvious points, as well as the points in the other answer:
They are exactly equivalent when using sub queries:
SELECT * FROM table WHERE column IN(subquery); SELECT * FROM table WHERE column = ANY(subquery);
On the other hand:
Only the
IN
operator allows a simple list:SELECT * FROM table WHERE column IN(… , … , …);
Presuming they are exactly the same has caught me out several times when forgetting that ANY
doesn’t work with lists.
WHERE id = ANY(array[1,2])
works. –
Medico WHERE id = ANY(array(<subquery>))
–
Pisano 'in'
is syntaxis sugar, you can take a look to plan analyse and will see that 'in'
will be transform to =ANY('...,...')::yourType[]
IN
constraint (values from a subquery), but when I switched to an = ANY(array(<subquery>))
the same query took a couple hundred milliseconds. The query plan definitely changed. PG 12.3 –
Pisano © 2022 - 2024 — McMap. All rights reserved.