Использование GROUP CONCAT на подзапросе в MySQL

у меня есть запрос MySQL, в который я хочу включить список идентификаторов из другой таблицы. На веб-сайте люди могут добавлять определенные элементы, а затем добавлять их в избранное. Я в основном хочу получить список идентификаторов людей, которые отдали предпочтение этому элементу (это немного упрощено, но это то, что он сводится к).

в основном, я делаю что-то вроде этого:

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. Может ли кто-нибудь помочь мне придумать умный (и, надеюсь, эффективный) способ сделать это?

спасибо!

Edit: я просто попытался сделать это:

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

и idlist пусто. Обратите внимание, что если я использую INNER JOIN вместо LEFT JOIN я получаю пустой результат. Хотя я уверен, что есть строки, которые отвечают на требование.

5 ответов


вы не можете получить доступ к переменным во внешней области в таких запросах (не можете использовать 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;

разверните список полей по мере необходимости (имя, цвет...).


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

это даст желаемый результат, а также означает, что принятый ответ частично неверен, потому что вы можете получить доступ к внешним переменным области в подзапросе.


Я думаю, что вы можете иметь" 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

цель 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

Да, решение soulmerge в порядке. Но мне нужен был запрос, где я должен был собирать данные из более дочерних таблиц, например:

  • основная таблица: сеансы (сеансы презентации) (uid, name,..)
  • 1. ребенок стол: событий С ключом session_id (uid, session_uid, date, time_start, time_end)
  • 2-й детский стол:accessories_needed (ноутбук, проектор, микрофоны и т. д.) с ключом session_id (uid, session_uid, accessory_name)
  • 3-й детский стол:session_presenters (presenter persons) с ключом session_id (uid, session_uid, presenter_name, address...)

каждый сеанс имеет больше строк в таблицах дочерних таблиц (больше графиков времени, больше аксессуаров)

и мне нужно было собрать в одну коллекцию для каждого сеанса, чтобы отобразить в строке руды (некоторые из них):

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

поэтому нет необходимости присоединяться или группировать. Еще одна полезная вещь для отображения дружественных данных (когда " эхо " их):

  • вы можете обернуть события.дата, time_start, time_end и т. д. В "
    • ... " таким образом, "
    • ", используемый в качестве разделителя в запросе, разделит результаты в элементах списка.

надеюсь, это кому-то поможет. Ура!