MySQL: Usando el GROUP_CONCAT()
20 de Noviembre de 2006 en SQL
Lecturas: 6,367

En éste artículo intento explicar el objetivo de esta instrucción no demasiado conocida el group_concat(). La verdad es que en mi trabajo cotidiano me ha salvado el pellejo. Podéis encontrar una descripción exacta en la documentación de MySQL (Funciones del Group By).

Imaginemos que tenemos una tabla típica de teléfonos de clientes, con unos campos típicos (id_cliente, teléfono, país, ...). Ésta tabla tiene la particularidad: si un cliente tiene más de un teléfono, tendrá un registro por cada teléfono, con la información extra que la tabla marque (el país, móvil o fijo... vaya, lo que se nos ocurra). Para un cliente dado, podríamos tener los siguientes registros:

id_cliente telefono pais fijo
123 696001122 ES 0
123 932345678 ES 1
123 998745621 FR 1
123 696001122 FR 0

Como vemos, tenemos que el mismo cliente tiene teléfonos en dos países diferentes, y en cada país tiene dos números, uno fijo y otro móvil. Imaginemos que ésto se da varias veces con varios clientes. Un día alguien busca la ficha del cliente 123 por el flamante buscador de clientes que busca por número de teléfonos y esperando sacar el movil francés le sale el movil español... mmm... qué buscador más malo... sólo te muestra la primera coincidencia... pero para el caso ya sirve.

Pero el que lo ha buscado es un accionista general, que se cabrea como una mona y manda al informático de turno saber qué pasa. El informático le explica que el buscador que compró a una empresa externa era una caca, y que además hay números de teléfono iguales en diferentes países. El jefe lo más probable es que diga "Y cuantos clientes tenemos en ésta situación?"... Y aquí entra nuestra nueva función.

Nosotros somos muy chulos y decimos "Bah, ésto con un count(*) y un group by lo tenemos solucionado":

SQL:
  1. SELECT id_cliente, count(*) FROM telefonos GROUP BY id_cliente

id_cliente count(*)
123 4

Pero ésto te da el número de teléfonos que tiene cada cliente... necesitamos saber los clientes que tienen teléfonos iguales en diferentes paises. Podemos probar otra:

SQL:
  1. SELECT id_cliente, pais, count(telefono) FROM telefonos GROUP BY id_cliente, pais

id_cliente pais count(telefono)
123 ES 2
123 FR 2

Ésto nos dará un resultado por cada país en el que el cliente tenga un teléfono, pero lo que queremos es que esté todo en un mismo registro, para luego poderlos contar... mmm... la cosa se complica más... porque además sólo queremos los que tengan teléfonos iguales en diferentes países.

Probaremos otra, ahora usando un having para indicar que sólo queremos los teléfonos que se repitan dos veces o más:

SQL:
  1. SELECT id_cliente, pais, telefono, count(telefono) FROM telefonos GROUP BY id_cliente, telefono HAVING count(telefono)>=2

id_cliente pais telefono count(telefono)
123 ES 696001122 2

Ésta ya se acerca más, pero curiosamente nos hace algo parecido a lo que ha hecho saltar las alarmas: sólo nos muestra el contenido del primer campo pais encontrado, el ES. Ahora sólo nos queda montarnos alguna forma para que muestre una concatenación de todos los paises en los que hay teléfonos coincidentes... ¿cómo lo hacemos? ¿usamos una join reflexiva para tener todos los registros a mano? uff...

No, usaremos el group_concat(), que concatena todos los registros afectados por los group by en un solo campo de salida:

SQL:
  1. SELECT id_cliente, group_concat(pais), telefono, count(telefono) FROM telefonos GROUP BY id_cliente, telefono HAVING count(telefono)>=2

id_cliente group_concat(pais) telefono count(telefono)
123 ES,FR 696001122 2

Mágicamente tenemos todos los países afectados por el problema dentro del mismo registro! Ahora ya podemos ir al jefe de turno a darle el resultado.


 Enviar a Fresqui

Leer los Comentarios

