Función GROUP_CONCAT de MySQL

In: mysql

19 oct 2009

MySQL logoDescubrí el otro día la función GROUP_CONCAT, que puede ser muy útil cuando hacemos consultas a MySQL donde usamos el GROUP BY. Sirve para concatenar con un separador, todos los registros afectados por un GROUP BY en un solo campo de salida. Lo mejor es explicarlo con un ejemplo.

Tenemos dos tablas, Contenidos y Categorías (o cualquier relación típica de 1:N o N:N). El objetivo es sacar todos los contenidos, y en cada registro de contenidos, las categorías de cada uno de ellos.

Si hiciéramos una consulta en que relacionamos las tablas, hicieramos el GROUP BY, y pidieramos los campos nombre_contenido y nombre_categoria, solamente retornaría el nombre de una categoría, la primera que encuentre:

SELECT nombre_contenido, nombre_categoria
FROM contenidos
	INNER JOIN categorias_contenidos USING (id_contenido)
	INNER JOIN categorias USING (id_categoria)
GROUP BY id_contenido

Pero con la función GROUP_CONCAT, todas las Categorías que se ven agrupadas por el GROUP BY, serán concatenadas en un campo, con una coma como separador.

SELECT nombre_contenido, GROUP_CONCAT(nombre_categoria)
FROM contenidos
	INNER JOIN categorias_contenidos USING (id_contenido)
	INNER JOIN categorias USING (id_categoria)
GROUP BY id_contenido

La función GROUP_CONCAT solo tiene un parámetro, que es una expresión. Básicamente puede ser el nombre de la columna a concatenar. Pero permite tres personalizaciones, según nuestras necesidades:

  • Utilizar DISTINCT, para evitar las repeticiones
  • Añadir un ORDER BY, para decidir el orden de concatenación del campo
  • Definir con SEPARATOR el separador a utilizar para separar los campos (por defecto, el separador es una coma)

Pongo un ejemplo completo con todas las funcionalidades de GROUP_CONCAT, así no tendremos repeticiones de las categorías, estarán ordenadas alfabéticamente y separadas por un guión:

SELECT nombre_contenido, GROUP_CONCAT(DISTINCT nombre_categoria
					ORDER BY nombre_categoria ASC
					SEPARATOR '-')
FROM contenidos
	INNER JOIN categorias_contenidos USING (id_contenido)
	INNER JOIN categorias USING (id_categoria)
GROUP BY id_contenido

Una vez recibido el registro, podemos convertir este campo concatenado en un array, simplemente utilizando la función explode de .

Actualización: A través del comentario de Daniel, me entero que la función tiene un límite de 1024 caracteres, incluidos los separadores. En un ejemplo que he visto, he leído que en una consulta en que la función GROUP_CONCAT tenía que devolver del 1 al 20.000 separados por comas, solo devolvía hasta el 283; los números cuadran de la siguiente manera:

  • Del 1 al 9, van 9 caracteres
  • Del 10 al 99, van 90*2= 180 caracteres
  • Del 100 al 283, van 184*3= 552 caracteres
  • Más las 283 comas, que son 283 carácteres más
  • TOTAL = 9 + 180 + 552 + 283 = 1024 caracteres.

Pero esto no es un inconveniente para utilizar la función GROUP_CONCAT. Este límite se puede modificar a nuestro gusto, de las dos maneras siguientes:

  1. Editando el archivo de configuración my.cnf y modificando la variable:
    group_concat_max_len=4096
  2. Ejecutando esta orden antes de realizar la consulta:
    SET GLOBAL group_concat_max_len=4096

Fuentes – Syntax ErrorMySQL Performance Blog (mirar también los comentarios)

Entradas relacionadas:

  1. La selectividad de los índices en MySQL
  2. Trabajando con el tipo de campo BIT de MySQL en PHP
  3. Diferencias entre ENUM y SET en MySQL
  4. Diferencias entre mysql, mysqli y PDO en PHP
  5. STRAIGHT_JOIN y el order de las tablas en JOINs de MySQL

1 Comentario en Función GROUP_CONCAT de MySQL

Daniel

19 octubre 2009 a las 14:46

Es una gran función.

Para tener en cuenta: Tiene un límite de 1024 caracteres. Si el resultado es mayor mysql lo trunca. De todas formas, el valor puede ser modificado desde la configuración cambiando la variable group_concat_max_len

Saludos

Formulario de Comentario

Página 1 de 0

Sobre este blog

Este blog informático pretende ser un blog de notas o portafolio de información variada: trozos de código, descubrimientos, notas sueltas, ... Para tenerla a mano, y ser compartida.