在 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 INSERT 在同一张表上使用带有 COUNT() 的子查询