Reputation: 315
Is there a T-SQL (SQL Server 2008R2) query to transform TABLE_1
into the expected resultset?
TABLE_1
+----------+-------------------------+---------+------+
| IdDevice | Timestamp | M300 | M400 |
+----------+-------------------------+---------+------+
| 3 | 2012-12-05 16:29:51.000 | 2357,69 | 520 |
| 6 | 2012-12-05 16:29:51.000 | 1694,81 | 470 |
| 1 | 2012-12-05 16:29:51.000 | 2046,33 | 111 |
+----------+-------------------------+---------+------+
Expected resultset
+-------------------------+---------+--------+---------+--------+---------+--------+
| Timestamp | 3_M300 | 3_M400 | 6_M300 | 6_M400 | 6_M300 | 6_M400 |
+-------------------------+---------+--------+---------+--------+---------+--------+
| 2012-12-05 16:29:51.000 | 2357,69 | 520 | 1694,81 | 470 | 2046,33 | 111 |
+-------------------------+---------+--------+---------+--------+---------+--------+
Upvotes: 1
Views: 265
Reputation: 247710
This is still a PIVOT
query but before you PIVOT
you must perform an UNPIVOT
of your columns.
First, you perform the UNPIVOT
which takes your current multiple columns and transforms them into two columns - one with the value and the other with the column name. The key for the UNPIVOT
is that the datatypes be the same, so in the subquery I cast
any columns to the same datatype:
select timestamp,
value, cast(iddevice as varchar(10)) + '_'+col as col
from
(
select iddevice,
timestamp,
cast(m300 as varchar(10)) m300,
cast(m400 as varchar(10)) m400
from yourtable
) src
unpivot
(
value
for col in (m300, m400)
) unpiv
Result:
| TIMESTAMP | VALUE | COL |
------------------------------------------------------
| December, 05 2012 16:29:51+0000 | 2357,69 | 3_m300 |
| December, 05 2012 16:29:51+0000 | 520 | 3_m400 |
| December, 05 2012 16:29:51+0000 | 1694,81 | 6_m300 |
| December, 05 2012 16:29:51+0000 | 470 | 6_m400 |
| December, 05 2012 16:29:51+0000 | 2046,33 | 1_m300 |
| December, 05 2012 16:29:51+0000 | 111 | 1_m400 |
Once you complete the unpivot, then you can apply the PIVOT
function:
select *
from
(
select timestamp,
value, cast(iddevice as varchar(10)) + '_'+col as col
from
(
select iddevice,
timestamp,
cast(m300 as varchar(10)) m300,
cast(m400 as varchar(10)) m400
from yourtable
) src
unpivot
(
value
for col in (m300, m400)
) unpiv
) src1
pivot
(
max(value)
for col in ([3_m300], [3_m400],
[6_m300], [6_m400],
[1_m300], [1_m400])
) piv
Results:
| TIMESTAMP | 3_M300 | 3_M400 | 6_M300 | 6_M400 | 1_M300 | 1_M400 |
--------------------------------------------------------------------------------------------
| December, 05 2012 16:29:51+0000 | 2357,69 | 520 | 1694,81 | 470 | 2046,33 | 111 |
If you have an unknown number of IdDevices
that you want to transform into columns, then you can use dynamic SQL:
DECLARE @cols AS NVARCHAR(MAX),
@query AS NVARCHAR(MAX)
select @cols = STUFF((SELECT DISTINCT ','
+ quotename(cast(t.IdDevice as varchar(10)) +'_'
+c.name)
from yourtable t
cross apply sys.columns as C
where C.object_id = object_id('yourtable') and
C.name not in ('IdDevice', 'Timestamp')
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set @query = 'SELECT timestamp,' + @cols + ' from
(
select timestamp,
value, cast(iddevice as varchar(10)) + ''_''+col as col
from
(
select iddevice,
timestamp,
cast(m300 as varchar(10)) m300,
cast(m400 as varchar(10)) m400
from yourtable
) src
unpivot
(
value
for col in (m300, m400)
) unpiv
) x
pivot
(
max(value)
for col in (' + @cols + ')
) p '
execute(@query)
Edit, if you need a totals field for each m value, then you can use:
select timestamp,
[3_m300], [3_m400],
[6_m300], [6_m400],
[1_m300], [1_m400],
[1_m300] + [3_m300] + [6_m300] Total_m300,
[1_m400] + [3_m400] + [6_m400] Total_m400
from
(
select timestamp,
value, cast(iddevice as varchar(10)) + '_'+col as col
from
(
select iddevice,
timestamp,
m300,
m400
from yourtable
) src
unpivot
(
value
for col in (m300, m400)
) unpiv
) src1
pivot
(
sum(value)
for col in ([3_m300], [3_m400],
[6_m300], [6_m400],
[1_m300], [1_m400])
) piv
Upvotes: 2