【问题标题】:rows into columns [duplicate]行成列[重复]
【发布时间】:2012-11-15 23:16:08
【问题描述】:

这是我的查询

   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

【问题讨论】:

  • 在使用关系模型时,您所要求的通常不会完成。你能告诉我们你为什么想要(或认为你想要)这样做吗?

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


【解决方案1】:

对于这种类型的数据,您需要同时实现 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 |

【讨论】:

  • 我有一些疑问,您的解决方案非常棒,但我的性别、职业、子名是 nvarchar,所以如果运行查询我会遇到一些错误,请查看这个小提琴 sqlfiddle.com/#!3/164b7/1跨度>
  • 你能检查一下并告诉
  • 你看到小提琴了吗:)
  • @KajahUser 如果一切都是nvarchar,那么日期转换也必须是——看这个小提琴——sqlfiddle.com/#!3/164b7/2
【解决方案2】:

您必须提供不同的列名,但除此之外,它很简单。但正如其他人所说,这并不常见,看起来如果您想打印一些包含两列的报告。

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

【讨论】:

  • 我无法传递这个 intCHID=1 这是自动生成的列
猜你喜欢
  • 2016-07-09
  • 1970-01-01
  • 1970-01-01
  • 2022-10-12
  • 2020-01-22
  • 2018-09-17
  • 2016-01-02
  • 1970-01-01
  • 2020-11-06
相关资源
最近更新 更多