Эффективный запрос для объединения трех таблиц

1

В моем приложении есть таблица users таблица teams таблица teams_users и таблица assessments. упрощенно:

**users**
id

**teams**
id

**teams_users**
team_id
user_id

**assessments**
id
user_id
team_id

Пользователь может иметь множество оценок.

Когда я захватываю пользователей в определенном контексте, я хочу также получить их связанные оценки (весь объект) плюс значение в качестве возвращаемого пользователя, team_ids которые по существу являются результатом выщипывания столбца team_id для всех строк в таблица teams_users с пользователем user_id.

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

SELECT users.id, users.name, users.email, users.role
FROM users
INNER JOIN assessments ON assessments.user_id = users.id
WHERE users.id='someID'

В этом вопросе, однако, я на самом деле ничего не делаю с оценками. Поэтому я рассматривал что-то вроде этого:

SELECT users.id, users.name, users.email, users.role, assessments
FROM users
INNER JOIN assessments ON assessments.user_id = users.id
WHERE users.id='someID'

Этот SORT работает, но возвращает оценки в виде массива значений с разделителями в круглых скобках (я использую JavaScript, а библиотека pg противном случае анализирует ответы в JSON), что лучше исправлять на уровне SQL, чем анализировать в JSON:

{
    id: 'mEPRVHp3',
    name: 'Frank',
    role: 'admin',
    assessments: '(uibbH0ff,rPWZDIoA,mEPRVHp3,99,2017-12-01)' 
}

Чтобы уточнить, я бы предпочел это так:

{
    id: 'mEPRVHp3',
    name: 'Frank',
    role: 'admin',
    assessments: [
     { 
       id: 'uibbH0ff',
       team_id: 'rPWZDIoA',
       user_id: 'mEPRVHp3',
       score: 99,
       date: '2017-12-01'
     }
   ]
}

Тогда отдельно, мне бы хотелось захватить teams_users team_id в том же запросе. Чтобы окончательный ответ был примерно таким:

{
    id: 'mEPRVHp3',
    name: 'Frank',
    role: 'admin',
    assessments: [
     { 
       id: 'uibbH0ff',
       team_id: 'rPWZDIoA',
       user_id: 'mEPRVHp3',
       score: 99,
       date: '2017-12-01'
     }
   ],
   team_ids: ['rPWZDIoA']
}

Попробовал добавить teams_users.team_id AS team_ids в конец инструкции SELECT, но это сломало весь запрос.

Опять же, не уверен, что это возможно, и в этом случае не ВСЕ уверенно, как это сделать.

Какие-нибудь мысли? Работа над моим ограниченным умением SQL.

Спасибо!

Теги:
pg

1 ответ

2
Лучший ответ

Предполагая, что вы используете PostgreSQL версии 9.3 или новее.

Я бы использовал row_to_json() для "форматирования" записи оценки. Затем я буду использовать боковое соединение, чтобы получить идентификаторы вашей команды.

Вот так:

SELECT
    usr.id,
    usr.name, 
    usr.email,
    usr.role,
    row_to_json(asmnt) AS assessments, --Use row_to_json()
    tusr.team_ids
FROM
    users usr
INNER JOIN
    assessments asmnt
    ON asmnt.user_id = usr.id
INNER JOIN LATERAL
    (
    SELECT
        array_agg(teams_users.team_id) AS team_ids
    FROM
        teams_users
    WHERE
        teams_users.user_id = usr.id
    ) tusr
    ON TRUE
WHERE
    usr.id = 'someID';
  • 0
    Это круто! Спасибо! Столкнулся с одной проблемой - assessments форматируются как один объект JSON (имеет смысл), но у пользователя может быть много оценок. Я попытался array_to_json(asmnt) но была array_to_json(asmnt) ошибка, говорящая, что это не функция. Любые идеи, как это исправить? Спасибо!
  • 0
    Понял! jsonb_build_array работал как шарм! postgresql.org/docs/9.5/static/functions-json.html

Ещё вопросы

Сообщество Overcoder
Наверх
Меню