Объединение таблиц «Многие ко многим» с помощью Pivot

#mysql #many-to-many #pivot

#mysql #»многие ко многим» #pivot

Вопрос:

В настоящее время у меня есть две таблицы, похожие на users и programs , которые связаны через отношения «многие ко многим» посредством link таблицы.

 mysql> select * from users;
 ---- ---------- 
| id | name     |
 ---- ---------- 
|  1 | Jonathan |
|  2 | Little   |
|  3 | Annie    |
|  4 | Bob      |
 ---- ---------- 
4 rows in set (0.00 sec)

mysql> select * from programs;
 ---- ---------------------- 
| id | name                 |
 ---- ---------------------- 
|  1 | Microsoft Word       |
|  2 | Microsoft Excel      |
|  3 | Microsoft PowerPoint |
 ---- ---------------------- 
3 rows in set (0.00 sec)

mysql> select * from link;
 --------- ------------ 
| user_id | program_id |
 --------- ------------ 
|       1 |          1 |
|       1 |          2 |
|       1 |          3 |
|       2 |          2 |
|       3 |          1 |
|       3 |          4 |
 --------- ------------ 
6 rows in set (0.00 sec)
  

Я понимаю, как объединять таблицы и возвращать результат такого рода:

 mysql> select users.name, programs.name from linker
    -> join users on users.id = linker.user_id
    -> join programs on programs.id = linker.program_id;
 ---------- ---------------------- 
| name     | name                 |
 ---------- ---------------------- 
| Jonathan | Microsoft Word       |
| Jonathan | Microsoft Excel      |
| Jonathan | Microsoft PowerPoint |
| Little   | Microsoft Excel      |
| Annie    | Microsoft Word       |
 ---------- ---------------------- 
  

Но то, что я действительно ищу, немного сложнее:

  ---------- ----------------------------------------------------- 
| name     | name                                                |
 ---------- ----------------------------------------------------- 
| Jonathan | Microsoft Word,Microsoft Excel,Microsoft PowerPoint |
| Little   | Microsoft Excel                                     |
| Annie    | Microsoft Word                                      |
 ---------- ----------------------------------------------------- 
  

Я предполагаю, что где-то в команде есть GROUP_CONCAT() , но, похоже, я не могу заставить результаты выглядеть так:

 mysql> select users.name, group_concat(programs.name) from linker
    -> join users on users.id = linker.user_id
    -> join programs on programs.id = linker.program_id;
 ---------- ------------------------------------------------------------------------------------ 
| name     | group_concat(programs.name)                                                        |
 ---------- ------------------------------------------------------------------------------------ 
| Jonathan | Microsoft Word,Microsoft Excel,Microsoft PowerPoint,Microsoft Excel,Microsoft Word |
 ---------- ------------------------------------------------------------------------------------ 
  

Кто-нибудь может указать мне правильное направление?

Ответ №1:

Вам нужно указать DISTINCT , т.е.

 select users.name, group_concat( DISTINCT programs.name)
  

Смотрите документы MySQL здесь.

Попробуйте изменить свой запрос на:

 SELECT users.name, group_concat(programs.name) 
from users
LEFT JOIN linker on linker.user_id = users.id
LEFT JOIN programs on linker.program_id = programs.id
GROUP BY users.id
  

Это даст вам null для любого пользователя, с которым не связаны программы. Чтобы отфильтровать их, просто добавьте WHERE programs.id IS NOT NULL .

Комментарии:

1. Это устраняет повторяющиеся значения, но также ограничивает результаты первой строкой.

2. Обновлен ответ — попробуйте запрос выше.

3. Ах, это было GROUP BY предложение, которое я пропустил. Большое вам спасибо!

Ответ №2:

 SELECT users.name, group_concat(programs.name) from linker
INNER JOIN users on linker.user_id = users.id
INNER JOIN programs on linker.program_id = programs.id
GROUP BY users.id;
  

Комментарии:

1. Это по-прежнему возвращает только первую строку, включая дополнительные (повторяющиеся) имена программ. Я думаю, что тест на равенство вычисляется одинаково независимо от порядка.

2. @kpsfire аааа! да, вы правы, моя ошибка, порядок важен, когда вы используете левое или правое объединение.