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.