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