PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Como combinar elementos em uma matriz do tipo composto?


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.