MySQL: 如何使用 GROUP_CONCAT 与 WHERE 比较

MySQL: How to use GROUP_CONCAT with WHERE comparison

我有 2 个 tables: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

我的问题:我正在尝试获取特定用户 ID 所属的组的列表(例如,此处 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 列表仅限于所述 ID。

我看到许多 SO 答案建议使用 HAVINGWHERE,但这会产生错误。我试过 JOINs,那也不管用。

如何将 groups_users table 过滤为仅 user_id 为 2 的成员,然后获取那些 group_id 的所有成员的列表?

您可以添加查询来过滤所需的组:

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;

条件:

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 转换为 CHAR(2)
如果 user_id 大于 99,它将被截断。
使用:

DISTINCT gu.user_id

inside GROUP_CONCAT() and MySql 将隐式转换整数值。

一个选项是使用子查询 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 作为 table 名称,因为它是一个保留词。

Demo

您可以只引用 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
;

另请注意,这个以及迄今为止的所有其他答案都将您的隐式 "comma" 连接查询转换为具有显式连接的查询。这是因为逗号连接语法在很长一段时间内一直被认为是陈旧且难以维护的,并且在十多年前几乎被显式 JOIN 语法所取代,除了最简单的查询之外。