Фильтрация данных из объединенной таблицы в PostgreSQL - PullRequest
0 голосов
/ 03 декабря 2018

В моей базе данных есть следующая схема:

CREATE TABLE survey_results (
    id integer NOT NULL
);

CREATE TABLE slide_results (
    id integer NOT NULL,
    survey_result_id integer,
    tags character varying[] DEFAULT '{}'::character varying[],
    content character varying,
    created_at timestamp with time zone NOT NULL
);

INSERT INTO survey_results (id)
  VALUES (1);

INSERT INTO slide_results (id, survey_result_id, tags, content, created_at)
  VALUES (1, 1, '{food}', 'Food slide', now());

INSERT INTO slide_results (id, survey_result_id, tags, content, created_at)
  VALUES (2, 1, '{motivation}', 'Motivation slide', now());

Теперь я хочу получить SQL-запрос, который будет возвращать идентификатор результата опроса и контент для результатов слайдов с указанными тегами.Я написал что-то вроде этого:

select distinct on(sr.id)
  sr.id,
  slr.content AS food,
  slr2.content AS motivation
  from survey_results sr

  LEFT JOIN slide_results slr ON slr.survey_result_id = sr.id AND slr.id IN (
    SELECT id as id
    FROM slide_results
    WHERE 'food' = ANY(tags)
    ORDER BY created_at desc
  )

  LEFT JOIN slide_results slr2 ON slr2.survey_result_id = sr.id AND slr2.id IN (
    SELECT id as id
    FROM slide_results
    WHERE 'motivation' = ANY(tags)
    ORDER BY created_at desc
  )
  group by slr.content, slr2.content, sr.id

, который возвращает:

| id  | food       | motivation       |
| --- | ---------- | ---------------- |
| 1   | Food slide | Motivation slide |

Этот запрос работает нормально, но мне интересно, есть ли лучший способ сделать это?

РЕДАКТИРОВАТЬ:

Я забыл добавить ссылку сделать db-fiddle:

https://www.db -fiddle.com / f / gP761psywgmovfdTT7DjP4 / 0

Ответы [ 2 ]

0 голосов
/ 04 декабря 2018

Я не могу обещать, что это немного лучше, чем у вас, но это кажется немного более масштабируемым.Не видя вашего полного набора данных и желаемых результатов, трудно понять, будет ли это иметь какие-либо последствия:

select
  sl.survey_result_id,
  array_to_string (array_agg (distinct sl.content) filter
      (where 'food' = any (sl.tags)), ',') as food,
  array_to_string (array_agg (distinct sl.content) filter
      (where 'motivation' = any (sl.tags)), ',') as motivation
from
  survey_results s
  join slide_results sl on s.id = sl.survey_result_id
group by survey_result_id
0 голосов
/ 03 декабря 2018

Я бы написал запрос следующим образом:

SELECT DISTINCT ON (sr.id)
       sr.id,
       slr.content AS food,
       slr2.content AS motivation
FROM survey_results AS sr
   LEFT JOIN (SELECT survey_result_id, content, created_at
              FROM slide_results
              WHERE '{food}' <@ tags) AS slr
      ON slr.survey_result_id = sr.id
   LEFT JOIN (SELECT survey_result_id, content, created_at
              FROM slide_results
              WHERE '{motivation}' <@ tags) AS slr2
      ON slr2.survey_result_id = sr.id
ORDER BY sr.id, slr.created_at DESC, slr2.created_at DESC;

Чтобы быть эффективным, ORDER BY должен быть во внешнем запросе.

Использование <@ вместо =ANYпозволяет использовать индекс GIN для slide_results.tags.

Использование подвыбора в списке FROM позволяет избежать ненужного объединения и неэффективного подзапроса IN.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...