简体   繁体   中英

How to convert SQL Server columns into rows?

I need help to switch columns with rows in SQL. Need to turn this:

+------------+------------+-------------+------+
|    Date    | Production | Consumption | .... |
+------------+------------+-------------+------+
| 2017-01-01 |        100 |        1925 |      |
| 2017-01-02 |        200 |        2005 |      |
| 2017-01-03 |        150 |        1998 |      |
| 2017-01-04 |        250 |        2200 |      |
| 2017-01-05 |         30 |         130 |      |
|...         |            |             |      |
+------------+------------+-------------+------+

into this:

+------------+------------+------------+------------+------------+-----+
| 01-01-2017 | 02-01-2017 | 03-01-2017 | 04-01-2017 | 05-01-2017 | ... |
+------------+------------+------------+------------+------------+-----+
|        100 |        200 |        150 |        250 |         30 |     |
|       1925 |       2005 |       1998 |       2200 |        130 |     |
+------------+------------+------------+------------+------------+-----+

Can someone help me? Should I use PIVOT ?

EDIT: I've tried using some suggestions like PIVOT and UNPIVOT , but I could not achieve the expected result.

I've tried:

SELECT *
FROM (
    SELECT date, Consumption
    FROM Energy
    where date < '2017-02-01'
) r
pivot (sum(Consumption) for date in ([2017-01-01],[2017-01-02],[2017-01-03]....)) c
order by 1

However with the above query I only managed to get some of what I need,

+------------+------------+------------+------------+------------+-----+
| 01-01-2017 | 02-01-2017 | 03-01-2017 | 04-01-2017 | 05-01-2017 | ... |
+------------+------------+------------+------------+------------+-----+
|        100 |        200 |        150 |        250 |         30 |     |
+------------+------------+------------+------------+------------+-----+

I need to have production and consumption, all in the same query, but I can only get one of them.

Is it possible to put more than one column in PIVOT ? I've tried, but unsuccessfully.

You can achieve the desired output with dynamic sql, but be aware of performance and security problems (ie SQL injection) of this approach.

--create test table 
CREATE TABLE dbo.Test ( 
      [Date]      date 
    , Production  int 
    , Consumption int 
) 

--populate test table with values 
insert into dbo.Test 
values 
 ('2017-01-01', 100, 1925) 
,('2017-01-02', 200, 2005) 
,('2017-01-03', 150, 1998) 
,('2017-01-04', 250, 2200) 
,('2017-01-05',  30,  130) 

--table variable that will hold the names of all columns to pivot 
declare @columNames table (ColumnId int identity (1,1), ColumnName varchar(255)) 
--variable that will hold the total number of columns to pivot 
declare @columnCount int 
--variable that will be used to run through the columns to pivot 
declare @counter int = 1 
--this variable holds all column names 
declare @headers nvarchar(max) = '' 
--this variable contains the TSQL dinamically generated 
declare @sql nvarchar(max) = '' 

--populate list of columns to pivot 
insert into @columNames 
select COLUMN_NAME 
from INFORMATION_SCHEMA.COLUMNS 
where 
        TABLE_NAME   = 'test' 
    and TABLE_SCHEMA = 'dbo' 
    and COLUMN_NAME  <>'date' 

--populate column total counter 
select @columnCount = count(*) from @columNames 

--populate list of headers of the result table 
select @headers = @headers + ', ' + quotename([Date]) 
from dbo.Test 

set @headers = right(@headers, len(@headers) - 2) 

--run through the table containing the columns names and generate the dynamic sql query 
while @counter <= @columnCount 
begin 
    select @sql = @sql + ' select piv.* from (select [Date], ' 
        + quotename(ColumnName) + ' from dbo.Test) p pivot (max(' 
        + quotename(ColumnName) + ') for [Date] in (' 
        + @headers + ') ) piv ' 
    from @columNames where ColumnId = @counter 

    --add union all except when we are concatenating the last pivot statement
    if @counter < @columnCount 
        set @sql = @sql + ' union all' 

    --increment counter
    set @counter = @counter + 1 
end 

--execute the dynamic query
exec (@sql)

Result:

在此处输入图片说明

Now if you add a column and some more rows:

--create test table 
CREATE TABLE [dbo].[Test] ( 
      [Date]      date 
    , Production  int 
    , Consumption int 
    , NewColumn   int 
) 

--populate test table with values 
insert into [dbo].[Test] 
values 
 ('2017-01-01', 100, 1925 , 10) 
,('2017-01-02', 200, 2005, 20) 
,('2017-01-03', 150, 1998, 30) 
,('2017-01-04', 250, 2200, 40) 
,('2017-01-05', 30, 130  , 50) 
,('2017-01-06', 30, 130  , 60) 
,('2017-01-07', 30, 130  , 70) 

this is the result:

在此处输入图片说明

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM