Usando GROUP_CONCAT na subconsulta no MySQL
-
22-08-2019 - |
Pergunta
Eu tenho uma consulta MySQL em que eu quiser incluir uma lista de ids de outra tabela.No site, as pessoas são capazes de adicionar alguns itens, e as pessoas podem, em seguida, adicionar os itens aos seus favoritos.Eu, basicamente, quer para obter a lista de IDENTIFICAÇÃO de pessoas que têm liked item (isto é um pouco simplificado, mas isso é o que ferve para baixo).
Basicamente, eu faço algo parecido com isto:
SELECT *,
GROUP_CONCAT((SELECT userid FROM favourites WHERE itemid = items.id) SEPARATOR ',') AS idlist
FROM items
WHERE id = $someid
Desta forma, eu seria capaz de mostrar que liked algum item, dividindo o idlist mais tarde, para um array no PHP no meu código, no entanto estou recebendo o seguinte MySQL erro:
1242 - a Subconsulta retorna mais de 1 linha
Eu pensei que era uma espécie de ponto de usar GROUP_CONCAT
em vez de, por exemplo, CONCAT
?Estou indo sobre isso da maneira errada?
Ok, obrigado pelas respostas até agora, que parece funcionar.No entanto, há um senão.Os itens também são considerados para ser um favorito se ele foi adicionado pelo usuário.Então eu teria uma verificação adicional para verificar se o criador = userid.Alguém pode me ajudar a encontrar um smart (e espero eficiente) maneira de fazer isso?
Obrigado!
Editar:Eu apenas tentei fazer isso:
SELECT [...] LEFT JOIN favourites ON (userid = itemid OR creator = userid)
E idlist é vazio.Observe que, se eu usar INNER JOIN
em vez de LEFT JOIN
Eu obter um resultado vazio.Embora eu tenho certeza que não são linhas que atendem o requisito.
Solução
Você não pode variáveis ??de acesso no âmbito exterior em tais consultas (não pode usar items.id
lá). Você deve, antes, tentar algo como
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;
Expanda a lista de campos conforme necessário (nome, cor ...).
Outras dicas
OP quase acertou. GROUP_CONCAT
deve ser envolver as colunas na subconsulta e não o subconsulta completo (eu estou descartando o separador porque vírgula é o padrão ):
SELECT i.*,
(SELECT GROUP_CONCAT(userid) FROM favourites f WHERE f.itemid = i.id) AS idlist
FROM items i
WHERE i.id = $someid
Isto irá produzir o resultado desejado e também significa que a resposta aceita é parcialmente errado, porque você pode acessar variáveis ??escopo externo em uma subconsulta.
Eu acho que você pode ter a "userid = itemid" errado, não deveria ser assim:
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
O objetivo da GROUP_CONCAT está correta, mas a subconsulta é desnecessária e causando o problema. Tente isto em vez disso:
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
Sim, soulmerge a solução é ok.Mas eu precisava de uma consulta onde eu tinha para coletar dados de mais uma criança tabelas, por exemplo:
- tabela principal: sessões (sessões de apresentação) (uid, nome, ..)
- 1º filho tabela: eventos com chave session_id (uid, session_uid, data, time_start, time_end)
- 2ª criança tabela: accessories_needed (laptop, projetor, microfone, etc.) com chave session_id (uid, session_uid, accessory_name)
- 3ª criança tabela: session_presenters (apresentador pessoas) com chave de session_id (uid, session_uid, presenter_name, endereço...)
Cada Sessão tem mais linhas na criança tabelas as tabelas (mais horários, mais acessórios)
E eu precisava recolher em um conjunto para cada sessão para exibição no minério de linha (alguns deles):
session_id | session_name | date | time_start | time_end | accessories | presenters
Minha solução (depois de muitas horas de experimentos):
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
Assim, nenhuma ASSOCIAÇÃO ou GRUPO, se necessário.Outra coisa útil para exibir dados amigável (quando "ecoando" deles):
- você pode moldar os eventos.data, time_start, time_end, etc."<UL><LI> ...</LI></UL>"assim, a "<LI></LI>"usado como separador na consulta irá separar os resultados em itens de lista.
Espero que isso ajude alguém.Saúde!