Compruebe si existe un valor en la matriz de Postgres

196

Usando Postgres 9.0, necesito una forma de probar si existe un valor en una matriz dada. Hasta ahora se me ocurrió algo como esto:

select '{1,2,3}'::int[] @> (ARRAY[]::int[] || value_variable::int)

Pero sigo pensando que debería haber una forma más simple de hacerlo, simplemente no puedo verlo. Esto parece mejor:

select '{1,2,3}'::int[] @> ARRAY[value_variable::int]

Creo que será suficiente. Pero si tiene otras formas de hacerlo, ¡comparta!

Mike Starov
fuente

Respuestas:

323

Más simple con la ANYconstrucción:

SELECT value_variable = ANY ('{1,2,3}'::int[])

El operando correcto de ANY(entre paréntesis) puede ser un conjunto (resultado de una subconsulta, por ejemplo) o una matriz . Hay varias formas de usarlo:

Importante diferencia: (operadores de matriz <@, @>, &&. Et al) esperar matriz tipos como operandos y apoyo GIN o índices GiST en la distribución estándar de PostgreSQL, mientras que el ANYconstructo espera un elemento tipo que deja operando y no admite estos índices. Ejemplo:

Nada de esto funciona para los NULLelementos. Para probar para NULL:

Erwin Brandstetter
fuente
Gracias. Debe haber omitido esa parte del manual. Esto funciona muy bien. Tiene un efecto secundario de fundición automática. Ej: SELECCIONE 1 :: smallint = CUALQUIERA ('{1,2,3}' :: int []) funciona. Solo asegúrate de poner CUALQUIERA () en el lado derecho de la expresión.
Mike Starov
Gracias por la respuesta. Tengo un problema donde mi consulta funcionaba en local, pero en heroku estaba lanzando este mensaje ANY/ALL (array) requires array on right side, el complemento de ::int[]hizo el encanto.
kinduff
donde S.employee_id <@ ANY ('"+ employeeIDsArray +"' :: int []) Esto devuelve PSQLException: ERROR: valor de dimensión faltante
Ramprasad
3
Aunque esta es una pregunta de dinosaurios en los años de Internet, la gente lenta como yo debería ser consciente de que 'something' = ANY(some_array)también se puede usar en una WHEREcláusula. Por razones conocidas solo por Crom, he pasado los últimos cuatro años pensando que no podría usar comparadores de matrices en las WHEREcláusulas. Esos días se han ido ahora. (De niño me cayeron de cabeza, así que tal vez solo soy yo).
GT.
1
@GT .: Lo esencial: cualquier boolean expresión funciona en la WHEREcláusula - Crom dispuesto.
Erwin Brandstetter
90

Tenga cuidado con la trampa en la que me metí: al verificar si cierto valor no está presente en una matriz, no debe hacer lo siguiente:

SELECT value_variable != ANY('{1,2,3}'::int[])

pero usa

SELECT value_variable != ALL('{1,2,3}'::int[])

en lugar.

Murison
fuente
2
Tipo de doble negativo; observe su uso de ALLvsANY
vol7ron
43
SELECT NOT value_variable = ANY('{1,2,3}'::int[])podría ser más legible
Ondřej Bouda
28

pero si tiene otras formas de hacerlo, por favor comparta.

Puedes comparar dos matrices. Si alguno de los valores en la matriz izquierda se superpone a los valores en la matriz derecha, entonces devuelve verdadero. Es un poco hack, pero funciona.

SELECT '{1}'   && '{1,2,3}'::int[];  -- true
SELECT '{1,4}' && '{1,2,3}'::int[];  -- true
SELECT '{4}'   && '{1,2,3}'::int[];  -- false
  • En la primera y segunda consulta, el valor 1está en la matriz correcta
  • Observe que la segunda consulta es true, aunque el valor 4no esté contenido en la matriz correcta
  • Para la tercera consulta, no hay valores en la matriz izquierda (es decir, 4) en la matriz derecha, por lo que devuelvefalse
vol7ron
fuente
¿Cómo puedo buscar una columna de otra tabla para tener un valor en la matriz? por ejemplo, seleccione * de cervezas donde style_id (seleccione las preferencias de los usuarios donde id = 1) limite 1; style_id es un tipo de datos entero; preferencias es entero [] Obtengo este error ERROR: el operador no existe: entero = entero [] LÍNEA 1: seleccione * de cervezas donde style_id (seleccione preferencias f ... ^ SUGERENCIA: Ningún operador coincide con el nombre y tipo de argumento (s). Es posible que deba agregar conversiones de tipo explícito.
HP
@ HP Hay diferentes maneras de resolver esa pregunta, deberías hacer una nueva pregunta
vol7ron
¿Estás seguro de que no hay una pregunta existente? @ vol7ron
HP
@ HP En absoluto, pero los comentarios son para comentarios sobre una pregunta o respuesta; generalmente para agregar más información o solicitar más información que no se abordó. Estás haciendo una pregunta que no está relacionada con esta respuesta. Creo que tendrás más suerte haciendo tu pregunta como una nueva publicación, no en el comentario;)
vol7ron
@HP si no ha publicado su pregunta, puede ver aquí: sqlfiddle.com/#!15/144cd/3 para ver un ejemplo de lo que debe hacer: su problema es diferente porque necesita deshacer su matriz.
vol7ron
4

unnesttambién se puede usar Expande la matriz a un conjunto de filas y luego simplemente verificar si un valor existe o no es tan simple como usar INoNOT IN .

p.ej

  1. id => uuid

  2. exception_list_ids => uuid []

select * from table where id NOT IN (select unnest(exception_list_ids) from table2)

pg2286
fuente
Si. Tenga en cuenta que en mis planes de consulta SELECT UNNEST no es tan bueno como = ANY. Recomiendo verificar los planes de consulta para ver si obtiene lo que desea / espera.
Rob Bygrave
3

Cuando se busca la existencia de un elemento en una matriz, se requiere una conversión adecuada para pasar el analizador SQL de postgres. Aquí hay una consulta de ejemplo que usa el operador contiene matriz en la cláusula join:

Para simplificar, solo enumero la parte relevante:

table1 other_name text[]; -- is an array of text

La parte de unión de SQL que se muestra

from table1 t1 join table2 t2 on t1.other_name::text[] @> ARRAY[t2.panel::text]

Lo siguiente también funciona

on t2.panel = ANY(t1.other_name)

Supongo que se requiere una conversión adicional porque el análisis no tiene que buscar la definición de la tabla para calcular el tipo exacto de la columna. Otros por favor comenten sobre esto.

Kemin Zhou
fuente
1

Hola, eso funciona bien para mí, quizás sea útil para alguien

seleccione * desde su_tabla donde array_column :: text ilike ANY (ARRAY ['% text_to_search%' :: text]);

Dave Kraczo
fuente