PostgreSQL
 sql >> база данни >  >> RDS >> PostgreSQL

ЛЯВО ВЪНШНО СЪЕДИНЕНИЕ в колона на масив с множество стойности

Да, оператор на припокриване && може да използва 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 изглежда да свърши работата, но е ненадежден, подвеждащ, потенциално неправилен и ненужно скъп.

  1. Прокси кръстосано присъединяване поради две несвързани присъединявания. Подъл антимодел. Вижте:

    Коригирано повърхностно с DISTINCT в array_agg() за елиминиране на генерираните дубликати, но това наистина е като слагане на червило на прасе. Освен това елиминира дубликатите в оригинала защото е невъзможно да се направи разлика в този момент - което е потенциално неправилно.

  2. Изразът a_person.id = any(eg_assoc.actors) работи , но елиминира дубликати от резултата (случва се два пъти в тази заявка), което е грешно, освен ако не е посочено.

  3. Оригиналният ред на елементите на масива не е запазен . Това като цяло е сложно. Но това се влошава в това запитване, тъй като актьорите и благодетелите се умножават и отново се разграничават, което гарантира произволен ред.

  4. Няма псевдоними на колони във външния SELECT водят до дублирани имена на колони, което кара някои клиенти да се провалят (не работят в цигулката без псевдоними).

  5. min(actors) и min(benefactors) са безполезни. Обикновено човек просто добавя колоните към GROUP BY вместо да ги агрегира фалшиво. Но eg_assoc.aid все пак е колоната PK (покриваща цялата таблица в GROUP BY ), така че това дори не е необходимо. Само actors, benefactors .

Обединяването на целия резултат като начало е загуба на време и усилия. Използвайте по-интелигентна заявка, която не умножава основните редове, след което не е необходимо да ги обобщавате обратно.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. CREATE SCHEMA IF NOT EXISTS предизвиква грешка при дублиране на ключ

  2. предоставяне на сертификати към tomcat jndi връзка към postgresql

  3. Rails Activerecord Relation:използване на подзаявка като таблица за SQL оператор за избор

  4. Как да променя типа на колоната в Heroku?

  5. Често срещани грешки при мигриране на PostgreSQL бази данни от On-Prem към AWS RDS