在一张桌子上旋转

时间:2013-02-06 15:42:44

标签: sql sql-server pivot

想象一下,我们有以下数据集:

Name    City           Date
Paul    Milan          04/01/2013
Charls  Rome           04/01/2013
Jim     Tokyo          04/01/2013
Justin  San Francisco  04/01/2013
Bill    London         04/01/2013
Paul    Berlin         05/01/2013
Charls  El Cairo       05/01/2013
Jim     Milan          05/01/2013
Justin  Paris          05/01/2013
Bill    Madrid         05/01/2013

每个人[Name]在某一天[City]访问了某个城镇[Date]

我们要做的是建立一个包含[Name][City day 1][City day 2]的表格,如下所示:

Name    City 04/01/2013 City 05/01/2013
Paul    Milan           Berlin
Charls  Rome            El Cairo
Jim     Tokyo           Milan
Justin  San Francisco   Paris
Bill    London          Madrid

我们如何编写查询来执行此操作?

2 个答案:

答案 0 :(得分:2)

此类数据转换称为PIVOT。从SQL Server 2005开始,有一个函数可以为您执行此数据轮换。但这可以通过许多不同的方式完成。

您可以使用聚合函数和CASE 转移数据:

select
  name,
  max(case when date = '2013-04-01' then city end) [City 04/01/2013],
  max(case when date = '2013-05-01' then city end) [City 05/01/2013]
from yourtable
group by name

请参阅SQL Fiddle with Demo

或者您可以使用PIVOT功能:

select name, [2013-04-01] as [City 04/01/2013], [2013-05-01] as [City 05/01/2013]
from
(
  select name, city, date
  from yourtable
) src
pivot
(
  max(city)
  for date in ([2013-04-01], [2013-05-01])
) piv

请参阅SQL Fiddle with Demo

这甚至可以通过多次加入你的桌子来完成:

select d1.name,
  d1.city [City 04/01/2013], 
  d2.city [City 05/01/2013]
from yourtable d1
left join yourtable d2
  on d1.name = d2.name
  and d2.date = '2013-05-01'
where d1.date = '2013-04-01'

请参阅SQL Fiddle with Demo

如果您想知道要转换为列的日期,则上述查询将会很有效。但是如果你有一个未知数量的列,那么你将需要使用动态sql:

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

select @cols = STUFF((SELECT distinct ',' + QUOTENAME(convert(char(10), date, 120)) 
                    from yourtable
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

select @colNames = STUFF((SELECT distinct ',' + QUOTENAME(convert(char(10), date, 120)) +' as '+ QUOTENAME('City '+convert(char(10), date, 120))
                    from yourtable
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT name, ' + @colNames + ' from 
             (
                select name, 
                  city, 
                  convert(char(10), date, 120) date
                from yourtable
            ) x
            pivot 
            (
                max(city)
                for date in (' + @cols + ')
            ) p '

execute(@query)

请参阅SQL Fiddle with Demo

他们都给出了结果:

|   NAME | CITY 04/01/2013 | CITY 05/01/2013 |
----------------------------------------------
|   Paul |           Milan |          Berlin |
| Charls |            Rome |        El Cairo |
|    Jim |           Tokyo |           Milan |
| Justin |   San Francisco |           Paris |
|   Bill |          London |          Madrid |

答案 1 :(得分:1)

最简单的方法是使用CASE

SELECT  Name,
        MAX(CASE WHEN DATE = '04/01/2013' THEN City END) [City 04/01/2013],
        MAX(CASE WHEN DATE = '05/01/2013' THEN City END) [City 05/01/2013]
FROM    tableName
GROUP   BY Name