For this type of data transformation, you will need to use the UNPIVOT
function and then apply the PIVOT
function in SQL Server.
There are two ways to perform this, either hard-coding the values with a static version of using dynamic sql to generate the values as run-time.
Static Version:
The UNPIVOT
piece of this takes the data from your multiple columns and transforms it into two rows. Note, the one thing to keep in mind with unpivot is that the datatypes must be the same. So you might have to perform a data type conversion on the data.:
select [Month], value, col
from
(
select DateName(month,[Month]) +'-'+Cast(datepart(year, [month]) as varchar(4)) Month,
[Affec], [KPI], [Total], [KPI_%], [Out], [rep_in_10], [ftm]
from yourtable
) src
unpivot
(
value
for col in ([Affec], [KPI], [Total], [KPI_%], [Out], [rep_in_10], [ftm])
) unpiv
See SQL Fiddle with Demo
Result:
| MONTH | VALUE | COL |
-------------------------------------
| January-2011 | 30565 | Affec |
| January-2011 | 34623 | KPI |
| January-2011 | 42003 | Total |
| January-2011 | 82.4 | KPI_% |
| January-2011 | 7380 | Out | ---etc
Then you apply the PIVOT
to the months:
select *
from
(
select [Month], value, col
from
(
select DateName(month,[Month]) +'-'+Cast(datepart(year, [month]) as varchar(4)) Month,
[Affec], [KPI], [Total], [KPI_%], [Out], [rep_in_10], [ftm]
from yourtable
) src
unpivot
(
value
for col in ([Affec], [KPI], [Total], [KPI_%], [Out], [rep_in_10], [ftm])
) unpiv
) src
pivot
(
max(value)
for month in ([January-2011], [February-2011], [March-2011],
[April-2011], [January-2012], [February-2012], [March-2012])
) piv
See SQL Fiddle with Demo
Result:
| COL | JANUARY-2011 | FEBRUARY-2011 | MARCH-2011 | APRIL-2011 | JANUARY-2012 | FEBRUARY-2012 | MARCH-2012 |
------------------------------------------------------------------------------------------------------------------
| Affec | 30565 | 27754 | 22838 | 20235 | 20955 | 19513 | 18778 |
| ftm | 5024 | 4189 | 3282 | 2967 | 3518 | 4185 | 4105 |
| KPI | 34623 | 27757 | 23758 | 21950 | 25915 | 25188 | 25098 |
| KPI_% | 82.4 | 76.1 | 79.3 | 84.7 | 93 | 93.4 | 95.9 |
| Out | 7380 | 8726 | 6193 | 3967 | 1942 | 1774 | 1079 |
| rep_in_10 | 7003 | 5648 | 4394 | 3895 | 4754 | 5768 | 5784 |
| Total | 42003 | 36483 | 29951 | 25917 | 27857 | 26962 | 26177 |
Dynamic Version:
The above works great, if you have a known number of values but it your values are unknown then you will want to use dynamic sql. I am going to guess that you will want a dynamic version since you will have a unknown number of dates:
DECLARE @colsUnpivot AS NVARCHAR(MAX),
@cols AS NVARCHAR(MAX),
@query AS NVARCHAR(MAX)
select @colsUnpivot = STUFF((SELECT DISTINCT ','
+ quotename(c.name)
from sys.columns as C
where C.object_id = object_id('yourtable') and
C.name not in ('Month')
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
select @cols = STUFF((SELECT ',' + QUOTENAME(DateName(month,[Month]) +'-'+Cast(datepart(year, [month]) as varchar(4)))
from yourtable
group by [Month]
order by [Month]
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set @query = 'SELECT col,' + @cols + ' from
(
select [Month], value, col
from
(
select DateName(month,[Month]) +''-''+Cast(datepart(year, [month]) as varchar(4)) Month,
[Affec], [KPI], [Total], [KPI_%], [Out], [rep_in_10], [ftm]
from yourtable
) src
unpivot
(
value
for col in ('+@colsunpivot+')
) unpiv
) x
pivot
(
max(value)
for [Month] in (' + @cols + ')
) p '
execute(@query)
See SQL Fiddle with Demo
The result will be the same as the dynamic version.
UNION ALL/CASE with aggregate:
Lastly, if you do not have access to either the UNPIVOT
or PIVOT
functions, then you can use a UNION ALL
to unpivot and an aggregate function with a CASE
to pivot the data:
select col,
max(case when month='January-2011' then value end) [January-2011],
max(case when month='February-2011' then value end) [February-2011],
max(case when month='March-2011' then value end) [March-2011],
max(case when month='April-2011' then value end) [April-2011],
max(case when month='January-2012' then value end) [January-2012],
max(case when month='February-2012' then value end) [February-2012],
max(case when month='March-2012' then value end) [March-2012]
from
(
select DateName(month,[Month]) +'-'+Cast(datepart(year, [month]) as varchar(4)) Month,
[Affec] value,
'Affec' col
from yourtable
union all
select DateName(month,[Month]) +'-'+Cast(datepart(year, [month]) as varchar(4)) Month,
[KPI] value,
'KPI' col
from yourtable
union all
select DateName(month,[Month]) +'-'+Cast(datepart(year, [month]) as varchar(4)) Month,
[Total] value,
'Total' col
from yourtable
union all
select DateName(month,[Month]) +'-'+Cast(datepart(year, [month]) as varchar(4)) Month,
[KPI_%] value,
'KPI_%' col
from yourtable
union all
select DateName(month,[Month]) +'-'+Cast(datepart(year, [month]) as varchar(4)) Month,
[rep_in_10] value,
'rep_in_10' col
from yourtable
union all
select DateName(month,[Month]) +'-'+Cast(datepart(year, [month]) as varchar(4)) Month,
[ftm] value,
'ftm' col
from yourtable
) src
group by col
See SQL Fiddle with Demo