Подтвердить что ты не робот

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

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

В принципе, я делаю что-то вроде этого:

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

Таким образом, я смог бы показать, кому понравился какой-то элемент, разделив список идентификаторов позже на массив в 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.

4b9b3361

Ответ 1

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

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

Ответ 2

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

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

Ответ 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, name,..)
  • Таблица 1-го ребенка: события с ключом session_id (uid, session_uid, date, time_start, time_end)
  • 2-й детский стол: accessories_needed (ноутбук, проектор, микрофоны и т.д.) с ключом session_id (uid, session_uid, имя_адреса)
  • 3-я дочерняя таблица: session_presenters (лица-презентаторы) с ключом session_id (uid, session_uid, имя-презентатора, адрес...)

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

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

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. Еще одна полезная вещь для отображения данных, дружественных (когда их "эхом" ):

  • вы можете обернуть события event.date, time_start, time_end и т.д. в <UL> <LI> </LI> </UL> поэтому "<LI> </LI> " используемый в качестве разделителя в запросе, будет отделять результаты в элементах списка.

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