IN vs CUALQUIER operador en PostgreSQL

Respuestas:

158

(Ni INtampoco ANYes un "operador". Un "constructo" o "elemento de sintaxis").

Lógicamente , citando el manual :

INes equivalente a = ANY.

Pero hay dos variantes de sintaxisIN y dos variantes de ANY. Detalles:

IN tomar un conjunto es equivalente a = ANYtomar un conjunto , como se demuestra aquí:

Pero la segunda variante de cada uno no es equivalente a la otra. La segunda variante de la ANYconstrucción toma una matriz (debe ser un tipo de matriz real), mientras que la segunda variante de INtoma una lista de valores separados por comas . Esto conduce a diferentes restricciones al pasar valores y también puede conducir a diferentes planes de consulta en casos especiales:

ANY es más versátil

La ANYconstrucción es mucho más versátil, ya que se puede combinar con varios operadores, no solo =. Ejemplo:

SELECT 'foo' LIKE ANY('{FOO,bar,%oo%}');

Para una gran cantidad de valores, proporcionar un conjunto de escalas mejor para cada uno:

Relacionado:

Inversión / opuesto / exclusión

"Encuentra filas donde idestá en la matriz dada":

SELECT * FROM tbl WHERE id = ANY (ARRAY[1, 2]);

Inversión: "Buscar filas donde noid está en la matriz":

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}'));

Los tres equivalentes. El primero con el constructor de matriz , los otros dos con literal de matriz . El tipo de datos puede derivarse del contexto sin ambigüedades. De lo contrario, es posible que se requiera un elenco explícito, como'{1,2}'::int[] .

Las filas con id IS NULLno pasan ninguna de estas expresiones. Para incluir NULLvalores adicionalmente:

SELECT * FROM tbl WHERE (id = ANY ('{1, 2}')) IS NOT TRUE;
Erwin Brandstetter
fuente
4
Sería bueno aclarar explícitamente que los resultados de las segundas variantes siempre serán los mismos. Estoy 99% seguro de que ese es el caso, pero la respuesta no parece indicarlo. Lo que significa que SELECT * from mytable where id in (1, 2, 3)siempre dará como resultado las mismas filas que SELECT * from mytable where id = ANY('{1, 2, 3}'), incluso si potencialmente podrían tener diferentes planes de consulta.
KPD
1
ANY no se puede combinar con el !=operador. No creo que esté documentado, pero select * from foo where id != ANY (ARRAY[1, 2])no es lo mismo que select * from foo where id NOT IN (1, 2). Por otro lado, select * from foo where NOT (id = ANY (ARRAY[1, 2]))funciona como se esperaba.
qris
1
@qris: ANYse puede combinar con el !=operador. Pero hay más. Agregué un capítulo arriba. (Tenga en cuenta que <>es el operador en SQL estándar, aunque también !=se acepta en Postgres.)
Erwin Brandstetter
¿Cómo funciona la última versión que incluye NULLvalores? ¿ WHERE id = ANY (ARRAY[1, 2]) OR id IS NULL;Funcionaría igual de bien?
Dvtan
1
@dvtan: (id = ...) IS NOT TRUEfunciona porque id = ...solo evalúa TRUEsi hay una coincidencia real. Resultados FALSEo NULLpasar nuestra prueba. Consulte: stackoverflow.com/a/23767625/939860 . Tus pruebas de expresión agregadas para otra cosa. Esto sería equivalenteWHERE id <> ALL (ARRAY[1, 2]) OR id IS NULL;
Erwin Brandstetter
3

Hay dos puntos obvios, así como los puntos de la otra respuesta:

  • Son exactamente equivalentes cuando se utilizan subconsultas:

    SELECT * FROM table
    WHERE column IN(subquery);
    
    SELECT * FROM table
    WHERE column = ANY(subquery);

Por otra parte:

  • Solo el INoperador permite una lista simple:

    SELECT * FROM table
    WHERE column IN(… ,  , …);

Suponer que son exactamente iguales me ha sorprendido varias veces al olvidar que ANYno funciona con listas.

Manngo
fuente