简体   繁体   English

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

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

I have data like this: 我有这样的数据:

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

I want to my result like this: 我想要这样的结果:

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

I don't know how many columns because MaGiangVienID have a lot of DateID 我不知道有多少列,因为MaGiangVienID有很多DateID

Please help me!!Thanks a lot. 请帮助我!非常感谢。

For this type of data transformation you need to apply both the UNPIVOT and PIVOT functions. 对于这种类型的数据转换,您需要同时应用UNPIVOTPIVOT函数。 The UNPIVOT takes the data from the multiple columns and places it into rows and then the PIVOT takes the rows and converts it back to columns. UNPIVOT从多列中获取数据并将其放置到行中,然后PIVOT从行中获取数据并将其转换回列中。

To perform the UNPIVOT all of the values that you convert to rows must be the same datatype so conversion might be needed. 要执行UNPIVOT ,您转换为行的所有值都必须是相同的数据类型,因此可能需要转换。

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

See SQL Fiddle with Demo . 请参阅带有演示的SQL Fiddle The result of the unpivot is: 取消透视的结果是:

|   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 |

As you see the UNPIVOT generates the new column names with the DateId appended to the end of it. 如您所见, UNPIVOT生成新列名,并在其DateId附加DateId Now you apply the PIVOT function. 现在,您将应用PIVOT功能。

Static 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

See SQL Fiddle with Demo 参见带有演示的SQL Fiddle

Now the above version works great if you have a known number of DateId values but you stated that you don't so you will want to implement this same query using dynamic sql. 现在,如果您拥有已知数量的DateId值,但上面的版本非常DateId但您声明了不这样的说法,那么您将希望使用动态sql实现相同的查询。

Dynamic PIVOT: 动态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)

See SQL Fiddle with Demo 参见带有演示的SQL Fiddle

Both versions produce the same result: 两种版本产生相同的结果:

The result is: 结果是:

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

If you do not have access to the UNPIVOT / PIVOT functions then you can replicate the query. 如果您无权使用UNPIVOT / PIVOT函数,则可以复制查询。 The UNPIVOT function can be replicated using a UNION ALL and the PIVOT can be produced using a CASE statement with an aggregate function: 可以使用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

See SQL Fiddle with Demo 参见带有演示的SQL Fiddle

All versions will produce identical results. 所有版本将产生相同的结果。

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

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