12 may 2013

Concatenar varios registros en una sola columna

Supongamos que, en SQL Server, tenemos una tabla de proveedores y una tabla aparte donde se almacenan los números de teléfonos de dichos proveedores como registros separados. De modo que tendríamos algo similar a lo siguiente:

Proveedor:
codProveedor desRazonSocial ...
1 Proveedor de Prueba 1 ...
2 Proveedor de Prueba 2 ..

ProveedorTelefono:
codProveedor desTelefono
1 88881685
1 89000000
1 98012012
2 78912000
2 12345678

Supongamos que una de las necesidades de nuestro cliente es que mostremos, en un grid o tabla, cada proveedor con todos sus teléfonos en una sola columna separados por comas.

Como para con casi todo en la vida, hay varias formas de hacerlo; podríamos traernos todo en dos consultas separadas (o en una sola por medio de joins, con la información de los proveedores repetida) y ya en nuestra aplicación, por medio de un bucle, concatenar los teléfonos en un solo campo, o usar un store procedure con un cursor y hacer mas o menos lo mismo que en el punto anterior pero en el motor de base de datos o tantas otras aproximaciones.

También se puede utilizar la combinación de una función y una consulta de la siguiente manera:

Primero creamos una función para devolver los teléfonos concatenados por proveedor:
CREATE FUNCTION [dbo].[fnTelefonosProveedor] (@codProveedor int)
RETURNS varchar(600)
AS
BEGIN 
 DECLARE @listaTelefonos varchar(600)
 SET @listaTelefonos = null
 
 SELECT  @listaTelefonos = COALESCE(@listaTelefonos, '') +
 	CASE
   		WHEN @listaTelefonos IS NULL THEN ''
  	ELSE
   		', '
  	END
  + T.desTelefono
 FROM ProveedorTelefono T
 WHERE T.codProveedor = @codProveedor

 RETURN @listaTelefonos 
END
Esta función que recibe por parámetro el código del proveedor y retorna los teléfonos concatenados en campo varchar de hasta 600 caracteres. La combinación de la sentencia SELECT con el COALESCCE [si el primer parámetro es nulo devuelve el segundo parámetro] hace la magia de concatenar los teléfonos en una sola variable (@listaTelefonos) separados por coma.

Finalmente utilizamos nuestra función dentro de nuestra consulta:
SELECT P.conCodigoProveedor, P.nomRazonSocial, 
	dbo.fnTelefonosProveedor(P.codProveedor) AS desTelefonos  
FROM Proveedor P
Obteniendo algo similar a

codProveedor desRazonSocial desTelefonos
1 Proveedor de Prueba 1 88881685, 89000000, 98012012
2 Proveedor de Prueba 2 78912000, 12345678

Y ya con esto concatenamos varios registros en una sola columna...y es fácil de traducir a otros motores de base de datos.

Roy {aka. Foy}

Autor & Editor

Desarrallador y líder técnico, con experiencia en tecnologías Microsoft desde los tiempos del VB6 y el asp clásico hasta el .Net Core, pasando por COM+, javascript, angularjs, Ionic, xaml, cordova, MVC, Web Api, Sql Server, Oracle... . Ávido lector, apasionado programador.