Как правильно собирать данные с разных таблиц БД?
У меня есть такие таблицы в БД:
Как мне получить такую структуру данных из sql запроса ?
export type Author = { account_id: number; first_name: string; last_name: string; } export type Posts = { post_id: number; body: string; author: Author; } |
export type Author = { account_id: number; first_name: string; last_name: string; } export type Posts = { post_id: number; body: string; author: Author; }
ps: так как данные находятся в разных таблицах, получается что нужно сделать сначала один запрос к базе (получить посты), потом второй (получить авторов), и далее уже соединять их в JavaScript, или можно как-то получить и через запрос SQL такую структуру ?
pss: там еще комментарии нужно получить, я до них еще не добрался.
Дополнительно:
https://dev.mysql.com/doc/refman/8.0/en/join.html
так я получу плоский список, а мне вложенность нужна
Результат выполнения запроса - это абсолютно всегда плоский список/таблица.
Если надо получить "третье измерение", то это можно сделать только путём получения в поле выходного набора сериализованного значения необходимой мерности. Если достаточно одного уровня, сойдёт и CSV, иначе - никакой альтернативы, только JSON. Извращения типа создания XML строковыми функциями рассматривать не будем.
const posts = { post_id: 0, body: 'Post Title', author: { account_id: 0, first_name: 'Jane', last_name: 'Doe' }, commits: [ { commit_id: 0, body: 'Commit message', author: { account_id: 2, first_name: 'Jhon', last_name: 'Doe' } // ... } ] } |
const posts = { post_id: 0, body: 'Post Title', author: { account_id: 0, first_name: 'Jane', last_name: 'Doe' }, commits: [ { commit_id: 0, body: 'Commit message', author: { account_id: 2, first_name: 'Jhon', last_name: 'Doe' } // ... } ] }
ps: как я понял, это делается вне БД а на серверном языке программирования.
делайте как вам легче , поддерживать вам.
смотри мой ответ.
Для построения такого JSON на SQL вам нужны функции json_agg() / json_build_object(), далее обычные запросы с объединениями и группировкой.
Пример как собрать JSON author
SELECT json_build_object( 'account_id', id, 'first_name', first_name, 'last_name', last_name ) AS author FROM accounts |
SELECT json_build_object( 'account_id', id, 'first_name', first_name, 'last_name', last_name ) AS author FROM accounts
post собирается как
json_build_object( 'post_id', p.id, 'body', p.body, 'author', json_build_object( 'account_id', a.id, 'first_name', a.first_name, 'last_name', a.last_name ) ) |
json_build_object( 'post_id', p.id, 'body', p.body, 'author', json_build_object( 'account_id', a.id, 'first_name', a.first_name, 'last_name', a.last_name ) )
при объединении таблиц posts и accounts
через json_agg собираем в массив
SELECT json_agg(json_build_object( 'post_id', p.id, 'body', p.body, 'author', json_build_object( 'account_id', a.id, 'first_name', a.first_name, 'last_name', a.last_name ) )) AS posts FROM posts p JOIN accounts a ON a.id = p.author_id |
SELECT json_agg(json_build_object( 'post_id', p.id, 'body', p.body, 'author', json_build_object( 'account_id', a.id, 'first_name', a.first_name, 'last_name', a.last_name ) )) AS posts FROM posts p JOIN accounts a ON a.id = p.author_id
комментарии аналогично, но с группировкой по постам - post_id
SELECT json_agg(json_build_object( 'comment_id', c.id, 'body', c.body, 'author', json_build_object( 'account_id', a.id, 'first_name', a.first_name, 'last_name', a.last_name ) )) AS comments FROM comments c JOIN accounts a ON a.id = c.author_id GROUP BY post_id |
SELECT json_agg(json_build_object( 'comment_id', c.id, 'body', c.body, 'author', json_build_object( 'account_id', a.id, 'first_name', a.first_name, 'last_name', a.last_name ) )) AS comments FROM comments c JOIN accounts a ON a.id = c.author_id GROUP BY post_id
далее объединяем комментарии с постами через post_id = id
для удобства комментарии вынес в CTE (общее табличное выражение)
WITH cmts AS ( SELECT json_agg(json_build_object( 'comment_id', c.id, 'body', c.body, 'author', json_build_object( 'account_id', a.id, 'first_name', a.first_name, 'last_name', a.last_name ) )) AS comments, post_id FROM comments c JOIN accounts a ON a.id = c.author_id GROUP BY post_id ) SELECT json_agg(json_build_object( 'post_id', p.id, 'body', p.body, 'author', json_build_object( 'account_id', a.id, 'first_name', a.first_name, 'last_name', a.last_name ), 'comments', COALESCE(c.comments, '[]') )) AS "posts with comments" FROM posts p JOIN accounts a ON a.id = p.author_id LEFT JOIN cmts c ON c.post_id = p.id |
WITH cmts AS ( SELECT json_agg(json_build_object( 'comment_id', c.id, 'body', c.body, 'author', json_build_object( 'account_id', a.id, 'first_name', a.first_name, 'last_name', a.last_name ) )) AS comments, post_id FROM comments c JOIN accounts a ON a.id = c.author_id GROUP BY post_id ) SELECT json_agg(json_build_object( 'post_id', p.id, 'body', p.body, 'author', json_build_object( 'account_id', a.id, 'first_name', a.first_name, 'last_name', a.last_name ), 'comments', COALESCE(c.comments, '[]') )) AS "posts with comments" FROM posts p JOIN accounts a ON a.id = p.author_id LEFT JOIN cmts c ON c.post_id = p.id
см. пример sqlfiddle
- круто, кажись работает. Правда для knex я так и не нашел этих функции...
Опишите проблему, и специалист поможет с настройкой, исправлением ошибки или доработкой сайта. Подберём понятный план работ без лишней переписки.
Пока нет других ответов. Будьте первым, кто поможет автору.
Ответить на вопрос

Для сбора данных с разных таблиц в базе данных (БД) вам потребуется использовать соединение таблиц. Существует несколько способов выполнения этой операции, в зависимости от ваших потребностей.
1. Внутреннее соединение (INNER JOIN):
INNER JOIN позволяет объединить строки из разных таблиц, у которых есть совпадающие значения в указанных столбцах. Например, если у вас есть таблицы "users" и "orders", и вы хотите получить данные о заказах и пользователях, которые сделали эти заказы, вы можете использовать INNER JOIN по идентификатору пользователя.
SELECT users.name, orders.order_id FROM users INNER JOIN orders ON users.user_id = orders.user_id;
2. Левое соединение (LEFT JOIN):
LEFT JOIN возвращает все строки из левой таблицы и соответствующие строки из правой таблицы. Если нет соответствия, то значения в правой таблице будут NULL. Например, если вы хотите получить список всех пользователей и их заказов (если они есть), вы можете использовать LEFT JOIN.
SELECT users.name, orders.order_id FROM users LEFT JOIN orders ON users.user_id = orders.user_id;
3. Правое соединение (RIGHT JOIN):
RIGHT JOIN возвращает все строки из правой таблицы и соответствующие строки из левой таблицы. Если нет соответствия, то значения в левой таблице будут NULL. Этот тип соединения редко используется, так как его можно заменить на LEFT JOIN.
SELECT users.name, orders.order_id FROM users RIGHT JOIN orders ON users.user_id = orders.user_id;
4. Полное соединение (FULL JOIN):
FULL JOIN возвращает все строки из обеих таблиц, даже если нет соответствия. Если нет соответствия, то значения будут NULL. Этот тип соединения также редко используется из-за своей сложности.
SELECT users.name, orders.order_id FROM users FULL JOIN orders ON users.user_id = orders.user_id;
При работе с данными из разных таблиц БД важно правильно определять связи между ними и выбирать подходящий тип соединения для вашего конкретного случая. Таким образом, вы сможете эффективно собирать данные и использовать их в своем приложении или отчете.