[ # 968 ] Comment desde Luis Cabre … [10 de Mayo de 2007, 05:14]

Tengo un problema ,,,, tengo la siguiente sentencia SQL

$sql_lista=”SELECT userid,email,articulo,codigogenerado FROM a2a002_aplicacion.tab_master WHERE userid = ‘$var_idx’ and email = ‘$var_ex’ GROUP BY codigogenerado “;

El trabaja perfecto haciendome la agrupacion por el campo — codigogenerado … pero quiero omitir los codigogenerados que no tengan datos .. osea que solo me agrupe los que tienen datos y omitan los que no tienen datos todavia … probe de esta forma pero no me funciono:

$sql_lista=”SELECT userid,email,articulo,codigogenerado FROM a2a002_aplicacion.tab_master WHERE userid = ‘$var_idx’ and email = ‘$var_ex’ GROUP BY codigogenerado HAVING articulo ‘’ “;

Por favor quisiera ver como puedo solventar esto?
Gracias

[ # 970 ] Comment desde Xavi [10 de Mayo de 2007, 07:10]

Buenas Luis.

No acabo de entender el GROUP BY si no hay ninguna operación sobre campos del SELECT… Lo vería claro con algo como

SELECT count(userid), codigogenerado
FROM tab_master
GROUP BY codigogenerado

Aunque tengas códigos repetidos que puedas agrupar los demás campos son muy “aleatorios”, así que no te serviría de mucho. De todos modos el Access (lo siento, es lo que tengo ahora a mano ;) ) no lo acepta.

Pero sobre tu pregunta, para omitir los codigogenerados de la query has de meter un AND articulo <> ‘’ AND articulo IS NOT NULL en el WHERE, no como HAVING.

El HAVING es para cosas como (en el ejemplo anterior):

SELECT count(userid) as cuantos, codigogenerado
FROM tab_master
GROUP BY codigogenerado
HAVING cuantos >2

Pásate por http://www.w3schools.com/sql/sql_quickref.asp :)

Ya sabes dónde estoy ;)

[ # 17748 ] Comment desde Vanessa [19 de Febrero de 2008, 06:10]

Necesito una cláusula para que en una consulta sobre una tabla que tiene dos campos. Se muestren sólo los datos de uno de ellos si sus datos son iguales a los de otro campo de la tabla. Localidad y Ayuntamiento son iguales, si es así , que sólo se muestre Localidad por ejemplo.

[ # 18298 ] Comment desde Gabriel [06 de Marzo de 2008, 03:04]

Hola. Tengo un problema al encontrar los datos repetidos en mi base de datos.
El problema es el siguiente: Necesito armar una consulta para encontrar Codigos de clientes que esten repetidos en la tabla Cliente. Pero que, ademas, de mostrarme el codigo que esta repetido, me muestre el idcliente de cada uno de los codigos.
Como puedo hacer esto???
Alguien sabe???
Agracerecia mucho su ayuda…..

[ # 18299 ] Comment desde Xavi [06 de Marzo de 2008, 03:12]

Pues… diría que el group_concat te puede ayudar… haciendo un group_concat(id_cliente) con un group by codigo_cliente…
Pruébalo y nos dices.

[ # 18300 ] Comment desde Gabriel [06 de Marzo de 2008, 03:43]

Estoy probando el group_contac… pero me dice que no es una funcion valida….
Este codigo sirve para SQL2000?????????????

[ # 18301 ] Comment desde Xavi [06 de Marzo de 2008, 03:47]

Desgraciadamente, SQL Server no soporta esta función. He encontrado una forma de simularlo aquí:
http://www.xaprb.com/blog/2005/09/28/simulating-the-group-concat-function/

Saludos.

[ # 18307 ] Comment desde Gabriel [06 de Marzo de 2008, 06:07]

Perdon… pero no entiendo la forma de applicarlo a SQL2000. Alguien sabra otra forma de lograr encontrar un codigo repetido en la tabla, pero que ademas, traiga mas datos de esa misma fila???? O sea, el resto de los datos de la fila aunque no se repitan en ningun lado…
Gracias

Escribe un Comentario





Estadísticas