sql >> Databáze >  >> RDS >> PostgreSQL

LEFT OUTER JOIN ve sloupci pole s více hodnotami

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é.

  1. Křížové spojení proxy kvůli dvěma nesouvisejícím spojením. Záludný anti-vzor. Viz:

    Opraveno povrchně pomocí DISTINCT v array_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é.

  2. 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.

  3. 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í.

  4. Žá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ů).

  5. min(actors) a min(benefactors) jsou k ničemu. Normálně stačí přidat sloupce do GROUP BY místo jejich falešného agregování. Ale eg_assoc.aid je stejně sloupec PK (pokrývá celou tabulku v GROUP BY ), takže to ani není potřeba. Jen actors, 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.



  1. Je možné zachytit neplatnou hodnotu v MySQL, když dostanu chybu omezení cizího klíče?

  2. Jak výkonný je váš uzel ProxySQL?

  3. Vytvořte dynamickou tabulku z funkce v PostgreSQL

  4. Presto ekvivalent MySQL group_concat