Ja, överlappningsoperator && skulle kunna använda ett GIN-index på arrayer
. Mycket användbart för frågor den här för att hitta rader med en given person (1 ) bland en rad skådespelare:
SELECT * FROM eg_assoc WHERE actors && '{1}'::int[]
Men , logiken i din fråga är tvärtom, letar efter alla personer som är listade i arrayerna i eg_assoc . Ett GIN-index är nej hjälp här. Vi behöver bara btree-indexet för PK person.id .
Rätta frågor
Grunderna:
Följande frågor bevarar ursprungliga arrayer exakt som givna , inklusive möjliga dubbletter av element och ursprunglig ordning av element. Fungerar för endimensionella arrayer . Ytterligare dimensioner viks till en enda dimension. Det är mer komplicerat att bevara flera dimensioner (men fullt möjligt):
WITH ORDINALITY i Postgres 9.4 eller senare
SELECT aid, actors
, ARRAY(SELECT name
FROM unnest(e.actors) WITH ORDINALITY a(id, i)
JOIN eg_person p USING (id)
ORDER BY a.i) AS act_names
, benefactors
, ARRAY(SELECT name
FROM unnest(e.benefactors) WITH ORDINALITY b(id, i)
JOIN eg_person USING (id)
ORDER BY b.i) AS ben_names
FROM eg_assoc e;
LATERAL frågor
För PostgreSQL 9.3+ .
SELECT e.aid, e.actors, a.act_names, e.benefactors, b.ben_names
FROM eg_assoc e
, LATERAL (
SELECT ARRAY( SELECT name
FROM generate_subscripts(e.actors, 1) i
JOIN eg_person p ON p.id = e.actors[i]
ORDER BY i)
) a(act_names)
, LATERAL (
SELECT ARRAY( SELECT name
FROM generate_subscripts(e.benefactors, 1) i
JOIN eg_person p ON p.id = e.benefactors[i]
ORDER BY i)
) b(ben_names);
db<>fiol här
med ett par varianter.
Gammal sqlfiddle
Subtil detalj:Om en person inte hittas släpps den bara. Båda dessa frågor genererar en tom array ('{}' ) om ingen person hittas för hela arrayen. Andra frågestilar skulle returnera NULL . Jag lade till varianter till fiolen.
Korrelerade underfrågor
För Postgres 8.4+ (där generate_subsrcipts()
introducerades):
SELECT aid, actors
, ARRAY(SELECT name
FROM generate_subscripts(e.actors, 1) i
JOIN eg_person p ON p.id = e.actors[i]
ORDER BY i) AS act_names
, benefactors
, ARRAY(SELECT name
FROM generate_subscripts(e.benefactors, 1) i
JOIN eg_person p ON p.id = e.benefactors[i]
ORDER BY i) AS ben_names
FROM eg_assoc e;
Kan fortfarande prestera bäst, även i Postgres 9.3.
The ARRAY konstruktör
är snabbare än array_agg() . Se:
Din misslyckade fråga
frågan från @a_horse verkar att göra jobbet, men det är opålitligt, vilseledande, potentiellt felaktigt och onödigt dyrt.
-
Proxy cross join på grund av två orelaterade joins. Ett lömskt antimönster. Se:
Fixat ytligt med
DISTINCTiarray_agg()för att eliminera de genererade dubbletterna, men det är verkligen att sätta läppstift på en gris. Det eliminerar också dubbletter i originalet eftersom det är omöjligt att se skillnad vid det här laget - vilket är potentiellt felaktigt. -
Uttrycket
a_person.id = any(eg_assoc.actors)fungerar , men eliminerar dubbletter från resultatet (händer två gånger i den här frågan), vilket är fel om inget annat anges. -
Ursprunglig ordning av matriselement bevaras inte . Detta är knepigt i allmänhet. Men det förvärras i den här frågan, eftersom aktörer och välgörare multipliceras och görs åtskilda igen, vilket garanterar godtycklig ordning.
-
Inga kolumnalias i den yttre
SELECTresultera i dubbla kolumnnamn, vilket gör att vissa klienter misslyckas (fungerar inte i fiolen utan alias). -
min(actors)ochmin(benefactors)är värdelösa. Normalt skulle man bara lägga till kolumnerna iGROUP BYistället för att falska samman dem. Meneg_assoc.aidär PK-kolumnen ändå (som täcker hela tabellen iGROUP BY), så det är inte ens nödvändigt. Baraactors, benefactors.
Att samla hela resultatet är bortkastad tid och ansträngning till att börja med. Använd en smartare fråga som inte multiplicerar basraderna, då behöver du inte aggregera dem igen.