SQL Server中的数据透视列

时间:2014-01-05 16:42:19

标签: sql sql-server pivot

我在SQL中有3列 - 名称,ID和句点:

Name    CarID    Period
--------------------- 
Bob     121      Jan 08 
Bob     123      Jan 08 
Bob     121      Feb 08 
Steve   121      Jan 08
Ruth    139      Feb 08

我需要将CarID与唯一名称和期间一起转动,即:

Name    Period   Col1    Col2   Col3
-------------------------------------
Bob     Jan 08   121     123    NULL
Bob     Feb 08   121     NULL   NULL
Steve   Jan 08   121     NULL   NULL
Ruth    Feb 08   139     NULL   NULL

我的问题是,指定用户的名字可能有1或x个CarID。我已经尝试了一些动态数据透视查询,但他们都必须设置列标题名称。

1 个答案:

答案 0 :(得分:1)

有几种方法可以获得所需的结果,但为了成功返回每个caridname的多个period值,我会使用窗口函数与row_number()类似,可为name / period的每个分区生成唯一序列。

您的查询将从使用以下内容开始:

select name, carid, period,
  'col'+
    cast(row_number() over(partition by name, period
                            order by carid) as varchar(10)) seq
from yourtable;

SQL Fiddle with Demo。这将为您提供以下数据,然后您可以将其PIVOT到列中。

|  NAME | CARID | PERIOD |  SEQ |
|-------|-------|--------|------|
|   Bob |   121 | Feb 08 | col1 |
|   Bob |   121 | Jan 08 | col1 |
|   Bob |   123 | Jan 08 | col2 |
|  Ruth |   139 | Feb 08 | col1 |
| Steve |   121 | Jan 08 | col1 |

然后,您可以使用聚合函数和类似于:

的CASE表达式将此数据转换为列
select 
  name, 
  period,
  max(case when seq = 'col1' then carid end) col1,
  max(case when seq = 'col2' then carid end) col2,
  max(case when seq = 'col3' then carid end) col3
from
(
  select name, carid, period,
    'col'+
      cast(row_number() over(partition by name, period
                              order by carid) as varchar(10)) seq
  from yourtable
) d
group by name, period;

SQL Fiddle with Demo。也可以使用PIVOT函数将其转换为列:

select name, period, col1, col2, col3
from
(
  select name, carid, period,
    'col'+
      cast(row_number() over(partition by name, period
                              order by carid) as varchar(10)) seq
  from yourtable
) d
pivot
(
  max(carid)
  for seq in (col1, col2, col3)
) p;

SQL Fiddle with Demo。如果您的值有限,上述两个查询将很有用,但如果您有未知值,则必须使用动态SQL生成结果:

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

select @cols = STUFF((SELECT ',' + QUOTENAME(seq) 
                    from
                    (
                      select 'col'+
                          cast(row_number() over(partition by name, period
                                                  order by carid) as varchar(10)) seq
                      from yourtable
                    ) d
                    group by seq
                    order by seq
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT name, period,' + @cols + ' 
            from 
            (
              select name, carid, period,
                ''col''+
                  cast(row_number() over(partition by name, period
                                          order by carid) as varchar(10)) seq
              from yourtable
            ) x
            pivot 
            (
                max(carid)
                for seq in (' + @cols + ')
            ) p '

execute sp_executesql @query;

SQL Fiddle with Demo。所有版本都会给你一个类似于:

的结果
|  NAME | PERIOD | COL1 |   COL2 |
|-------|--------|------|--------|
|   Bob | Feb 08 |  121 | (null) |
|  Ruth | Feb 08 |  139 | (null) |
|   Bob | Jan 08 |  121 |    123 |
| Steve | Jan 08 |  121 | (null) |