动态 SQL 使用多列交叉应用来反透视数据
Posted
技术标签:
【中文标题】动态 SQL 使用多列交叉应用来反透视数据【英文标题】:Dynamic SQL to Unpivot Data using Cross Apply with Multiple Columns 【发布时间】:2021-04-28 18:05:23 【问题描述】:Microsoft SQL Server Management Studio v18.8
我有一个表,其中包含不同的列和列名。我需要对数据进行反透视,以便最终将其存储到不同的表中。不幸的是,这是从 Google 表格中提取原始表格的过程。
我在这里查找了几篇文章和答案,但我无法成功复制其中任何一篇。我需要根据项目、时间戳和位置进行反透视。那么 Q1、Q2、Q3 等应该是不可旋转的。下面是一个示例表和查询,它将获得我想要的结果。在动态 SQL 中为将来的列添加/修改提供任何帮助将不胜感激。我也愿意使用 UNPIVOT 或任何其他功能来获得所需的结果。实际数据源将是永久表,而不是临时表。
创建表格
DROP TABLE IF EXISTS #test
CREATE TABLE #test (Item VARCHAR(16), Timestamp DATETIME, Location VARCHAR(2), Q1 VARCHAR(3), Q2 VARCHAR(3), Q3 VARCHAR(3))
INSERT INTO #test VALUES('Stapler','2021-04-14 12:00:00.000', 'US','Yes','No','Yes'),
('Paper','2021-04-10 16:00:00.000', 'CA','No','Yes','Yes'),
('Pen','2021-04-06 15:00:00.000','MX','Yes','Yes','No')
使用交叉应用取消透视
SELECT A.Item,
A.Timestamp,
A.Location,
B.*
FROM #test AS A
CROSS APPLY
(
VALUES ('Q1', A.Q1),
('Q2', A.Q2),
('Q3', A.Q3)
) B (Question,Answer)
【问题讨论】:
【参考方案1】:您可以使用一些 JSON 来动态反透视您的数据。如果不是 2016+ ... 有类似的 XML 方法。
示例
Select A.Item
,A.Timestamp
,A.Location
,B.*
From #test A
Cross Apply (
Select Question = [Key]
,Answer = [Value]
From OpenJson((Select A.* For JSON Path,Without_Array_Wrapper,INCLUDE_NULL_VALUES ) )
Where [Key] not in ('Item','Timestamp','Location')
) B
结果
编辑 - XML 版本更新
Select A.Item
,A.Timestamp
,A.Location
,C.*
From #test A
Cross Apply ( values ((Select A.* for XML RAW,Type)) )B(XMLData)
Cross Apply (
Select Question = xAttr.value('local-name(.)', 'varchar(100)')
,Answer = xAttr.value('.','varchar(max)')
From XMLData.nodes('//@*') xNode(xAttr)
Where xAttr.value('local-name(.)', 'varchar(100)') not in ('Item','Timestamp','Location')
) C
【讨论】:
这太棒了! JSON 方法运行良好。我将不得不更多地研究 JSON 以及您在其中使用的函数是如何工作的。到目前为止,我还没有看到这种方法。 @MonkeyMonkey 总是乐于提供帮助,沉浸在 JSON 池中非常值得您花时间。 相当整洁。在 XML 版本中添加,TYPE
,如果您添加(Select A.* for XML RAW, TYPE)
,则无需转换。 text()
也比 .
快以上是关于动态 SQL 使用多列交叉应用来反透视数据的主要内容,如果未能解决你的问题,请参考以下文章