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.
-
Proxy sprzężenie krzyżowe z powodu dwóch niepowiązanych sprzężeń. Podstępny antywzór. Zobacz:
Naprawiono powierzchownie za pomocą
DISTINCT
warray_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. -
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. -
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ść.
-
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). -
min(actors)
imin(benefactors)
są bezużyteczne. Normalnie wystarczy dodać kolumny doGROUP BY
zamiast fałszywego ich agregowania. Aleeg_assoc.aid
i tak jest kolumną PK (pokrywa całą tabelę wGROUP BY
), więc nie jest to nawet konieczne. Tylkoactors, 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ć.