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í
DISTINCT
varray_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
SELECT
vý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 BY
místo jejich falešného agregování. Aleeg_assoc.aid
je 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.