Detta fungerar:
SELECT *
FROM element
WHERE (pk1, pk2, pk3) IN (SELECT (unnest(elements)).*
FROM collection
WHERE id = 1);
Eller mer omfattande, men föredraget :
SELECT *
FROM element
WHERE (pk1, pk2, pk3) IN (SELECT (e).*
FROM collection c, unnest(c.elements) e
WHERE c.id = 1);
Mer robust och undviker att utvärdera unnest()
flera gånger. Se:
Detta fungerar också:
SELECT *
FROM element
WHERE ROW((pk1, pk2, pk3)) IN (SELECT unnest(elements)
FROM collection
WHERE id = 1);
Kärnan i problemet är att IN
ta en underfråga känner till två skilda former. Citerar handboken:
Din misslyckade fråga löser sig till den andra formen, medan du (förståeligt nog) förväntar dig den första. Men den andra formen gör detta:
Min första och andra fråga få det att fungera genom att dekomponera radtypen
till höger om operatören. Så Postgres har tre bigint
värderar vänster och höger och är nöjd.
Min tredje fråga får det att fungera genom att kapsla radtypen till vänster i en annan radkonstruktör . Postgres bryter bara ner den första nivån och slutar med en enda sammansatt typ - matchande den enstaka sammansatta typen till höger.
Observera att sökordet ROW
krävs för det enskilda fältet vi lindar. Handboken:
Din arbetsfråga är subtilt annorlunda eftersom det ger en lista av värden till höger istället för en underfråga (ställ ). Det är en annan implementering som tar en annan kodväg. Den får till och med ett separat kapitel i manualen . Denna variant har ingen speciell behandling för en ROW-konstruktör till vänster. Så det fungerar precis som förväntat (av dig).
Mer likvärdiga (fungerande) syntaxvarianter med = 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[]);
Gäller även med (pk1, pk2, pk3)::element_pk_t
eller ROW(pk1, pk2, pk3)::element_pk_t
Se:
Eftersom din källa är en array , Daniels andra fråga med (e.pk1, e.pk2, e.pk3) = ANY(c.elements)
lämpar sig naturligt.
Men för en satsning på den snabbaste frågan , mina pengar är på min andra variant, eftersom jag förväntar mig att den använder PK-indexet optimalt.
Bara som proof of concept. Som a_horse kommenterade:en normaliserad DB-design kommer förmodligen att skala bäst.