What you are trying to do is a full data transpose where your current columns of data become rows and your rows become columns, this can be accomplished in two steps. First, applying the UNPIVOT function to convert your current columns of Conv1
, Conv2
, etc into rows, then you apply the PIVOT function to convert the data1
, data2
into columns.
Prior to trying to write a dynamic version of the query, I would always start with a static version so can get the correct logic, then convert to dynamic sql. In order to generate your new column names Col1
, Col2
, etc I would use a windowing function like row_number()
when querying your data, this will generate a unique sequence for each row of data that you want to transpose.
The UNPIVOT code will be similar to:
;with cte as
(
select Conv1, Conv2, Conv3,
row_number() over(order by conv1) seq
from dbo.yourtable
)
select *
from
(
select Conv, value,
col = 'Col'+cast(seq as varchar(50))
from cte
unpivot
(
value for Conv in (Conv1, Conv2, Conv3)
) unpiv
) src;
See SQL Fiddle with Demo. The data will look like:
| CONV | VALUE | COL |
|-------|-------|------|
| Conv1 | data1 | Col1 |
| Conv2 | data2 | Col1 |
| Conv3 | data3 | Col1 |
| Conv1 | data1 | Col2 |
| Conv2 | data2 | Col2 |
| Conv3 | data3 | Col2 |
You'll notice that you now have multiple rows for each Conv1
and you have a new column with that uses the row_number()
to create your new column names. Now you can use PIVOT to finish the rotation of the data:
;with cte as
(
select Conv1, Conv2, Conv3,
row_number() over(order by conv1) seq
from dbo.yourtable
)
select Conv, Col1, Col2, Col3
from
(
select Conv, value,
col = 'Col'+cast(seq as varchar(50))
from cte
unpivot
(
value for Conv in (Conv1, Conv2, Conv3)
) unpiv
) src
pivot
(
max(value)
for col in (Col1, Col2, Col3)
) piv;
See SQL Fiddle with Demo. This will fully transpose your current data to your final result. For your case you stated you need a dynamic solution so you will need to use dynamic SQL. This will involve getting a list of the column names that need to be unpivoted and then the new columns for the pivot:
DECLARE @colsUnpivot AS NVARCHAR(MAX),
@colsPivot AS NVARCHAR(MAX),
@query AS NVARCHAR(MAX)
select @colsUnpivot = STUFF((SELECT ','+ quotename(c.name)
from sys.tables t
inner join sys.columns c
on t.object_id = c.object_id
where t.name = 'yourtable'
group by c.name, c.column_id
order by c.column_id
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
select @colsPivot = STUFF((SELECT ','+ quotename('Col'+cast(seq as varchar(10)))
from
(
select row_number() over(order by conv1) seq
from dbo.yourtable
) d
group by seq
order by seq
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set @query
= ';with cte as
(
select Conv1, Conv2, Conv3,
row_number() over(order by conv1) seq
from dbo.yourtable
)
select Conv, '+@colsPivot+'
from
(
select Conv, value,
col = ''Col''+cast(seq as varchar(50))
from cte
unpivot
(
value for Conv in ('+@colsUnpivot+')
) unpiv
) src
pivot
(
max(value)
for col in ('+@colsPivot+')
) piv'
execute sp_executesql @query;
See SQL Fiddle with Demo. Both give a final result of:
| CONV | COL1 | COL2 | COL3 |
|-------|-------|-------|-------|
| Conv1 | data1 | data1 | data1 |
| Conv2 | data2 | data2 | data2 |
| Conv3 | data3 | data3 | data3 |