Как запросить иерархию таблиц в SQL - PullRequest
0 голосов
/ 23 сентября 2018

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

Все обычные meetings будут связаны как минимум с одним объединительным столом meeting_yearly_meeting.meeting_yearly_meeting имеет два столбца: meeting_id и yearly_meeting_id.

. Вот как выглядят эти две таблицы:

meeting:

id SERIAL PRIMARY KEY,
title VARCHAR(255),
mappable BOOLEAN,
phone VARCHAR(255),
email VARCHAR(255),
city VARCHAR(255),
address VARCHAR(255),
zip VARCHAR(255),
latitude NUMERIC,
longitude NUMERIC,
description VARCHAR(255),
worship_time TIME,
state VARCHAR(255),
website VARCHAR(255),
lgbt_affirming BOOLEAN,
created TIMESTAMP default current_timestamp,
updated TIMESTAMP default current_timestamp

meeting_yearly_meeting:

id SERIAL PRIMARY KEY,
meeting_id SMALLINT,
yearly_meeting_id SMALLINT,
created TIMESTAMP default current_timestamp,
updated TIMESTAMP default current_timestamp

Итак, с моей конечной точки /meetings я хочу вернуть коллекцию всех собраний - как регулярных, так и ежегодных.Я хочу вернуть встречи со всеми их столбцами, а также дополнительный столбец: yearly_meeting.

Для meeting записей, имеющих одну или несколько связанных meeting_yearly_meeting записей, yearly_meeting будетРазделенный запятыми список title записи meeting, который обозначен как ежегодное собрание meeting.Для тех собраний, которые не имеют связанных meeting_yearly_meeting записей (и, следовательно, сами являются ежегодными собраниями), я хочу yearly_meeting field to be NULL`.

На пути к достижению этой цели я попробовал что-то подобное:

SELECT t1.*, t2.meeting_yearly_meeting AS yearly_meeting
FROM (
  SELECT * FROM meeting
  FULL JOIN meeting_yearly_meeting ON meeting.id = meeting_yearly_meeting.yearly_meeting_id;
) as t1, 
(
  SELECT CASE WHEN (meeting_yearly_meeting.id IS NOT NULL)
    THEN (SELECT title FROM meeting WHERE meeting.id = meeting_yearly_meeting.yearly_meeting_id)
    ELSE NULL
    END
  FROM (
    SELECT meeting_yearly_meeting.* FROM meeting
    FULL JOIN meeting_yearly_meeting ON meeting.id = meeting_yearly_meeting.meeting_id
  ) as meeting_yearly_meeting;
) as t2;

Но это вызывает синтаксическую ошибку.

Я ценю любые идеи, которые могут иметь другие.Пожалуйста, дайте мне знать, если вам нужен какой-либо дополнительный контекст или уточнение!

ОБНОВЛЕНИЕ:

Образец meeting данные: https://gist.github.com/micahbales/4013399c3fd23a0caf108124dab827c8

Образец meeting_yearly_meeting данные:https://gist.github.com/micahbales/fcbdeef282bd7bf1014606cee43bfb5e

Пример ожидаемого возвращаемого значения: https://gist.github.com/micahbales/13d2aafdc5d43c4b948dc39c2df51569

1 Ответ

0 голосов
/ 23 сентября 2018

Вы можете попробовать присоединиться к ежегодным собраниям, а затем использовать string_agg(), чтобы получить список с разделителями-запятыми.

SELECT m1.id,
       m1.title,
       m1.mappable,
       m1.phone,
       m1.email,
       m1.city,
       m1.address,
       m1.zip,
       m1.latitude,
       m1.longitude,
       m1.description,
       m1.worship_time,
       m1.state,
       m1.website,
       m1.lgbt_affirming,
       m1.created,
       m1.updated,
       string_agg(m2.title, ', ') yearly_meeting
       FROM meeting m1
            LEFT JOIN meeting_yearly_meeting mym1
                      ON mym1.meeting_id = m1.id
            LEFT JOIN meeting m2
                      ON m2.id = mym1.yearly_meeting_id
       GROUP BY m1.id,
                m1.title,
                m1.mappable,
                m1.phone,
                m1.email,
                m1.city,
                m1.address,
                m1.zip,
                m1.latitude,
                m1.longitude,
                m1.description,
                m1.worship_time,
                m1.state,
                m1.website,
                m1.lgbt_affirming,
                m1.created,
                m1.updated;

Редактировать:

Более "компактный"Решение может заключаться в использовании коррелированного подзапроса.

SELECT m1.*,
       (SELECT string_agg(m2.title, ', ')
               FROM meeting_yearly_meeting mym1
                    LEFT JOIN meeting m2
                              ON m2.id = mym1.yearly_meeting_id
               WHERE mym1.meeting_id = m1.id) yearly_meeting
       FROM meeting m1;

Но обратите внимание, что хотя он и меньше кода, он не обязательно быстрее.

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