Transponer filas y columnas sin agregado

Tengo el siguiente conjunto de datos

Account Contact 1 324324324 1 674323234 2 833343432 2 433243443 3 787655455 4 754327545 4 455435435 5 543544355 5 432455553 5 432433242 5 432432432 

Me gustaría la salida de la siguiente manera:

 Account Contact1 Contact2 Contact3 Contact4 1 324324324 674323234 2 833343432 433243443 3 787655455 4 754327545 455435435 5 543544355 432455553 432433242 432432432 

El problema también es que tengo una cantidad no fija de cuentas y una cantidad no fija de contactos

Si va a aplicar la función PIVOT , necesitará usar una función de agregado para obtener el resultado, pero también querrá usar una función de ventana como row_number() para generar una secuencia única para cada contacto en la cuenta.

Primero, consultará sus datos de manera similar a:

 select account, contact, 'contact' + cast(row_number() over(partition by account order by contact) as varchar(10)) seq from yourtable 

Ver SQL Fiddle con demostración . Esto creará una nueva columna con la secuencia única:

 | ACCOUNT | CONTACT | SEQ | |---------|-----------|----------| | 1 | 324324324 | contact1 | | 1 | 674323234 | contact2 | 

Si tiene un número limitado de columnas, puede codificar su consulta:

 select account, contact1, contact2, contact3, contact4 from ( select account, contact, 'contact' + cast(row_number() over(partition by account order by contact) as varchar(10)) seq from yourtable ) d pivot ( max(contact) for seq in (contact1, contact2, contact3, contact4) ) piv; 

Ver SQL Fiddle con demostración

Si tiene un número desconocido de columnas, tendrá que usar SQL dynamic:

 DECLARE @cols AS NVARCHAR(MAX), @query AS NVARCHAR(MAX) select @cols = STUFF((SELECT ',' + QUOTENAME(seq) from ( select 'contact' + cast(row_number() over(partition by account order by contact) as varchar(10)) seq from yourtable ) d group by seq order by seq FOR XML PATH(''), TYPE ).value('.', 'NVARCHAR(MAX)') ,1,1,'') set @query = 'SELECT account, ' + @cols + ' from ( select account, contact, ''contact'' + cast(row_number() over(partition by account order by contact) as varchar(10)) seq from yourtable ) x pivot ( max(contact) for seq in (' + @cols + ') ) p ' execute sp_executesql @query; 

Ver SQL Fiddle con demostración . Ambos le darán un resultado de:

 | ACCOUNT | CONTACT1 | CONTACT2 | CONTACT3 | CONTACT4 | |---------|-----------|-----------|-----------|-----------| | 1 | 324324324 | 674323234 | (null) | (null) | | 2 | 433243443 | 833343432 | (null) | (null) | | 3 | 787655455 | (null) | (null) | (null) | | 4 | 455435435 | 754327545 | (null) | (null) | | 5 | 432432432 | 432433242 | 432455553 | 543544355 | 

Solo una manera ligeramente diferente de generar el PIVOT dynamic:

 DECLARE @c INT; SELECT TOP 1 @c = COUNT(*) FROM dbo.YourTable GROUP BY Account ORDER BY COUNT(*) DESC; DECLARE @dc1 NVARCHAR(MAX) = N'', @dc2 NVARCHAR(MAX) = N'', @sql NVARCHAR(MAX); SELECT @dc1 += ',Contact' + RTRIM(i), @dc2 += ',[Contact' + RTRIM(i) + ']' FROM (SELECT TOP (@c) i = number + 1 FROM master.dbo.spt_values WHERE type = N'P' ORDER BY number) AS x; SET @sql = N'SELECT Account ' + @dc1 + ' FROM (SELECT Account, Contact, rn = ''Contact'' + RTRIM(ROW_NUMBER() OVER (PARTITION BY Account ORDER BY Contact)) FROM dbo.YourTable) AS src PIVOT (MAX(Contact) FOR rn IN (' + STUFF(@dc2, 1, 1, '') + ')) AS p;'; EXEC sp_executesql @sql; 

Demostración SQLiddle