No MySQL, você pode retornar os resultados de sua consulta como uma lista separada por vírgulas usando o
GROUP_CONCAT()
função. O
GROUP_CONCAT()
A função foi criada especificamente para concatenar o conjunto de resultados de uma consulta em uma lista separada por uma vírgula ou um delimitador de sua escolha. Este artigo fornece exemplos de como tudo funciona.
Os dados
Primeiro, vamos usar os seguintes dados em nossos primeiros exemplos:
USE Solutions; SELECT TaskName FROM Tasks;
Resultado:
+-------------------+ | TaskName | +-------------------+ | Do garden | | Feed cats | | Paint roof | | Take dog for walk | | Relax | | Feed cats | +-------------------+
Exemplo básico
Aqui está um exemplo básico para demonstrar o
GROUP_CONCAT()
função:SELECT GROUP_CONCAT(TaskName) FROM Tasks;
Resultado:
+------------------------------------------------------------------+ | GROUP_CONCAT(TaskName) | +------------------------------------------------------------------+ | Do garden,Feed cats,Paint roof,Take dog for walk,Relax,Feed cats | +------------------------------------------------------------------+
Como você pode ver, cada linha do conjunto de resultados foi concatenada em uma única linha. Por padrão, a lista é separada por uma vírgula.
Observe que há restrições quanto ao tamanho dessa lista. Mais sobre isso mais adiante no artigo.
Exemplo – DISTINTO
Você pode usar
DISTINCT
para remover duplicatas (para que registros duplicados se tornem um registro). Exemplo:
SELECT GROUP_CONCAT(DISTINCT TaskName) FROM Tasks;
Resultado:
+--------------------------------------------------------+ | GROUP_CONCAT(DISTINCT TaskName) | +--------------------------------------------------------+ | Do garden,Feed cats,Paint roof,Relax,Take dog for walk | +--------------------------------------------------------+
Portanto, neste caso, “Feed cats” é listado apenas uma vez, enquanto foi listado duas vezes no exemplo anterior.
Exemplo - ORDENAR POR
Você pode usar
ORDER BY
para ordenar os resultados por uma determinada coluna. Exemplo:
SELECT GROUP_CONCAT(DISTINCT TaskName ORDER BY TaskName DESC) FROM Tasks;
Resultado:
+--------------------------------------------------------+ | GROUP_CONCAT(DISTINCT TaskName ORDER BY TaskName DESC) | +--------------------------------------------------------+ | Take dog for walk,Relax,Paint roof,Feed cats,Do garden | +--------------------------------------------------------+
Então neste caso eu uso
DESC
para especificar que deve estar em ordem decrescente. O valor alternativo (e padrão) é ASC
para ascendente. Exemplo – Especificar um delimitador
Por padrão, a lista é uma lista separada por vírgulas. No entanto, você pode especificar um delimitador de sua escolha, se necessário.
Para fazer isso, use
SEPARATOR
seguido pelo valor literal da string que deve ser inserido entre os valores do grupo. Exemplo:
SELECT GROUP_CONCAT(DISTINCT TaskName SEPARATOR ' + ') FROM Tasks;
Resultado:
+----------------------------------------------------------------+ | GROUP_CONCAT(DISTINCT TaskName SEPARATOR ' + ') | +----------------------------------------------------------------+ | Do garden + Feed cats + Paint roof + Relax + Take dog for walk | +----------------------------------------------------------------+
Exemplo – Combinando Colunas
Você também pode concatenar colunas e fornecer seu próprio separador fornecendo um valor literal de string.
Exemplo:
SELECT GROUP_CONCAT(TaskId, ') ', TaskName SEPARATOR ' ') FROM Tasks;
Resultado:
+------------------------------------------------------------------------------------+ | GROUP_CONCAT(TaskId, ') ', TaskName SEPARATOR ' ') | +------------------------------------------------------------------------------------+ | 1) Do garden 2) Feed cats 3) Paint roof 4) Take dog for walk 5) Relax 6) Feed cats | +------------------------------------------------------------------------------------+
Neste exemplo, retornamos o
TaskId
coluna e o TaskName
coluna, separados por um parênteses de fechamento e um espaço. Também usamos o SEPARATOR
argumento para especificar que o delimitador a ser usado entre cada linha (concatenada) deve ser um espaço (em vez da vírgula padrão). Resultados agrupados
O
GROUP_CONCAT()
A função pode ser útil para ocasiões em que você deseja fornecer uma lista de resultados, agrupados por outra coluna. Por exemplo, você pode querer uma lista de artistas, com cada artista seguido por uma lista de álbuns que eles lançaram.
Para demonstrar isso, digamos que temos um banco de dados com duas tabelas;
Artists
e Albums
. Há uma relação de um para muitos entre essas tabelas. Para cada artista, pode haver muitos álbuns. Portanto, uma consulta regular juntando as duas tabelas pode ser algo assim:
USE Music; SELECT ar.ArtistName, al.AlbumName FROM Artists ar INNER JOIN Albums al ON ar.ArtistId = al.ArtistId;
Resultado:
+------------------------+--------------------------+ | ArtistName | AlbumName | +------------------------+--------------------------+ | Iron Maiden | Powerslave | | AC/DC | Powerage | | Jim Reeves | Singing Down the Lane | | Devin Townsend | Ziltoid the Omniscient | | Devin Townsend | Casualties of Cool | | Devin Townsend | Epicloud | | Iron Maiden | Somewhere in Time | | Iron Maiden | Piece of Mind | | Iron Maiden | Killers | | Iron Maiden | No Prayer for the Dying | | The Script | No Sound Without Silence | | Buddy Rich | Big Swing Face | | Michael Learns to Rock | Blue Night | | Michael Learns to Rock | Eternity | | Michael Learns to Rock | Scandinavia | | Tom Jones | Long Lost Suitcase | | Tom Jones | Praise and Blame | | Tom Jones | Along Came Jones | | Allan Holdsworth | All Night Wrong | | Allan Holdsworth | The Sixteen Men of Tain | +------------------------+--------------------------+
Como você pode ver, ao usar esse formato, se um artista tiver mais de um álbum, esse artista será listado várias vezes – uma vez para cada álbum.
Poderíamos modificar essa consulta para que cada artista seja listado apenas uma vez. Se um artista tiver mais de um álbum, todos os álbuns serão exibidos em um único campo em uma lista separada por vírgulas. Podemos fazer isso graças ao
GROUP_CONCAT()
função. Exemplo:
USE Music; SELECT ar.ArtistName, GROUP_CONCAT(al.AlbumName) FROM Artists ar INNER JOIN Albums al ON ar.ArtistId = al.ArtistId GROUP BY ArtistName;
Resultado:
+------------------------+----------------------------------------------------------------------------+ | ArtistName | GROUP_CONCAT(al.AlbumName) | +------------------------+----------------------------------------------------------------------------+ | AC/DC | Powerage | | Allan Holdsworth | All Night Wrong,The Sixteen Men of Tain | | Buddy Rich | Big Swing Face | | Devin Townsend | Epicloud,Ziltoid the Omniscient,Casualties of Cool | | Iron Maiden | Somewhere in Time,Piece of Mind,Powerslave,Killers,No Prayer for the Dying | | Jim Reeves | Singing Down the Lane | | Michael Learns to Rock | Eternity,Scandinavia,Blue Night | | The Script | No Sound Without Silence | | Tom Jones | Long Lost Suitcase,Praise and Blame,Along Came Jones | +------------------------+----------------------------------------------------------------------------+
Cuidado com o comprimento!
Uma coisa importante que você precisa estar ciente ao usar
GROUP_CONCAT()
é que o resultado é truncado para o comprimento máximo fornecido pelo group_concat_max_len
variável do sistema, que tem um valor padrão de 1024
. O valor dessa variável pode ser definido mais alto usando a seguinte sintaxe:
SET [GLOBAL | SESSION] group_concat_max_len = val;
Onde
val
é um número inteiro não assinado. No entanto, observe que o comprimento máximo efetivo do valor de retorno é limitado pelo valor de
max_allowed_packet
.