Isso funciona:
SELECT *
FROM element
WHERE (pk1, pk2, pk3) IN (SELECT (unnest(elements)).*
FROM collection
WHERE id = 1);
Ou mais detalhado, mas preferível :
SELECT *
FROM element
WHERE (pk1, pk2, pk3) IN (SELECT (e).*
FROM collection c, unnest(c.elements) e
WHERE c.id = 1);
Mais robusto e evita avaliar
unnest()
várias vezes. Ver:Isso também funciona:
SELECT *
FROM element
WHERE ROW((pk1, pk2, pk3)) IN (SELECT unnest(elements)
FROM collection
WHERE id = 1);
O cerne do problema é que
IN
fazendo uma subconsulta conhece duas formas distintas. Citando o manual:
Sua consulta com falha resolve para a segunda forma, enquanto você (compreensivelmente) espera a primeira. Mas a segunda forma faz isso:
Minha primeira e segunda consulta faça funcionar decompondo o tipo de linha à direita do operador. Então o Postgres tem três
bigint
valores à esquerda e à direita e é satisfeito. Minha terceira consulta faz com que funcione aninhando o tipo de linha à esquerda em outro construtor de linha . O Postgres decompõe apenas o primeiro nível e termina com um único tipo composto - correspondendo ao único tipo composto à direita.
Observe que a palavra-chave
ROW
é necessário para o campo único que estamos envolvendo. O manual:
Sua consulta de trabalho é sutilmente diferente, pois fornece uma lista de valores à direita em vez de uma subconsulta (definir ). Essa é uma implementação diferente tomando um caminho de código diferente. Ele ainda recebe um capítulo separado no manual . Esta variante não tem tratamento especial para um construtor ROW à esquerda. Portanto, funciona como esperado (por você).
Variantes de sintaxe mais equivalentes (de trabalho) com
= 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[]);
Também válido com
(pk1, pk2, pk3)::element_pk_t
ou ROW(pk1, pk2, pk3)::element_pk_t
Ver:
Como sua fonte é uma matriz , a segunda consulta de Daniel com
(e.pk1, e.pk2, e.pk3) = ANY(c.elements)
se presta naturalmente.Mas para uma aposta na consulta mais rápida , meu dinheiro está na minha segunda variante, porque espero que ela use o índice PK de maneira ideal.
Apenas como prova de conceito. Como a_horse comentou:um design de banco de dados normalizado provavelmente será melhor dimensionado.