行成列

时间:2012-11-28 06:50:19

标签: sql sql-server sql-server-2005 pivot

这是我的查询

   select * from dbo.tblHRIS_ChildDetails where intSID=463

输出:

   intCHID  intsid nvrchildname  nvrgender      dttchildDOB                   Occupation 
        3      463     SK           Female     2001-12-11 00:00:00.000  Studying    
        4      463     SM            Male      2007-10-08 00:00:00.000  Student 

我需要像这样的输出这是查询是动态的,它可能会根据intSID返回n行

chidname1   gender  DOB   childoccupation1           chidname2  gender  DOB childoccupation2 
  SK     female  2001-12-11 00:00:00.000  studying     SM        Male   2007-10-08 00:00:00.000     Student

2 个答案:

答案 0 :(得分:2)

对于此类数据,您需要同时实现SQL Server的UNPIVOTPIVOT功能。 UNPIVOT从多列中获取数据并将其放入两列,然后应用PIVOT将数据转换回列。

如果您知道要转换的所有值,那么您可以对其进行硬编码,类似于:

select *
from
(
  select value, col+'_'+cast(rn as varchar(10)) col
  from
  (
    select nvrchildname,
      nvrgender,
      convert(varchar(10), dttchildDOB, 120) dttchildDOB,
      occupation,
      row_number() over(partition by intsid order by intCHID) rn
    from tblHRIS_ChildDetails
    where intsid = 463
  ) src
  unpivot
  (
    value 
    for col in (nvrchildname, nvrgender, dttchildDOB, occupation)
  ) unpiv
) src1
pivot
(
  max(value)
  for col in ([nvrchildname_1], [nvrgender_1], 
              [dttchildDOB_1], [occupation_1], 
              [nvrchildname_2], [nvrgender_2], 
              [dttchildDOB_2], [occupation_2]) 
) 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('tblHRIS_ChildDetails') and
               C.name not in ('intCHID', 'intsid')
         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 intsid order by intCHID) rn
                      from tblHRIS_ChildDetails
                    ) t
                    cross apply sys.columns as C
                   where C.object_id = object_id('tblHRIS_ChildDetails') and
                         C.name not in ('intCHID', 'intsid')
                   group by c.name, t.rn
                   order by t.rn
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query 
  = 'select *
      from
      (
        select col+''_''+cast(rn as varchar(10)) col, value
        from 
        (
          select nvrchildname,
            nvrgender,
            convert(varchar(10), dttchildDOB, 120) dttchildDOB,
            occupation,
            row_number() over(partition by intsid order by intCHID) rn
          from tblHRIS_ChildDetails
          where intsid = 463
        ) x
        unpivot
        (
          value
          for col in ('+ @colsunpivot +')
        ) u
      ) x1
      pivot
      (
        max(value)
        for col in  ('+ @colspivot +')
      ) p'

exec(@query)

请参阅SQL Fiddle with Demo

两个查询的结果是:

| NVRCHILDNAME_1 | NVRGENDER_1 | DTTCHILDDOB_1 | OCCUPATION_1 | NVRCHILDNAME_2 | NVRGENDER_2 | DTTCHILDDOB_2 | OCCUPATION_2 |
-----------------------------------------------------------------------------------------------------------------------------
|             SK |      Female |    2001-12-11 |     Studying |             SM |        Male |    2007-10-08 |      Student |

答案 1 :(得分:0)

您必须提供不同的列名称,但除此之外,它很简单。但正如其他人所说的那样,这种情况并不常见,如果你想打印一些包含两列的报告,那就好了。

select 
  max(case when intCHID=1 then nvrchildname end) as chidname1,
  max(case when intCHID=1 then gender      end) as gender1,
  max(case when intCHID=1 then dttchildDOB end) as DOB1,
  max(case when intCHID=1 then Occupation  end) as cildOccupation1,
  max(case when intCHID=2 then nvrchildname end) as chidname2,
  max(case when intCHID=2 then gender      end) as gender2,
  max(case when intCHID=2 then dttchildDOB end) as DOB2,
  max(case when intCHID=2 then Occupation  end) as cildOccupation2
from 
  dbo.tblHRIS_ChildDetails 
where 
  intSID=463