Group_concat работает некорректно при множественном соединении

У меня проблема с созданием запроса на выборку с данными объединения и конкатенации из 3 таблиц.

Первая сущность таблицы имеет идентификаторы некоторых сущностей с их авторами:

идентификатор автор 11 "Джон" 12 "Майк" 13 "Кевин"

2-я и 3-я таблицы имеют разделы и файлы, относящиеся к этим объектам, по одной строке для каждого. Количество разделов и файлов может быть разным для любой сущности.

файл:

идентификатор entity_id имя файла 1 11 файл1 2 12 файл1 3 12 файл2 4 12 файл3 5 13 файл4 6 13 файл5 7 13 файл6

раздел (также некоторые объекты могут быть без разделов, например 12 в этом примере):

идентификатор entity_id section_id 1 11 1001 2 11 1002 3 13 1003

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

SELECT 
    entity.id, 
    entity.author, 
    group_concat(section.section_id) section_ids, 
    group_concat(file.file_name) files 
FROM entity
LEFT JOIN file ON entity.id = file.entity_id
LEFT JOIN section ON entity.id = section.entity_id
group by entity.id;

Я ожидаю получить следующий результат:

идентификатор автор файлы section_ids 11 "Джон" файл1 1001 1002 12 "Майк" файл1, файл2, файл3 нулевой 13 "Кевин" файл4, файл5, файл6 1003

Но на самом деле я получаю это:

идентификатор автор файлы section_ids 11 "Джон" файл1,файл1 1001 1002 12 "Майк" файл1, файл2, файл3 нулевой 13 "Кевин" файл4, файл5, файл6 1003 1003 1003

Похоже, что файлы дублируются, если объект имеет несколько разделов, и разделы дублируются, если объект имеет несколько файлов. Я пробовал играть с разными типами соединения (внутреннее/внешнее, правое/левое), но не нашел решения. Пожалуйста, помогите мне исправить этот запрос.

Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
В последние годы архитектура микросервисов приобрела популярность как способ построения масштабируемых и гибких приложений. Laravel , популярный PHP...
Как построить CRUD-приложение в Laravel
Как построить CRUD-приложение в Laravel
Laravel - это популярный PHP-фреймворк, который позволяет быстро и легко создавать веб-приложения. Одной из наиболее распространенных задач в...
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
В предыдущем посте мы создали функциональность вставки и чтения для нашей динамической СУБД. В этом посте мы собираемся реализовать функции обновления...
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
Роли и разрешения пользователей без пакета Laravel 9
Роли и разрешения пользователей без пакета Laravel 9
Этот пост изначально был опубликован на techsolutionstuff.com .
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
В предыдущей статье мы завершили установку базы данных, для тех, кто не знает.
1
0
304
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

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

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

select e.id, e.author, 
    (select group_concat(f.file_name) from file f where f.entity_id = e.id) as files_names
    (select group_concat(s.section_id) from section s where s.entity_id = e.id) as section_ids
from entity e

Вы объединяете два разных измерения, в результате чего получается декартово произведение. Самая простая корректировка вашего запроса — DISTINCT:

SELECT e.id, e.author, 
      group_concat(distinct s.section_id) as section_ids, 
      group_concat(f.file_name) as files 
FROM entity e LEFT JOIN
     file f
     ON e.id = f.entity_id LEFT JOIN
     section s
     ON e.id = s.entity_id
group by e.id;

Однако для производительности я бы рекомендовал подход, который предлагает GMB.

Итак, вы открыли вопрос, который я закрыл как дубликат, и разместили в качестве своего ответа ответ на дубликат ссылки: stackoverflow.com/questions/3083499/…?

forpas 24.12.2020 16:12

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

forpas 24.12.2020 16:23

Другие вопросы по теме