sql-server - 将多行转换为具有指定标题的列

标签 sql-server pivot

我有一个表,其中包含个人进行的事件的详细信息 - 该表的内容类似于以下内容:

| Person    | Category  | Activity   |
--------------------------------------
| Username1 | X         | X1         |
| Username1 | Y         | Y1         |
| Username1 | Z         | Z1         |

我需要一个可以生成类似以下内容的 SQL 查询,如有任何帮助,我们将不胜感激:

| Person    | Cat1 | Cat1_Act|Cat2 | Cat2_Act| Cat3  | Cat3_Act |
---------------------------------------------------------------
| Username1 | X    | X1      | Y   | Y1      | Z     |    Z1    |

我通过阅读许多帖子了解到可以使用 PIVOT 来实现此目的,但我还没有找到接近我需要的解决方案,因为大多数解决方案通常使用值,例如“X”、“Y”、 'Z'(在我的示例表中)作为表标题,但我希望理想情况下能够为包含新列的表标题指定名称(希望这一切都有意义并且有人可以提供帮助:-))

最佳答案

有多种方法可以获得所需的结果。如果您想要将有限数量的值透视到列中,那么您可以通过几种不同的方式对查询进行硬编码。

使用 CASE 聚合函数:

select 
  person,
  max(case when seq = 1 then category end) Cat1,
  max(case when seq = 1 then activity end) Cat1_Act,
  max(case when seq = 2 then category end) Cat2,
  max(case when seq = 2 then activity end) Cat2_Act,
  max(case when seq = 3 then category end) Cat3,
  max(case when seq = 3 then activity end) Cat3_Act
from
(
  select person, category, activity,
    row_number() over(partition by person
                      order by category) seq
  from yourtable
) d
group by person;

参见SQL Fiddle with Demo 。通过为每个用户的每个类别分配序列或 row_number,您可以使用此行号将行转换为列。

静态枢轴:

如果您想应用 PIVOT 函数,那么我建议首先将 categoryactivity 列取消透视为多行,然后应用透视函数。

;with cte as
(
  select person, category, activity,
    row_number() over(partition by person
                      order by category) seq
  from yourtable
)
select person,
  cat1, cat1_act, 
  cat2, cat2_act,
  cat3, cat3_act
from
(
  select t.person, 
    col = case 
     when c.col = 'cat' then col+cast(seq as varchar(10))
      else 'cat'+cast(seq as varchar(10))+'_'+col
    end,
    value
  from cte t
  cross apply
 (
    select 'cat', category union all
    select 'act', activity
  ) c (col, value)
) d
pivot
(
  max(value)
  for col in (cat1, cat1_act, cat2, cat2_act,
              cat3, cat3_act)
) piv;

参见SQL Fiddle with Demo

动态 PIVOT:最后,如果您有未知数量的值,则可以使用动态 SQL 来获取结果:

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

select @cols = STUFF((SELECT ',' 
                          + QUOTENAME(case 
                                       when d.col = 'cat' then col+cast(seq as varchar(10))
                                        else 'cat'+cast(seq as varchar(10))+'_'+col end) 
                    from 
                    (
                      select row_number() over(partition by person
                                                order by category) seq
                      from yourtable
                    ) t
                    cross apply
                    (
                      select 'cat', 1 union all
                      select 'act', 2
                    ) d (col, so)
                    group by col, so, seq
                    order by seq, so
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT person, ' + @cols + ' 
            from 
            (
              select t.person, 
                col = case 
                 when c.col = ''cat'' then col+cast(seq as varchar(10))
                  else ''cat''+cast(seq as varchar(10))+''_''+col
                end,
                value
              from 
              (
                select person, category, activity,
                  row_number() over(partition by person
                                    order by category) seq
                from yourtable
              ) t
              cross apply
             (
                select ''cat'', category union all
                select ''act'', activity
              ) c (col, value)
            ) x
            pivot 
            (
                max(value)
                for col in (' + @cols + ')
            ) p '

execute sp_executesql @query;

参见SQL Fiddle with Demo 。所有版本都给出结果:

|    PERSON | CAT1 | CAT1_ACT | CAT2 | CAT2_ACT | CAT3 | CAT3_ACT |
| Username1 |    X |       X1 |    Y |       Y1 |    Z |       Z1 |

关于sql-server - 将多行转换为具有指定标题的列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18515170/

相关文章:

mysql - 转向 SQL Access

sql:其中子查询不为空

sql - 空数据库的通用 SQL 查询

sql - 使用 SQL Server 存储过程将列名与变量匹配

sql-server - Excel powerpivot更新错误 "object was not found in the cube"

postgresql - Postgresql 中列的唯一行

SQL Join/Pivot/Unpivot = 疯狂

SQL 静态和动态数据透视不起作用

SQL-Server:从另一个表更新表

sql - 当尝试获取最后 5 个值作为列时,T-SQL 将行转换为列?