PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Come abbinare gli elementi in una matrice di tipo composito?

Funziona:

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

O più dettagliato, ma preferibile :

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

Più robusto ed evita di valutare unnest() più volte. Vedi:

Funziona anche questo:

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

Il cuore del problema è che IN prendendo una sottoquery conosce due forme separate. Citando il manuale:

La tua query non riuscita si risolve nella seconda forma, mentre tu (comprensibilmente) ti aspetti la prima. Ma il secondo modulo fa questo:

La mia prima e seconda query fallo funzionare scomponendo il tipo di riga alla destra dell'operatore. Quindi Postgres ha tre bigint valori a sinistra e a destra ed è soddisfatto.

La mia terza domanda lo fa funzionare annidando il tipo di riga a sinistra in un altro costruttore di riga . Postgres scompone solo il primo livello e finisce con un unico tipo composito, corrispondente al singolo tipo composito a destra.

Tieni presente che la parola chiave ROW è richiesto per il singolo campo che stiamo avvolgendo. Il manuale:

La tua domanda di lavoro è leggermente diverso in quanto fornisce un elenco di valori a destra invece di una sottoquery (imposta ). Questa è un'implementazione diversa che prende un percorso di codice diverso. Ottiene persino un capitolo separato nel manuale . Questa variante non ha un trattamento speciale per un costruttore ROW a sinistra. Quindi funziona come previsto (da te).

Più varianti di sintassi equivalenti (funzionanti) 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[]);

Valido anche con (pk1, pk2, pk3)::element_pk_t o ROW(pk1, pk2, pk3)::element_pk_t

Vedi:

Poiché la tua sorgente è un array , la seconda query di Daniel con (e.pk1, e.pk2, e.pk3) = ANY(c.elements) si presta naturalmente.
Ma per una scommessa sulla query più veloce , il mio denaro è sulla mia seconda variante, perché mi aspetto che utilizzi l'indice PK in modo ottimale.

Proprio come prova del concetto. Come ha commentato a_horse:un design DB normalizzato probabilmente scalerà meglio.