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.