m1n64
@m1n64
Fullstack Web Developer

Проблема с объединением нескольких таблиц MySQL?

Здравствуйте. У меня имеются три таблицы - условно TABLE 1, TABLE 2 и TABLE BIND. В таблице 1 находятся какие-нибудь продукты каталога, а в таблице 2 - фотографии. Таблица TABLE BIND сопоставляет по ID продукт каталога с картинками для этого продукта.
6211337f07a2c875104704.png

В чём собственно и заключается проблема - мне нужно вытянуть к продукту из таблицы 1 все картинки, которые сопоставляются с этим продуктом в таблице BIND. То есть в таблице BIND находится несколько записей у которых условно TABLE 1 ID равно 1, но TABLE 2 ID равняется 1, 2, 3 и т.д.
ID TABLE 1 ID TABLE 2 ID
1 1 1
2 1 2
3 2 3
4 2 4


И мне нужно вытянуть все картинки для определённой записи. Но стандартным объединением через JOIN запись одного продукта на выходе получется столько раз, сколько картинок к ней сопоставлено, например
ID NAME DESCRIPTION PHOTO
1 Prod 1 Desc 46372842.png
1 Prod 1 Desc 75843932.png
2 Prod 2 Desc 2 fjdskjkdsfgds.png
2 Prod 2 Desc 2 fhdgkhueriwyui.png


Возможно ли вообще сделать так, что бы все записи с продуктами выводились только по одному разу, но при этом были сопоставлены все картинки, и если возможно - то как? На объединение через GROUP BY через TABLE 1.ID ругается:
SELECT list is not in GROUP BY clause and contains nonaggregated column '*DATABASE*.*TABLE NAME*.id' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
  • Вопрос задан
  • 98 просмотров
Решения вопроса 1
@Akela_wolf
Extreme Programmer
Во-первых, стрелки на диаграмме принято рисовать в другую сторону - это таблица связи ссылается на таблицу продуктов и на таблицу фотографий.
Во-вторых, то чего вы хотите, сделать можно но это неправильный путь. Правильных путей тут два:
  1. Построить запрос, который выбирает продукты по определенному условию и присоединяет к ним картинки. В этом случае у вас будет несколько записей на один продукт, отличающихся только картинками (это, я так понимаю, вы сумели сделать). Обрабатывать это не очень удобно, но зато один запрос в БД.
  2. Выбрать сначала продукты, а затем к продуктам выбрать фотографии. Потребуется сопоставить фотографии с продуктами (по ID) на уровне приложения. Зато два запроса в БД и каждый возвращает свой набор требуемых данных.


Третий правильный путь - использовать ORM, которая возьмет на себя извлечение данных из БД.

Неправильный (на мой взгляд) путь - использовать агрегирующие функции, как-то так:
SELECT p.*, JSON_ARRAYAGG(f.filename) AS files FROM product p
LEFT JOIN product2file p2f ON p2f.product_id=p.id
LEFT JOIN file f ON p2f.file_id=f.id
GROUP BY p.id;

Пример

Но я считаю этот путь неправильным, потому что: с ростом сложности БД сложность подобных запросов быстро растет и тут начинают вылазить ошибки. А еще потому что вытащить из подчиненной таблицы 2 колонки можно, но порядок элементов в функции JSON_ARRAYAGG не определен, поэтому начинается возня с тем чтобы все это сопоставить. GROUP_CONCAT тоже имеет проблемы (в первую очередь ограничение длины).

Так что, мне кажется, лучше привыкать к тому что запрос может возвращать несколько строк для одной сущности и учиться с этим работать на уровне приложения, чем извращаться в запросе.
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 1
rozhnev
@rozhnev Куратор тега MySQL
Fullstack programmer, DBA, медленно, дорого
Пожалуйста, посмотрите ниже пример

select items.id, items.name, group_concat(img) images
from items
join item_images on items.id = item_images.item_id
join images on images.id = item_images.image_id
group by items.id, items.name;


SQL online test queries
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы