GROUP_CONCAT – Agrupando dados no MySQL

On 8 de outubro de 2014, in SQL, by andersonstraube

Se você precisa exibir um relacionamento 1 para muitos, a primeira coisa que vem em mente é JOIN das tabelas, todavia você já se deparou com uma questão da quantidade de dados “desnecessário” que isso causa?

Exemplo/Cenário:

Temos as tabelas pessoas e livros (1 para n):


der

Se eu quero uma relação dos livros que a pessoa possui, normalmente é feito isso:


SELECT 
    pessoas.nome AS nome, livros.nome AS livro, paginas
FROM 
    livros
INNER JOIN
    pessoas ON ( pessoas.id = livros.id_pessoa )
ORDER BY
    pessoas.nome ASC
</code>

Não está errado, todavia rodando o SQL observamos que o nome da pessoa repete-se para cada livro encontrado. Imagine isso em um sistema grande onde muitos clientes possuem milhares de livros. Isso é totalmente desnecessário.

Como nosso objetivo é apenas saber os livros que o usuário possui então vamos agrupar esses dados por pessoa, ou seja, trazemos o nome da pessoa (apenas uma vez) e outra coluna com os livros que ela possui.

SQL:


SELECT 
    pessoas.nome AS nome, 
    GROUP_CONCAT(livros.nome, ' - ', livros.paginas, ' páginas ' SEPARATOR '<br>') AS livros
FROM 
    livros
INNER JOIN
    pessoas ON ( pessoas.id = livros.id_pessoa )
GROUP BY
    pessoas.id
ORDER BY
    pessoas.nome ASC  

Há situações em que não podemos usar a cláusula GROUP BY no WHERE ou então precisamos agrupar outras tabelas, por exemplo: retornar os livros da pessoa juntamente com os DVD’s que ela possui.

Para tais situações podemos usar o SQL abaixo:


SELECT 
    pessoas.nome AS nome, 
    ( SELECT GROUP_CONCAT(nome, ' - ', paginas, ' páginas ' SEPARATOR '<br>') FROM livros WHERE livros.id_pessoa = pessoas.id ) AS livros,
    ( SELECT GROUP_CONCAT(nome, ' - ', minutos, ' minutos ' SEPARATOR '<br>') FROM dvds WHERE dvds.id_pessoa = pessoas.id ) AS dvds
FROM 
    pessoas
ORDER BY
    pessoas.nome ASC   

#ficaDica

Tagged with:  

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *