繁体   English   中英

如果列数未知,如何将行转换为列

[英]how to convert row to column if unknown number of columns SQL server

我有这样的数据:

 MaGiangVienID  |  SoTiet1  |  SoTiet2  |  DateID
79000G07.000206 |      60   |    60.00  |     t11
79000G07.000206 |      54   |    54.00  |     t12

我想要这样的结果:

 MaGiangVienID  | SoTiet1_t11 | SoTiet2_t11 | SoTiet1_t12 | SoTiet2_t12
79000G07.000206 |          60 |       60.00 |          54 |       54.00

我不知道有多少列,因为MaGiangVienID有很多DateID

请帮助我!非常感谢。

对于这种类型的数据转换,您需要同时应用UNPIVOTPIVOT函数。 UNPIVOT从多列中获取数据并将其放置到行中,然后PIVOT从行中获取数据并将其转换回列中。

要执行UNPIVOT ,您转换为行的所有值都必须是相同的数据类型,因此可能需要转换。

取消枢纽

select MaGiangVienID, 
    value, 
    col +'_'+DateId col
from
(
  select MaGiangVienID, 
    cast(SoTiet1 as varchar(50)) SoTiet1, 
    cast(SoTiet2 as varchar(50)) SoTiet2,
    DateID
  from yourtable
) src
unpivot
(
  value
  for col in (SoTiet1, SoTiet2)
) unpiv

请参阅带有演示的SQL Fiddle 取消透视的结果是:

|   MAGIANGVIENID | VALUE |         COL |
-----------------------------------------
| 79000G07.000206 |    60 | SoTiet1_t11 |
| 79000G07.000206 | 60.00 | SoTiet2_t11 |
| 79000G07.000206 |    54 | SoTiet1_t12 |
| 79000G07.000206 | 54.00 | SoTiet2_t12 |

如您所见, UNPIVOT生成新列名,并在其DateId附加DateId 现在,您将应用PIVOT功能。

静态PIVOT:

select MaGiangVienID, SoTiet1_t11, SoTiet2_t11, SoTiet1_t12, SoTiet2_t12
from
(
  select MaGiangVienID, 
    value, 
    col +'_'+DateId col
  from
  (
    select MaGiangVienID, 
      cast(SoTiet1 as varchar(50)) SoTiet1, 
      cast(SoTiet2 as varchar(50)) SoTiet2,
      DateID
    from yourtable
  ) src
  unpivot
  (
    value
    for col in (SoTiet1, SoTiet2)
  ) unpiv
) src
pivot
(
  max(value)
  for col in (SoTiet1_t11, SoTiet2_t11, SoTiet1_t12, SoTiet2_t12)
) piv

参见带有演示的SQL Fiddle

现在,如果您拥有已知数量的DateId值,但上面的版本非常DateId但您声明了不这样的说法,那么您将希望使用动态sql实现相同的查询。

动态PIVOT:

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 ('MaGiangVienID', 'DateID')
         for xml path('')), 1, 1, '')

select @colsPivot = STUFF((SELECT DISTINCT ',' 
                      + quotename(c.name + '_'+t.DateId)
                    from yourtable t
                    cross apply sys.columns as C
                   where C.object_id = object_id('yourtable') and
                         C.name not in ('MaGiangVienID', 'DateID')

            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query 
  = 'select MaGiangVienID, '+@colsPivot+'
      from
      (
          select MaGiangVienID, value, col +''_''+DateId col
          from
          (
            select MaGiangVienID, 
              cast(SoTiet1 as varchar(50)) SoTiet1, 
              cast(SoTiet2 as varchar(50)) SoTiet2,
              DateID
            from yourtable
          ) src
          unpivot
          (
            value
            for col in ('+@colsUnpivot+')
          ) unpiv
      ) src
      pivot
      (
        max(value)
        for col in ('+ @colspivot +')
      ) p'

exec(@query)

参见带有演示的SQL Fiddle

两种版本产生相同的结果:

结果是:

|   MAGIANGVIENID | SOTIET1_T11 | SOTIET2_T11 | SOTIET1_T12 | SOTIET2_T12 |
---------------------------------------------------------------------------
| 79000G07.000206 |          60 |       60.00 |          54 |       54.00 |

如果您无权使用UNPIVOT / PIVOT函数,则可以复制查询。 可以使用UNION ALL复制UNPIVOT函数,并可以使用带有聚合函数的CASE语句生成PIVOT

select MaGiangVienID,
  max(case when col = 'SoTiet1_t11' then value end) SoTiet1_t11,
  max(case when col = 'SoTiet2_t11' then value end) SoTiet2_t11,
  max(case when col = 'SoTiet1_t12' then value end) SoTiet1_t12,
  max(case when col = 'SoTiet2_t12' then value end) SoTiet2_t12
from
(
  select MaGiangVienID, 'SoTiet1_t11' col, cast(SoTiet1 as varchar(50)) value
  from yourtable
  where DateID = 't11'
  union all
  select MaGiangVienID, 'SoTiet2_t11' col, cast(SoTiet2 as varchar(50)) value
  from yourtable
  where DateID = 't11'
  union all
  select MaGiangVienID, 'SoTiet1_t12' col, cast(SoTiet1 as varchar(50)) value
  from yourtable
  where DateID = 't12'
  union all
  select MaGiangVienID, 'SoTiet2_t12' col, cast(SoTiet2 as varchar(50)) value
  from yourtable
  where DateID = 't12'
) src
group by MaGiangVienID

参见带有演示的SQL Fiddle

所有版本将产生相同的结果。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM