MySQL: как использовать GROUP_CONCAT для сравнения с WHERE - PullRequest
0 голосов
/ 20 января 2020

У меня есть 2 таблицы: groups: простой список имен групп и group_users: список групп и их пользователей, например:

group_id user_id
1        2
1        37
1        38
3        14
8        2
8        24
8        27

У меня запрос GROUP_CONCAT который в данный момент работает:

SELECT g.group_id, g.groupname
,GROUP_CONCAT(DISTINCT CONVERT(gu.user_id, CHAR(2)) ORDER BY gu.user_id) AS group_members
FROM group_users gu, groups g
WHERE g.group_id = gu.group_id
GROUP BY gu.group_id
ORDER BY gu.group_id;

Это приводит к результату:

group_id  groupname  group_members
1         Sales      2,37,38
3         Marketing  3
8         Production 2,24,27

Моя проблема : Я пытаюсь получить список групп с указанием c идентификатор пользователя является членом (например, здесь user_id 2 должен создавать строки результатов 1 и 3).

Однако, когда я изменяю критерии WHERE g.group_id = gu.group_id AND gu.user_id = 2, я получаю:

group_id  groupname  group_members
1         Sales      2
8         Production 2

Группы фильтруются правильно, но список group_members ограничен указанным идентификатором.

Я видел много ответов SO, предлагающих использовать HAVING против WHERE, но это приводит к ошибке. Я пробовал JOIN s, это тоже не работает.

Как я могу отфильтровать таблицу groups_users только для таблиц с user_id из 2, а затем получить список всех членов этих group_id s

Ответы [ 4 ]

1 голос
/ 20 января 2020

Вы можете просто ссылаться на group_users дважды, никаких подзапросов не требуется:

SELECT g.group_id, g.groupname
   , GROUP_CONCAT(DISTINCT CONVERT(gu.user_id, CHAR(2)) ORDER BY gu.user_id) AS group_members
FROM group_users AS ug -- the specified User's groups
INNER JOIN groups AS g ON ug.group_id = g.group_id
INNER JOIN group_users AS gu ON g.group_id = gu.group_id
WHERE ug.user_id = 2
GROUP BY g.group_id
ORDER BY g.group_id
;

Также обратите внимание, что этот и каждый другой ответ преобразовал ваш неявный запрос соединения "запятая" в один с явными соединениями JOIN. Это связано с тем, что синтаксис соединения с запятыми считался архаи c и его трудно поддерживать довольно долгое время, и в течение десятилетия его заменяли явным синтаксисом JOIN go для всех, кроме самых простых запросов.

1 голос
/ 20 января 2020

Вы можете добавить запрос для фильтрации желаемых групп:

SELECT g.group_id, g.groupname
,GROUP_CONCAT(DISTINCT CONVERT(gu.user_id, CHAR(2)) ORDER BY gu.user_id) AS group_members
FROM (SELECT group_id FROM group_users WHERE user_id=2) gu1
INNER JOIN group_users gu
ON gu.group_id=gu1.group_id
INNER JOIN groups g
ON g.group_id = gu.group_id
GROUP BY gu.group_id
ORDER BY gu.group_id;
0 голосов
/ 20 января 2020

Одним из вариантов будет использование подзапроса с GROUP_CONCAT(), сгруппированного по столбцу group_id, содержащему предложение having, чтобы проверить наличие user_id=2:

SELECT g.group_id, g.groupname, gu.group_members
  FROM `groups` g
  JOIN (SELECT GROUP_CONCAT(DISTINCT user_id ORDER BY user_id) 
               AS group_members, group_id
          FROM `group_users` 
         GROUP BY group_id
        HAVING COUNT(CASE WHEN user_id = 2 THEN 1 END) > 0
        ) gu
    ON g.group_id = gu.group_id 
 ORDER BY gu.group_id;

+----------+------------+--------------+     
| group_id | groupname  | group_members| 
+----------+------------+--------------+
|  1       | Sales      | 2,37,38      |
|  8       | Production | 2,24,27      |
+----------+------------+--------------+

Использовать могильно-акцентированный groups в качестве имени таблицы, поскольку оно является сохраненным словом.

Демо

0 голосов
/ 20 января 2020

Условие:

WHERE gu.user_id = 2

удаляет строки перед агрегацией. Вместо этого вы можете использовать предложение HAVING:

SELECT g.group_id, g.groupname
,GROUP_CONCAT(DISTINCT gu.user_id ORDER BY gu.user_id) AS group_members
FROM group_users gu INNER JOIN groups g
ON g.group_id = gu.group_id
GROUP BY gu.group_id
HAVING SUM(gu.user_id = 2) > 0
ORDER BY gu.group_id;

Кроме того, почему вы конвертируете user_id s в CHAR(2)? Если user_id больше 99, оно будет усечено. Используйте:

DISTINCT gu.user_id

внутри GROUP_CONCAT() и MySql неявно преобразует целочисленное значение.

...