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

Hvordan matcher man elementer i en række af sammensatte typer?

Dette virker:

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

Eller mere omfattende, men at foretrække :

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

Mere robust og undgår at evaluere unnest() flere gange. Se:

Dette virker også:

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

Kernen i problemet er, at IN tager en underforespørgsel kender to separate former. Citerer manualen:

Din mislykkede forespørgsel løser sig til den anden form, mens du (forståeligt nok) forventer den første. Men den anden form gør dette:

Min første og anden forespørgsel få det til at fungere ved at dekomponere rækketypen til højre for operatøren. Så Postgres har tre bigint værdier venstre og højre og er tilfreds.

Min tredje forespørgsel får det til at fungere ved at indlejre rækketypen til venstre i en anden rækkekonstruktør . Postgres nedbryder kun det første niveau og ender med en enkelt sammensat type - matchende den enkelte sammensatte type til højre.

Bemærk, at søgeordet ROW er påkrævet for det enkelte felt, vi pakker. Manualen:

Din arbejdsforespørgsel er subtilt anderledes, da det giver en liste af værdier til højre i stedet for en underforespørgsel (indstil ). Det er en anden implementering, der tager en anden kodesti. Den får endda et separat kapitel i manualen . Denne variant har ingen særlig behandling for en ROW-konstruktør til venstre. Så det fungerer bare som forventet (af dig).

Mere ækvivalente (fungerende) syntaksvarianter 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[]);

Også gyldig med (pk1, pk2, pk3)::element_pk_t eller ROW(pk1, pk2, pk3)::element_pk_t

Se:

Da din kilde er en matrix , Daniels anden forespørgsel med (e.pk1, e.pk2, e.pk3) = ANY(c.elements) giver sig naturligt.
Men for et væddemål på den hurtigste forespørgsel , mine penge er på min anden variant, fordi jeg forventer, at den bruger PK-indekset optimalt.

Bare som proof of concept. Som en hest kommenterede:et normaliseret DB-design vil sandsynligvis skaleres bedst.




  1. ORACLE SQL Timeinterval

  2. Oracle SQL:Sådan bruger du mere end 1000 elementer i en IN-klausul

  3. Sådan gemmer du en udfyldt polygon point folder.draw til mysql tabel

  4. Sådan arbejder du med MySQL-underforespørgsler