在列中选择多行 - 动态数据透视

时间:2012-11-29 01:11:44

标签: sql pivot

以下是初始查询返回的内容:

plan_id   Rep_id     rep_nm         employee_id    Row_id
6720      35         Robert Jones   160            1
6720      36         Pam Smith      23             2
6720      37         Erik Johnson   85             3
6720      38         Sally Ells     212            4
6719      40         Barbara Wax    168            5

我需要获取如下行:

plan_id  Rep_id1 rep_nm1      emp_id1  Rep_id2  rep_nm2   emp_id2 Rep_id3  etc.
6720     35      Robert Jones 160      36       Pam Smith 23      Erik Johnson
6719     40      Barbara Wax  168      NULL     NULL      NULL    NULL    

最多rep_id*列将为5.我尝试搜索此类示例的数据透视查询,但没有成功。

1 个答案:

答案 0 :(得分:1)

您没有指定正在使用的RDBMS,但如果您使用的是SQL Server,则可以实现UNPIVOTPIVOT函数。如果您知道要进行多少个值,那么您可以对值进行硬编码:

select *
from
(
  select plan_id, value, col+cast(rn as varchar(10)) col
  from
  (
    select plan_id, 
      cast(rep_id as varchar(12)) rep_id, 
      rep_nm, 
      cast(employee_id as varchar(12)) employee_id, 
      row_number() over(partition by plan_id order by rep_id) rn
    from yourtable
  ) src
  unpivot
  (
    value
    for col in (rep_id, rep_nm, employee_id)
  ) up
) un
pivot
(
  max(value)
  for col in ([rep_id1], [rep_nm1], [employee_id1], 
              [rep_id2], [rep_nm2], [employee_id2],
              [rep_id3], [rep_nm3], [employee_id3],
              [rep_id4], [rep_nm4], [employee_id4])
) piv

请参阅SQL Fiddle with Demo

但是如果你有一个未知数量的值,那么你可以使用类似这样的动态SQL:

DECLARE @colsUnpivot AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX),
    @colsPivot as  NVARCHAR(MAX)

select @colsUnpivot = stuff((select ','+quotename(C.name)
         from sys.columns as C
         where C.object_id = object_id('yourtable') and
               C.name not in ('plan_id', 'Rep_id', 'Row_id')
         for xml path('')), 1, 1, '')

select @colsPivot = STUFF((SELECT  ',' 
                      + quotename(c.name 
                         + cast(t.rn as varchar(10)))
                    from
                    (
                      select row_number() over(partition by plan_id order by rep_id) rn
                      from yourtable
                    ) t
                    cross apply sys.columns as C
                   where C.object_id = object_id('yourtable') and
                         C.name not in ('plan_id', 'Rep_id', 'Row_id')
                   group by c.name, t.rn
                   order by t.rn
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')


set @query 
  = 'select *
      from
      (
        select plan_id, value, col+cast(rn as varchar(10)) col
        from 
        (
          select plan_id, 
            cast(rep_id as varchar(12)) rep_id, 
            rep_nm, 
            cast(employee_id as varchar(12)) employee_id, 
            row_number() over(partition by plan_id order by rep_id) rn
          from yourtable
        ) x
        unpivot
        (
          value
          for col in ('+ @colsunpivot +')
        ) u
      ) src
      pivot
      (
        max(value)
        for col in ('+ @colspivot +')
      ) p'

exec(@query)

请参阅SQL Fiddle with Demo

两者都会产生相同的结果:

| PLAN_ID | EMPLOYEE_ID1 |      REP_NM1 | EMPLOYEE_ID2 |   REP_NM2 | EMPLOYEE_ID3 |      REP_NM3 | EMPLOYEE_ID4 |    REP_NM4 |
------------------------------------------------------------------------------------------------------------------------------
|    6719 |          168 |  Barbara Wax |       (null) |    (null) |       (null) |       (null) |       (null) |     (null) |
|    6720 |          160 | Robert Jones |           23 | Pam Smith |           85 | Erik Johnson |          212 | Sally Ells |