¿Cuál es la diferencia entre el operador INy ANYen PostgreSQL?
El mecanismo de trabajo de ambos parece ser el mismo. ¿Alguien puede explicar esto con un ejemplo?
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:
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 literalSELECT*FROM tbl WHERENOT(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:
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
ANYno 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:
Respuestas:
(Ni
INtampocoANYes un "operador". Un "constructo" o "elemento de sintaxis").Lógicamente , citando el manual :
Pero hay dos variantes de sintaxis
INy dos variantes deANY. Detalles:INtomar 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 deINtoma 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()pero usado coninANYes más versátilLa
ANYconstrucción es mucho más versátil, ya que se puede combinar con varios operadores, no solo=. Ejemplo: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":Inversión: "Buscar filas donde no
idestá en la matriz":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 incluirNULLvalores adicionalmente:fuente
SELECT * from mytable where id in (1, 2, 3)siempre dará como resultado las mismas filas queSELECT * from mytable where id = ANY('{1, 2, 3}'), incluso si potencialmente podrían tener diferentes planes de consulta.ANYno se puede combinar con el!=operador. No creo que esté documentado, peroselect * from foo where id != ANY (ARRAY[1, 2])no es lo mismo queselect * 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.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.)NULLvalores? ¿WHERE id = ANY (ARRAY[1, 2]) OR id IS NULL;Funcionaría igual de bien?(id = ...) IS NOT TRUEfunciona porqueid = ...solo evalúaTRUEsi hay una coincidencia real. ResultadosFALSEoNULLpasar 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;Hay dos puntos obvios, así como los puntos de la otra respuesta:
Son exactamente equivalentes cuando se utilizan subconsultas:
Por otra parte:
Solo el
INoperador permite una lista simple:Suponer que son exactamente iguales me ha sorprendido varias veces al olvidar que
ANYno funciona con listas.fuente