Concatenar datos de una columna en una fila

- 3 minutos de lectura

Me he topado en varias ocasiones con la necesidad de crear una vista en la que un campo contiene concatenados el valor de varios registros de otra tabla. Casi siempre he acabado recurriendo a Google para recordar c贸mo hacerlo, porque, por alguna raz贸n que desconozco, esta informaci贸n no queda registrada en mi hipocampo.

En este art铆culo vamos a ver c贸mo conseguirlo con un ejemplo muy sencillo. Partimos de 3 tablas: autor, libro y libro_autor, que contienen, como podemos suponer, una relaci贸n de autores, libros y libro-autor. La estructura de estas tres tablas es la que se muestra en el siguiente diagrama.

Ahora supongamos que queremos mostrar el listado de todos los libros y que en una columna queremos que aparezcan concatenados el nombre de todos los autores del libro. El resultado que queremos obtener es el siguiente:

id_libro titulo autores
1 libro1 autor1, autor2
2 libro2 autor2, autor1
3 libro3 autor3

La forma m谩s sencilla de obtener este resultado es creando una funci贸n que devuelva el nombre de todos los autores, pasando como par谩metro el identificador del libro. Esto lo podemos hacer f谩cilmente haciendo uso de las funciones ISNULL o COALESCE. En este ejemplo, lo conseguimos mediante la funci贸n COALESCE.

CREATE FUNCTION dbo.DevuelveActores ( @id\_libro int )
RETURNS VARCHAR(40)
AS
BEGIN
   DECLARE @autores VARCHAR(40)

   SELECT @autores = COALESCE(@autores + ', ' + nombre, nombre)
   FROM libro\_autor la
   LEFT JOIN autor a ON la.id\_autor = a.id\_autor
   WHERE id\_libro=@id\_libro

   RETURN @autores
END

Ahora podemos, mediante la siguiente consulta, obtener el resultado deseado:

SELECT id_libro, titulo, autores = dbo.DevuelveActores(id_libro)
FROM libro

Otra opci贸n es hacer uso del modo PATH de la cl谩usula FOR XML. Este modo permite definir, mediante los nombres o alias de la columnas, la manera c贸mo se asignan los valores en el XML, as铆 como el nombre del elemento, pudiendo sobrescribir el valor __ predeterminado. Por ejemplo, la siguiente consulta devuelve una cadena con todos los autores concatenados.

SELECT nombre as \[data()\] FROM autor FOR XML PATH ('')

Haciendo uso de esta caracter铆stica, es posible montar una consulta con una subconsulta que devuelva todos los autores de un libro y reemplazar el espacio entre autores por el separador que queramos. Con la siguiente consulta obtenemos exactamente el mismo resultado que hemos conseguido antes con la funci贸n.

SELECT id_libro, titulo, autores = CAST( REPLACE( (
   SELECT nombre as [data()]
   FROM libro_autor la
   LEFT JOIN autor a ON la.id_autor = a.id_autor
   WHERE id_libro = l.id_libro
   FOR XML PATH ('')
   ), ' ', ', ') AS NVARCHAR(40) )
FROM libro l

Dejo un enlace para descargar el script que contiene las consultas de los dos m茅todos explicados y la creaci贸n de todos los elementos de base de datos (tablas y funciones) que he utilizado en este ejemplo.