如何从表中的 XML 列获取所有 XML 路径的超集

问题描述 投票:0回答:1

我有一个带有 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 在下面的评论中提供了一个很好的解决方案的链接。

sql-server xml t-sql
1个回答
0
投票

您可以为此使用递归 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;
© www.soinside.com 2019 - 2024. All rights reserved.