Ano, operátor překrytí && mohl použít GIN index na polích
. Velmi užitečné pro tyto dotazy k nalezení řádků s danou osobou (1 ) mezi řadou herců:
SELECT * FROM eg_assoc WHERE actors && '{1}'::int[]
Nicméně , logika vašeho dotazu je opačná a hledá všechny osoby uvedené v polích v eg_assoc . Index GIN je ne pomozte zde. Potřebujeme pouze btree index PK person.id .
Správné dotazy
Základy:
Následující dotazy zachovávají původní pole přesně tak, jak je uvedeno , včetně případných duplicitních prvků a původního pořadí prvků. Funguje pro jednorozměrná pole . Další rozměry jsou složeny do jednoho rozměru. Je složitější zachovat více dimenzí (ale zcela možné):
WITH ORDINALITY v Postgres 9.4 nebo novější
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 dotazy
Pro 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<>fiddle zde
s několika variantami.
Starý sqlfiddle
Jemný detail:Pokud není nalezena osoba, je prostě vypuštěna. Oba tyto dotazy generují prázdné pole ('{}' ), pokud se pro celé pole nenajde žádná osoba. Jiné styly dotazů vrátí NULL . K houslím jsem přidal varianty.
Korelované poddotazy
Pro Postgres 8.4+ (kde generate_subsrcipts()
byl představen):
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;
Může stále fungovat nejlépe, dokonce i v Postgresu 9.3.
The ARRAY konstruktor
je rychlejší než array_agg() . Viz:
Váš neúspěšný dotaz
dotaz poskytnutý @a_horse zdá se dělat práci, ale je to nespolehlivé, zavádějící, potenciálně nesprávné a zbytečně drahé.
-
Křížové spojení proxy kvůli dvěma nesouvisejícím spojením. Záludný anti-vzor. Viz:
Opraveno povrchně pomocí
DISTINCTvarray_agg()to eliminuje generované duplikáty, ale to už je fakt prase rtěnky. Také eliminuje duplikáty v originále protože v tomto bodě není možné rozeznat rozdíl – což je potenciálně nesprávné. -
Výraz
a_person.id = any(eg_assoc.actors)funguje , ale eliminuje duplicity z výsledku (v tomto dotazu se to stane dvakrát), což je nesprávné, pokud není uvedeno jinak. -
Původní pořadí prvků pole není zachováno . To je obecně ošemetné. Ale v tomto dotazu je to ještě horší, protože aktéři a dobrodinci jsou násobeni a znovu odlišeni, což zaručuje libovolné pořadí.
-
Žádné aliasy sloupců ve vnějším
SELECTvýsledkem jsou duplicitní názvy sloupců, v důsledku čehož někteří klienti selhávají (nefungují v houslích bez aliasů). -
min(actors)amin(benefactors)jsou k ničemu. Normálně stačí přidat sloupce doGROUP BYmísto jejich falešného agregování. Aleeg_assoc.aidje stejně sloupec PK (pokrývá celou tabulku vGROUP BY), takže to ani není potřeba. Jenactors, benefactors.
Agregace celého výsledku je pro začátek ztrátou času a úsilí. Použijte chytřejší dotaz, který nenásobí základní řádky, takže je nemusíte zpětně agregovat.