在SQL Server中将多个列转换为行?

时间:2013-09-05 19:25:40

标签: sql-server pivot unpivot

我有一个包含这样数据的表

create table temp
(
    colName varchar(50),
    name varchar(50),
    icon varchar(150),
    totalcount int
)

insert into temp values ('Eng1', 'Following', 'followingicon.png', 1564)

insert into temp values ('Eng2','Total Followers', 'followericon.png', 500)

insert into temp values ('Eng3','Direct Messages', 'messageicon.png', 800)

如何选择并使数据显示为

End Result

以Eng1,Eng2和Eng3为列标题

这是我到目前为止所得到的,但它只是第一级。我需要获得所有三个级别

DECLARE @cols AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX);

SET @cols = STUFF((SELECT distinct ',' + QUOTENAME(c.colName) 
            FROM temp c
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')


set @query = 'SELECT ' + @cols + ' from 
            (
                select colName              
                    , totalcount
                from temp
           ) x
            pivot 
            (
                 max( totalcount)
                for colName in (' + @cols + ')               
            ) p'

execute(@query)

我正在使用SQL Server 2008。

感谢您的帮助!

2 个答案:

答案 0 :(得分:3)

这是一种方式:

DECLARE @cols   AS NVARCHAR(MAX),
        @query  AS NVARCHAR(MAX);

SET @cols = STUFF((SELECT distinct ',' + QUOTENAME(c.colName) 
            FROM #temp c
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
            ,1,1,'')


SET @query = 'SELECT ' + @cols + ' FROM 
            (
                SELECT y.*
                FROM #Temp t
                CROSS APPLY 
                (
                    VALUES (t.colname,CONVERT(VARCHAR(150),name),''name''),
                           (t.colname,icon,''icon''),
                           (t.colname,CONVERT(VARCHAR(150),totalcount),''totalcount'')
                ) y (colName, value, Data)
           ) x
            PIVOT 
            (
                 MAX(Value)
                FOR colName IN (' + @cols + ')               
            ) p'

EXECUTE(@query)

答案 1 :(得分:3)

当您使用动态SQL时,我的建议是首先编写查询的硬编码版本以使逻辑正确,然后将其转换为动态SQL。

要获得结果,您必须首先查看nameicontotalcount列的隐藏,然后您可以应用数据透视来创建新列。您可以使用UNPIVOT函数或CROSS APPLY将列转换为行。将数据从列转换为行的查询将是:

select colname, origCol, value
from temp
cross apply
(
  select 'name', name union all
  select 'icon', icon union all
  select 'totalcount', cast(totalcount as varchar(50))
) c (origCol, value)

Demo。这将为您提供以下格式的数据:

| COLNAME |    ORIGCOL |             VALUE |
|    Eng1 |       name |         Following |
|    Eng1 |       icon | followingicon.png |
|    Eng1 | totalcount |              1564 |
|    Eng2 |       name |   Total Followers |

然后,您可以将PIVOT功能应用于新的colname值:

select Eng1, Eng2, Eng3
from 
(
  select colname, origCol, value
  from temp
  cross apply
  (
    select 'name', name union all
    select 'icon', icon union all
    select 'totalcount', cast(totalcount as varchar(50))
  ) c (origCol, value)
) src
pivot
(
  max(value)
  for colname in (Eng1, Eng2, Eng3)
) piv

SQL Fiddle with Demo。正如我所说,你需要一个动态版本,所以你现在可以将逻辑正确转换为动态SQL查询:

DECLARE @cols AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX);

SET @cols = STUFF((SELECT distinct ',' + QUOTENAME(c.colName) 
            FROM temp c
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')


set @query = 'SELECT ' + @cols + ' 
          from 
          (
            select colname, origCol, value
            from temp
            cross apply
            (
              select ''name'', name union all
              select ''icon'', icon union all
              select ''totalcount'', cast(totalcount as varchar(50))
            ) c (origCol, value)
           ) x
            pivot 
            (
                 max(value)
                for colName in (' + @cols + ')               
            ) p'

execute sp_executesql @query;

SQL Fiddle with Demo。这将得到一个结果:

|              ENG1 |             ENG2 |            ENG3 |
| followingicon.png | followericon.png | messageicon.png |
|         Following |  Total Followers | Direct Messages |
|              1564 |              500 |             800 |