提问人:Xoom 提问时间:9/8/2023 最后编辑:marc_sXoom 更新时间:9/11/2023 访问量:62
在 SQL 中将带有嵌套 XML 的列转换为表格格式?
Convert a column with nested XML into tabular format in SQL?
问:
DDL 和示例数据:
-- DDL and sample data population, start
DECLARE @tbl TABLE (OwnerID INT IDENTITY PRIMARY KEY, House XML);
INSERT @tbl (House)
VALUES (N'<House>
<Room id="111111" type="b" name="Master Bedroom" formatstring="">
<Closest>3</Closest>
<Windows>4</Windows>
</Room>
<Room id="222222" type="a" name="Guest Bedroom" formatstring="">
<Closest>1</Closest>
<Windows>2</Windows>
</Room>
<Room id="333333" type="a" name="Bathroom" formatstring="">
<Closest>0</Closest>
<Windows>2</Windows>
</Room>
<Room id="444414" type="b" name="Kitchen" formatstring="">
<Closest>1</Closest>
<Windows>0</Windows>
</Room>
</House>');
-- DDL and sample data population, end
以下是我尝试通过 T-SQL 将列拆分为单个列的尝试:House
...
期望输出:
所有者 ID | 编号 | 类型 | 名字 | 格式字符串 | 最近 | 窗户 |
---|---|---|---|---|---|---|
1 | 111111 | b | 主卧室 | 3 | 4 | |
1 | 222222 | 一个 | 客房 | 1 | 2 | |
1 | 333333 | 一个 | 浴室 | 0 | 2 | |
1 | 444414 | b | 厨房 | 1 | 0 |
SQL Server 版本:发出以下内容:SELECT @@VERSION;
Microsoft SQL Server 2022 (RTM-CU5) (KB5026806) - 16.0.4045.3 (X64)
May 26 2023 12:52:08
Copyright (C) 2022 Microsoft Corporation
Developer Edition (64-bit) on Windows 10 Pro 10.0 <X64> (Build 19045: )
答:
0赞
marc_s
9/8/2023
#1
您可以尝试如下操作:
SELECT
OwnerID,
RoomId = xc.value('@id', 'int'),
RoomType = xc.value('@type', 'varchar(50)'),
RoomName = xc.value('@name', 'varchar(50)'),
FormatString = xc.value('@formatstring', 'varchar(50)'),
Closets = xc.value('(Closest/text())[1]', 'int'),
Windows = xc.value('(Windows/text())[1]', 'int')
FROM
@tbl
CROSS APPLY
House.nodes('/House/Room') AS XT(XC)
这应该会为您返回所需的数据。
您基本上是将 XML “切碎”为根节点下每个元素的 XML 片段列表,然后访问该元素并挑选出各种属性值(等),以及访问一些子元素并获取它们的值<Room>
<House>
<Room>
id
type
更新
如果你想支持多个元素和子元素 - 试试这样的方法:<Closet>
<Windows>
SELECT
OwnerID,
RoomId = xc.value('@id', 'int'),
RoomType = xc.value('@type', 'varchar(50)'),
RoomName = xc.value('@name', 'varchar(50)'),
FormatString = xc.value('@formatstring', 'varchar(50)'),
Closets = xc2.value('(./text())[1]', 'int'),
Windows = xc3.value('(./text())[1]', 'int')
FROM
@tbl
CROSS APPLY
House.nodes('/House/Room') AS XT(XC)
CROSS APPLY
XC.nodes('Closet') AS XT2(XC2)
CROSS APPLY
XC.nodes('Windows') AS XT3(XC3)
评论
0赞
Xoom
9/8/2023
这奏效了!谢谢。
0赞
Xoom
9/8/2023
我遇到了另一个问题,即可能有多个相似的 XML 元素。即:同一<房间>内有 2 个或更多<壁橱>。但是,当前代码没有考虑到这一点。你能建议吗?
0赞
marc_s
9/8/2023
@Xoom:嗯,这是一个全新的问题,真的 - 但基本上,你需要第二级来处理XML元素中的多个子元素......CROSS APPLY
<Room>
0赞
Xoom
9/9/2023
当我仅为“最近”添加 1 个额外的 CROSS APPLY 时,这非常有效。但是,当我尝试在查询中为“窗口”应用第二个 CROSS APPLY 时,此进度丢失了 3 个。使用相同的逻辑,我收到错误。您能建议如何成功实施 3 交叉申请吗?
1赞
Xoom
9/9/2023
谢谢你,先生。作为新用户,在我获得 15 个信用评分之前,他们不会让我为您的帖子投票。我能够使用“outer apply”来复制它来获取所有 null 值。谢谢!
评论