【问题标题】:Pivot columns in SQL ServerSQL Server 中的数据透视列
【发布时间】:2014-01-06 00:58:35
【问题描述】:

我在 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 一起旋转,即:

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。我尝试了一些动态数据透视查询,但它们都必须设置列标题名称。

【问题讨论】:

标签: sql sql-server pivot


【解决方案1】:

有几种方法可以获得所需的结果,但为了成功地为每个 nameperiod 返回多个 carid 值,我会使用像 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。这将为您提供以下数据,然后您可以将这些数据透视到列中。

|  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) |

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-06
    • 1970-01-01
    相关资源
    最近更新 更多