PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

LEFT OUTER JOIN w kolumnie tablicy z wieloma wartościami

Tak, operator nakładania się && może używać indeksu GIN w tablicach . Bardzo przydatne przy zapytaniach tego, aby znaleźć wiersze z daną osobą (1 ) wśród szeregu aktorów:

SELECT * FROM eg_assoc WHERE actors && '{1}'::int[]

Jednak , logika zapytania jest odwrotna, szukając wszystkich osób wymienionych w tablicach w eg_assoc . Indeks WZ to nie pomoc tutaj. Potrzebujemy tylko indeksu btree pliku PK person.id .

Właściwe zapytania

Podstawy:

Poniższe zapytania zachowują oryginalne tablice dokładnie takie, jakie podano , w tym możliwe zduplikowane elementy i oryginalną kolejność elementów. Działa z tablicami jednowymiarowymi . Dodatkowe wymiary są składane w jeden wymiar. Zachowanie wielu wymiarów jest bardziej skomplikowane (ale całkowicie możliwe):

WITH ORDINALITY w Postgresie 9.4 lub nowszym

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 zapytania

Dla 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 tutaj z kilkoma wariantami.
Stary sqlfiddle

Subtelny szczegół:jeśli dana osoba nie zostanie znaleziona, zostanie po prostu usunięta. Oba te zapytania generują pustą tablicę ('{}' ), jeśli żadna osoba nie została znaleziona dla całej tablicy. Inne style zapytań zwrócą NULL . Dodałem warianty do skrzypiec.

Skorelowane podzapytania

Dla Postgresa 8.4+ (gdzie generate_subsrcipts() został wprowadzony):

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;

Może nadal działać najlepiej, nawet w Postgresie 9.3.
ARRAY konstruktor jest szybszy niż array_agg() . Zobacz:

Twoje nieudane zapytanie

zapytanie dostarczone przez @a_horse wydaje się do wykonania pracy, ale jest zawodna, myląca, potencjalnie niepoprawna i niepotrzebnie droga.

  1. Proxy sprzężenie krzyżowe z powodu dwóch niepowiązanych sprzężeń. Podstępny antywzór. Zobacz:

    Naprawiono powierzchownie za pomocą DISTINCT w array_agg() aby wyeliminować wygenerowane duplikaty, ale to naprawdę nakładanie szminki na świnię. Ponadto eliminuje duplikaty w oryginale ponieważ w tym momencie nie można odróżnić - co jest potencjalnie niepoprawne.

  2. Wyrażenie a_person.id = any(eg_assoc.actors) działa , ale eliminuje duplikaty z wyniku (zdarza się to dwa razy w tym zapytaniu), który jest nieprawidłowy, chyba że określono inaczej.

  3. Oryginalna kolejność elementów tablicy nie jest zachowana . Ogólnie jest to trudne. Jednak w tym zapytaniu sytuacja się pogarsza, ponieważ aktorzy i dobroczyńcy są mnożeni i ponownie wyróżniani, co gwarantuje dowolna kolejność.

  4. Brak aliasów kolumn w zewnętrznym SELECT powodują zduplikowane nazwy kolumn, co powoduje, że niektórzy klienci nie działają (nie działają na skrzypcach bez aliasów).

  5. min(actors) i min(benefactors) są bezużyteczne. Normalnie wystarczy dodać kolumny do GROUP BY zamiast fałszywego ich agregowania. Ale eg_assoc.aid i tak jest kolumną PK (pokrywa całą tabelę w GROUP BY ), więc nie jest to nawet konieczne. Tylko actors, benefactors .

Agregacja całego wyniku to strata czasu i wysiłku na początek. Użyj inteligentniejszego zapytania, które nie mnoży podstawowych wierszy, dzięki czemu nie musisz ich ponownie agregować.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Jak ograniczyć wiersze w PostgreSQL SELECT

  2. UUID z możliwością sortowania i nadpisywanie ActiveRecord::Base

  3. LEFT OUTER JOIN w kolumnie tablicy z wieloma wartościami

  4. PGError:BŁĄD:odmowa pozwolenia na relację (podczas korzystania z Heroku)

  5. Bezpieczny wątkowo obiekt PQconn