¿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
IN
tampocoANY
es un "operador". Un "constructo" o "elemento de sintaxis").Lógicamente , citando el manual :
Pero hay dos variantes de sintaxis
IN
y dos variantes deANY
. Detalles:IN
tomar un conjunto es equivalente a= ANY
tomar un conjunto , como se demuestra aquí:Pero la segunda variante de cada uno no es equivalente a la otra. La segunda variante de la
ANY
construcción toma una matriz (debe ser un tipo de matriz real), mientras que la segunda variante deIN
toma 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 conin
ANY
es más versátilLa
ANY
construcció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
id
está en la matriz dada":Inversión: "Buscar filas donde no
id
está 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 NULL
no pasan ninguna de estas expresiones. Para incluirNULL
valores 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.ANY
no 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.ANY
se 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.)NULL
valores? ¿WHERE id = ANY (ARRAY[1, 2]) OR id IS NULL;
Funcionaría igual de bien?(id = ...) IS NOT TRUE
funciona porqueid = ...
solo evalúaTRUE
si hay una coincidencia real. ResultadosFALSE
oNULL
pasar 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
IN
operador permite una lista simple:Suponer que son exactamente iguales me ha sorprendido varias veces al olvidar que
ANY
no funciona con listas.fuente