在 MySQL 中的子查询上使用 GROUP_CONCAT

发布于 2024-07-11 02:33:20 字数 953 浏览 7 评论 0原文

我有一个 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 的意义所在? 我是否以错误的方式处理这个问题?


好的,感谢到目前为止的回答,这似乎有效。 然而,有一个问题。 如果项目是由该用户添加的,则也被视为最喜欢的项目。 所以我需要额外的检查来检查创建者是否=用户ID。 有人可以帮我想出一种聪明的(希望是有效的)方法来做到这一点吗?

谢谢你!

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

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

并且 idlist 是空的。 请注意,如果我使用 INNER JOIN 而不是 LEFT JOIN 我会得到一个空结果。 尽管我确信有些行满足 ON 要求。

I have a MySQL query in which I want to include a list of ID's from another table. On the website, people are able to add certain items, and people can then add those items to their favourites. I basically want to get the list of ID's of people who have favourited that item (this is a bit simplified, but this is what it boils down to).

Basically, I do something like this:

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

This way, I would be able to show who favourited some item, by splitting the idlist later on to an array in PHP further on in my code, however I am getting the following MySQL error:

1242 - Subquery returns more than 1 row

I thought that was kind of the point of using GROUP_CONCAT instead of, for example, CONCAT? Am I going about this the wrong way?


Ok, thanks for the answers so far, that seems to work. However, there is a catch. Items are also considered to be a favourite if it was added by that user. So I would need an additional check to check if creator = userid. Can someone help me come up with a smart (and hopefully efficient) way to do this?

Thank you!

Edit: I just tried to do this:

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

And idlist is empty. Note that if I use INNER JOIN instead of LEFT JOIN I get an empty result. Even though I am sure there are rows that meet the ON requirement.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

深巷少女 2024-07-18 02:33:20

OP几乎猜对了。 GROUP_CONCAT 应该将列包装在子查询中,而不是完整子查询(我不予考虑)分隔符,因为逗号是默认值):

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

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

OP almost got it right. GROUP_CONCAT should be wrapping the columns in the subquery and not the complete subquery (I'm dismissing the separator because comma is the default):

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

This will yield the desired result and also means that the accepted answer is partially wrong, because you can access outer scope variables in a subquery.

水水月牙 2024-07-18 02:33:20

您无法在此类查询中访问外部作用域中的变量(不能在那里使用 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;

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

You can't access variables in the outer scope in such queries (can't use items.id there). You should rather try something like

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;

Expand the list of fields as needed (name, color...).

夕嗳→ 2024-07-18 02:33:20

我认为你可能有“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

I think you may have the "userid = itemid" wrong, shouldn't it be like this:

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
爱已欠费 2024-07-18 02:33:20

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

The purpose of GROUP_CONCAT is correct but the subquery is unnecessary and causing the problem. Try this instead:

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
物价感观 2024-07-18 02:33:20

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

  • 主表:会话(演示会话)(uid,名称,..)
  • 第一个子表:事件 带有关键 session_id(uid、session_uid、日期、time_start、time_end)
  • 第二个子表:accessories_needed(笔记本电脑、投影仪、麦克风等)带有关键 session_id(uid、session_uid、accessory_name)
  • 第三个子表:session_presenters(演示者),带有关键session_id(uid、session_uid、presenter_name、地址...)

每个会话在子表中都有更多行(更多时间表、更多附件)

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

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 等包装在“
    • ...
    • ” 在查询中用作分隔符将分隔列表项中的结果。

我希望这可以帮助别人。 干杯!

Yes, soulmerge's solution is ok. But I needed a query where I had to collect data from more child tables, for example:

  • main table: sessions (presentation sessions) (uid, name, ..)
  • 1st child table: events with key session_id (uid, session_uid, date, time_start, time_end)
  • 2nd child table: accessories_needed (laptop, projector, microphones, etc.) with key session_id (uid, session_uid, accessory_name)
  • 3rd child table: session_presenters (presenter persons) with key session_id (uid, session_uid, presenter_name, address...)

Every Session has more rows in child tables tables (more time schedules, more accessories)

And I needed to collect in one collection for every session to display in ore row (some of them):

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

My solution (after many hours of experiments):

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

So no JOIN or GROUP BY needed.
Another useful thing to display data friendly (when "echoing" them):

  • you can wrap the events.date, time_start, time_end, etc in "<UL><LI> ... </LI></UL>" so the "<LI></LI>" used as separator in the query will separate the results in list items.

I hope this helps someone. Cheers!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文