我有一个带有 XML 列的表。我没有该列的数据字典或 XML 结构的定义。大约有 150 万条记录。从小样本的目视检查来看,XML 的结构似乎非常相似。我想要做的是运行一些 SQL,它将为我提供跨所有记录的 XML 结构的超集。
表称为
Remittance
,列称为 RemittInstr
。
例如,如果我有两条测试数据记录,其
RemittInstr
列中的 XML 值为:
第 1 行:
<ri>
<Msg Type="MT103">
<AccountNo>12345678</AccountNo>
<Description code="ORCSR">Ordering Customer<Description>
</Msg>
</ri>
第 2 行:
<ri>
<Msg Type="MT202">
<BICFI>ABCD1234</BICFI>
<Description code="FI">Financial Institution<Description>
</Msg>
</ri>
如何编写将返回以下行的查询:
/ri
/ri/Msg
/ri/Msg/@Type
/ri/Msg/AccountNo
/ri/Msg/BICFI
/ri/Msg/Description
/ri/Msg/Description/@code
这样我就可以全面了解所有行的 XML 结构?
编辑:这与链接问题有很大不同,因为链接问题仅处理单个 XML 值。问题是查找整个表中各行的 XML 结构。这样做的解决方案是完全不同的。 @Charlieface 在下面的评论中提供了一个很好的解决方案的链接。
您可以为此使用递归 CTE。我警告你,这在 150 万行上可能会非常慢。
获取属性名称有点复杂,因为你似乎无法做到
.nodes('@*')
来获取所有属性。
相反,您需要
CROSS APPLY
节点名称及其属性的并集。
WITH cte AS (
SELECT
xpath = r.RemittanceInstr.value('local-name(.)[1]','nvarchar(max)'),
child = r.RemittanceInstr.query('*')
FROM Remittance r
UNION ALL
SELECT
xpath = CONCAT(cte.xpath, '/', v2.name),
v2.child
FROM cte
CROSS APPLY cte.child.nodes('*') x(nd)
CROSS APPLY (VALUES (x.nd.value('local-name(.)[1]','nvarchar(max)') )) v(name)
CROSS APPLY (
SELECT
v.name,
x.nd.query('./*')
UNION ALL
SELECT
CONCAT(v.name, '/@', x2.attr.value('local-name(.)[1]','nvarchar(max)')),
NULL
FROM x.nd.nodes('*/@*') x2(attr)
) v2(name, child)
)
SELECT DISTINCT
xpath
FROM cte;