Да, оператор на припокриване &&
може да използва GIN индекс на масиви
. Това е много полезно за заявки за намиране на редове с даден човек (1
) сред масив от актьори:
SELECT * FROM eg_assoc WHERE actors && '{1}'::int[]
Въпреки това , логиката на вашата заявка е обратната, търсейки всички лица, изброени в масивите в eg_assoc
. GIN индексът е не помогнете тук. Нуждаем се само от btree индекса на PK person.id
.
Правилни заявки
Основи:
Следните заявки запазват оригиналните масиви точно както са дадени , включително възможни дублирани елементи и оригинален ред на елементите. Работи за едномерни масиви . Допълнителните размери се сгъват в едно измерение. По-сложно е да се запазят множество измерения (но е напълно възможно):
WITH ORDINALITY
в Postgres 9.4 или по-нова версия
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
заявки
За 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 тук
с няколко варианта.
Стар sqlfiddle
Тънък детайл:Ако човек не бъде намерен, той просто е изпуснат. И двете заявки генерират празен масив ('{}'
), ако не е намерен човек за целия масив. Други стилове на заявка биха върнали NULL
. Добавих варианти към цигулката.
Свързани подзаявки
За Postgres 8.4+ (където generate_subsrcipts()
беше въведен):
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;
Все пак може да се представи най-добре дори в Postgres 9.3.ARRAY
конструктор
е по-бърз от array_agg()
. Вижте:
Вашата неуспешна заявка
заявката, предоставена от @a_horse изглежда да свърши работата, но е ненадежден, подвеждащ, потенциално неправилен и ненужно скъп.
-
Прокси кръстосано присъединяване поради две несвързани присъединявания. Подъл антимодел. Вижте:
Коригирано повърхностно с
DISTINCT
вarray_agg()
за елиминиране на генерираните дубликати, но това наистина е като слагане на червило на прасе. Освен това елиминира дубликатите в оригинала защото е невъзможно да се направи разлика в този момент - което е потенциално неправилно. -
Изразът
a_person.id = any(eg_assoc.actors)
работи , но елиминира дубликати от резултата (случва се два пъти в тази заявка), което е грешно, освен ако не е посочено. -
Оригиналният ред на елементите на масива не е запазен . Това като цяло е сложно. Но това се влошава в това запитване, тъй като актьорите и благодетелите се умножават и отново се разграничават, което гарантира произволен ред.
-
Няма псевдоними на колони във външния
SELECT
водят до дублирани имена на колони, което кара някои клиенти да се провалят (не работят в цигулката без псевдоними). -
min(actors)
иmin(benefactors)
са безполезни. Обикновено човек просто добавя колоните къмGROUP BY
вместо да ги агрегира фалшиво. Ноeg_assoc.aid
все пак е колоната PK (покриваща цялата таблица вGROUP BY
), така че това дори не е необходимо. Самоactors, benefactors
.
Обединяването на целия резултат като начало е загуба на време и усилия. Използвайте по-интелигентна заявка, която не умножава основните редове, след което не е необходимо да ги обобщавате обратно.