簡體   English   中英

編寫一個 SQL 查詢將表從 A 轉換為 B

[英]Write a SQL query to convert table from A to B

我有一個數據庫表(表 A),在 SQL Server 2016 中如下所示:

表 A:

ID     Group       2018     2019    2020
-----------------------------------------
ID1    Group A      200      300     400
ID2    Group B      100      800     ---
ID2    Group B      ----     500     300

我想編寫一個 SQL 查詢或類似的東西或報告工具來生成報告/表格(將表格 A 轉換為表格 B),如下所示:

表 B:

ID       Group   -   Year  -      Value
----------------------------------------
ID1      Group A     2018         200
ID1      Group A     2019         300
ID1      Group A     2020         400
ID2      Group B     2018         100
ID2      Group B     2019         800
ID2      Group B     2019         500
ID2      Group B     2020         300

如果可以通過編寫 SQL 查詢來實現,那就太好了。 如果它需要使用編程語言編寫程序或使用工具,那也可以,但請告訴我使用什么以及如何實現(我知道一些 C# 編程)。

(我知道我不應該使用 ID 和 Group 作為列名。我不會在數據庫表中真正使用該名稱,只是為了簡化這里的問題)

任何人都可以幫忙嗎? 非常感謝!

規范方法使用union all

select id, group, 2018 as year, "2018" from t
union all
select id, group, 2019 as year, "2019" from t
union all
select id, group, 2020 as year, "2018" from t;

但是,在 SQL 服務器中,我強烈建議apply

select t.id, t.group, v.*
from t cross apply
     (values (2018, [2018]), (2019, [2019]), (2020, [2020])
     ) v(year, value)
where v.value is not null;

以防萬一您隨着時間的推移有可變列或附加列。

請注意,您只需要 EXCLUDE 某些列並省略 NULLS。

全面披露:Gordon 的 APPLY 性能更佳。

例子

Select A.[ID]
      ,A.[Group]
      ,[Year] = B.[Key]
      ,[Value] = try_convert(int,B.[Value])  --<< choose the proper data type (optional)
 From  YourTable A
 Cross Apply (
                Select *
                 From OpenJson( (Select A.* For JSON Path,Without_Array_Wrapper ) ) 
                 Where [Key] not in ('ID','Group')
             ) B

退貨

ID  Group       Year    Value
ID1 Group A     2018    200
ID1 Group A     2019    300
ID1 Group A     2020    400
ID2 Group B     2018    100
ID2 Group B     2019    800
ID2 Group B     2019    500
ID2 Group B     2020    300

編輯——XML 版本如果不是 2016+

Select A.[ID]
      ,A.[Group]
      ,[Year]  = replace(replace(C.[Item],'X003',''),'_','')
      ,[Value] = try_convert(int,C.[Value])  --<< choose the proper data type (optional)
 From  YourTable A
 Cross Apply ( values ( convert(xml,(Select A.* for XML RAW)) ) ) B(XMLData)
 Cross Apply (
                Select Item  = xAttr.value('local-name(.)', 'varchar(100)')
                      ,Value = xAttr.value('.','varchar(max)')
                 From  XMLData.nodes('//@*') xNode(xAttr)
                 Where xAttr.value('local-name(.)', 'varchar(100)') not in ('ID','Group')
             ) C

使用 UNPIVOT 的解決方案:

select * from A
UNPIVOT 
(
   [value] for [Year] in ([2018],[2019],[2020])
)u;

希望能幫助到你。!

這是我的解決方案,完全符合您的需求

我用方括號將關鍵字和年份作為列名括起來

Select id, [Group], [year], value
from
(
select id, [Group], 2018 as [year], [2018] as value from a
union all
select id, [Group], 2019 as [year], [2019] as value from a
union all
select id, [Group], 2020 as [year], [2020] as value from a
) Q
Where value is not null
order by id, [Group], [year]

這是小提琴

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM