sql >> Base de Datos >  >> RDS >> PostgreSQL

¿Cómo hacer coincidir elementos en una matriz de tipo compuesto?

Esto funciona:

SELECT *
FROM   element 
WHERE  (pk1, pk2, pk3) IN (SELECT (unnest(elements)).*
                           FROM   collection
                           WHERE  id = 1);

O más detallado, pero preferible :

SELECT *
FROM   element 
WHERE  (pk1, pk2, pk3) IN (SELECT (e).*
                           FROM   collection c, unnest(c.elements) e
                           WHERE  c.id = 1);

Más robusto y evita evaluar unnest() varias veces. Ver:

Esto también funciona:

SELECT *
FROM   element 
WHERE  ROW((pk1, pk2, pk3)) IN (SELECT unnest(elements)
                                FROM   collection
                                WHERE  id = 1);

El núcleo del problema es que IN tomar una subconsulta conoce dos formas separadas. Citando el manual:

Tu consulta fallida se resuelve en la segunda forma, mientras que usted (comprensiblemente) espera la primera. Pero la segunda forma hace esto:

Mi primera y segunda consulta haz que funcione descomponiendo el tipo de fila a la derecha del operador. Entonces Postgres tiene tres bigint valores izquierda y derecha y está satisfecho.

Mi tercera consulta hace que funcione anidando el tipo de fila a la izquierda en otro constructor de filas . Postgres solo descompone el primer nivel y termina con un solo tipo compuesto, haciendo coincidir el tipo compuesto único a la derecha.

Tenga en cuenta que la palabra clave ROW es requerido para el único campo que estamos envolviendo. El manual:

Tu consulta de trabajo es sutilmente diferente ya que proporciona una lista de valores a la derecha en lugar de una subconsulta (establecer ). Esa es una implementación diferente que toma una ruta de código diferente. Incluso obtiene un capítulo separado en el manual . Esta variante no tiene un tratamiento especial para un constructor ROW a la izquierda. Así que simplemente funciona como se esperaba (por usted).

Más variantes de sintaxis equivalentes (en funcionamiento) con = ANY :

SELECT * FROM element 
WHERE (pk1, pk2, pk3) = ANY ('{"(1,2,3)","(2,3,4)"}'::element_pk_t[]);

SELECT * FROM element 
WHERE (pk1, pk2, pk3) = ANY (ARRAY[(1,2,3)::element_pk_t,(2,3,4)::element_pk_t]);

SELECT * FROM element 
WHERE (pk1, pk2, pk3) = ANY (ARRAY[(1,2,3),(2,3,4)]::element[]);

También válido con (pk1, pk2, pk3)::element_pk_t o ROW(pk1, pk2, pk3)::element_pk_t

Ver:

Dado que su fuente es una matriz , la segunda consulta de Daniel con (e.pk1, e.pk2, e.pk3) = ANY(c.elements) se presta naturalmente.
Pero para apostar por la consulta más rápida , mi dinero está en mi segunda variante, porque espero que use el índice PK de manera óptima.

Solo como prueba de concepto. Como comentó a_horse:un diseño de base de datos normalizado probablemente escalará mejor.