sql >> Database >  >> RDS >> PostgreSQL

Hoe elementen in een array van composiettype te matchen?

Dit werkt:

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

Of uitgebreider, maar bij voorkeur :

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

Robuuster en vermijdt het evalueren van unnest() meerdere keren. Zie:

Dit werkt ook:

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

De kern van het probleem is dat IN een subquery nemen kent twee aparte vormen. Ik citeer de handleiding:

Uw mislukte zoekopdracht besluit naar de tweede vorm, terwijl u (begrijpelijkerwijs) de eerste verwacht. Maar de tweede vorm doet dit:

Mijn eerste en tweede vraag laat het werken door het rijtype te ontleden rechts van de bediener. Dus Postgres heeft drie bigint waarden links en rechts en is tevreden.

Mijn derde vraag laat het werken door het rijtype aan de linkerkant te nesten in een andere rij-constructor . Postgres ontleedt alleen het eerste niveau en eindigt met een enkel composiettype - overeenkomend met het enkele composiettype aan de rechterkant.

Merk op dat het trefwoord ROW is vereist voor het enkele veld dat we inpakken. De handleiding:

Uw werkvraag is subtiel anders omdat het een lijst . biedt waarden aan de rechterkant in plaats van een subquery (instellen ). Dat is een andere implementatie met een ander codepad. Het krijgt zelfs een apart hoofdstuk in de handleiding . Deze variant heeft geen speciale behandeling voor een ROW-constructeur aan de linkerkant. Dus het werkt gewoon zoals verwacht (door jou).

Meer gelijkwaardige (werkende) syntaxisvarianten met = 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[]);

Ook geldig met (pk1, pk2, pk3)::element_pk_t of ROW(pk1, pk2, pk3)::element_pk_t

Zie:

Aangezien je bron een array is , Daniel's tweede zoekopdracht met (e.pk1, e.pk2, e.pk3) = ANY(c.elements) leent zich natuurlijk.
Maar voor een weddenschap op de snelste zoekopdracht , mijn geld staat op mijn tweede variant, omdat ik verwacht dat deze de PK-index optimaal gebruikt.

Net als proof of concept. Zoals a_horse opmerkte:een genormaliseerd DB-ontwerp zal waarschijnlijk het beste schalen.




  1. Herstarten van transactie in MySQL na een impasse

  2. apt-get installatie van oracle java 7 werkt niet meer

  3. Declareer een kolom van het type 'not-null-string' array in PostgreSQL

  4. Selecteer de rijen die zojuist zijn ingevoegd