在 MySQL 中的子查询上使用 GROUP_CONCAT

Posted

技术标签:

【中文标题】在 MySQL 中的子查询上使用 GROUP_CONCAT【英文标题】:Using GROUP_CONCAT on subquery in MySQL 【发布时间】:2010-09-27 12:44:03 【问题描述】:

我有一个 mysql 查询,我想在其中包含另一个表中的 ID 列表。在网站上,人们可以添加某些项目,然后人们可以将这些项目添加到他们的收藏夹中。我基本上想获取收藏该项目的人的 ID 列表(这有点简化,但归根结底就是这样)。

基本上,我会这样做:

SELECT *,
GROUP_CONCAT((SELECT userid FROM favourites WHERE itemid = items.id) SEPARATOR ',') AS idlist
FROM items
WHERE id = $someid

这样,我可以通过稍后在我的代码中将 idlist 拆分为 php 中的数组来显示谁最喜欢某个项目,但是我收到以下 MySQL 错误:

1242 - 子查询返回多于 1 行

我认为这就是使用GROUP_CONCAT 而不是CONCAT 的意义所在?我是不是走错了路?


好的,感谢到目前为止的答案,这似乎有效。但是,有一个问题。如果项目是由该用户添加的,则该项目也被视为收藏夹。所以我需要一个额外的检查来检查creator = userid。有人可以帮我想出一个聪明的(并且希望是有效的)方法来做到这一点吗?

谢谢!

编辑:我只是尝试这样做:

SELECT [...] LEFT JOIN favourites ON (userid = itemid OR creator = userid)

idlist 为空。请注意,如果我使用 INNER JOIN 而不是 LEFT JOIN 我会得到一个空结果。即使我确定有满足 ON 要求的行。

【问题讨论】:

【参考方案1】:

OP 几乎做对了。 GROUP_CONCAT 应该包装子查询中的列,而不是 complete subquery(我正在关闭分隔符,因为逗号是默认值):

SELECT i.*,
(SELECT GROUP_CONCAT(userid) FROM favourites f WHERE f.itemid = i.id) AS idlist
FROM items i
WHERE i.id = $someid

这将产生所需的结果,也意味着接受的答案部分错误,因为您可以在子查询中访问外部范围变量。

【讨论】:

不错,我也在做同样的事情并将 GROUP_CONCAT 放在子查询之外,感谢您的帮助!! 如果我想当版主,我会做出最好的回答,而不是接受一个 @OlegAbrazhaev 这就是这个平台上的支持。 ;-) 非常感谢先生。这应该是公认的答案:)【参考方案2】:

您不能在此类查询中访问外部范围内的变量(不能在那里使用items.id)。你应该尝试类似的东西

SELECT
    items.name,
    items.color,
    CONCAT(favourites.userid) as idlist
FROM
    items
INNER JOIN favourites ON items.id = favourites.itemid
WHERE
    items.id = $someid
GROUP BY
    items.name,
    items.color;

根据需要展开字段列表(名称、颜色...)。

【讨论】:

这可能已经改变,因为我可以使用AS 命令将您的行设置为变量,然后您可以像我经常做的那样从任何范围访问它们 EG SELECT *,(SELECT COUNT(* ) FROM blog_likes WHERE blog_id = B.blog_id ) AS 喜欢的博客 AS B【参考方案3】:

我想你可能把“userid = itemid”弄错了,不应该是这样吗:

SELECT ITEMS.id,GROUP_CONCAT(FAVOURITES.UserId) AS IdList
FROM FAVOURITES 
INNER JOIN ITEMS ON (ITEMS.Id = FAVOURITES.ItemId OR FAVOURITES.UserId = ITEMS.Creator)
WHERE ITEMS.Id = $someid
GROUP BY ITEMS.ID

【讨论】:

【参考方案4】:

GROUP_CONCAT 的目的是正确的,但子查询是不必要的并导致问题。试试这个:

SELECT ITEMS.id,GROUP_CONCAT(FAVOURITES.UserId)
FROM FAVOURITES INNER JOIN ITEMS ON ITEMS.Id = FAVOURITES.ItemId
WHERE ITEMS.Id = $someid
GROUP BY ITEMS.ID

【讨论】:

【参考方案5】:

是的,soulmerge 的解决方案没问题。但我需要一个查询,我必须从更多子表中收集数据,例如:

主表:会话(演示会话)(uid、名称、..) 第一个子表:events 键为 session_id (uid, session_uid, date, time_start, time_end) 第二个子表:accessories_needed(笔记本电脑、投影仪、麦克风等),键为 session_id(uid、session_uid、accessory_name) 第三个子表:session_presenters(演示者个人),带有 key session_id(uid、session_uid、presenter_name、address...)

每个 Session 在子表中都有更多行(更多时间表,更多附件)

而且我需要为每个会话收集一个集合以显示在矿石行中(其中一些):

session_id | session_name | date | time_start | time_end | accessories | presenters

我的解决方案(经过数小时的实验):

SELECT sessions.uid, sessions.name,
    ,(SELECT GROUP_CONCAT( `events`.date SEPARATOR '</li><li>') 
            FROM `events` 
            WHERE `events`.session_id = sessions.uid ORDER BY `events`.date) AS date
    ,(SELECT GROUP_CONCAT( `events`.time_start SEPARATOR '</li><li>') 
            FROM `events` 
            WHERE `events`.session_id = sessions.uid ORDER BY `events`.date) AS time_start
    ,(SELECT GROUP_CONCAT( `events`.time_end SEPARATOR '</li><li>') 
            FROM `events` 
            WHERE `events`.session_id = sessions.uid ORDER BY `events`.date) AS time_end
    ,(SELECT GROUP_CONCAT( accessories.name SEPARATOR '</li><li>') 
            FROM accessories 
            WHERE accessories.session_id = sessions.uid ORDER BY accessories.name) AS accessories
    ,(SELECT GROUP_CONCAT( presenters.name SEPARATOR '</li><li>') 
            FROM presenters
            WHERE presenters.session_id = sessions.uid ORDER BY presenters.name) AS presenters

    FROM sessions

因此不需要 JOIN 或 GROUP BY。 友好地显示数据的另一件有用的事情(当“回显”它们时):

您可以将 events.date、time_start、time_end 等包装在“ ... ”中,以便将“ ”用作分隔符在查询中将分隔列表项中的结果。

我希望这对某人有所帮助。干杯!

【讨论】:

不管你想要完成什么——你在这里混合了存储和视图层。你永远不应该使用数据库来准备 html 输出,你正在混合图层,这真的很难维护:-\ 可维护性是一方面,另一方面是性能。 ''-元素可以添加到服务器端或客户端。关于性能的最坏选择是获取大量行,使用服务器端语言添加“ ”元素,例如。 PHP,因为您必须在 PHP 中遍历数组才能将那些 ' ' 元素放在正确的位置。所以最好放弃PHP并在MYSQL中生成字符串。但最好的选择是使用 GROUP_CONCAT 生成实际数据的序列化 javascript 数组/对象并添加那些 :s 客户端。客户通常是需要那些“ ”的人。

以上是关于在 MySQL 中的子查询上使用 GROUP_CONCAT的主要内容,如果未能解决你的问题,请参考以下文章

mysql中的多行查询结果合并成一个

mysql中的多行查询结果合并成一个(转)

为啥 MySQL 会挂在这个简单的子查询上?

MySQL INSERT 在同一张表上使用带有 COUNT() 的子查询

MySQL基础语法之子链接查询和特殊查询(union 和 limit)

MySQL的子查询中FROM和EXISTS子句的使用教程