分析数据透视位置的 XML

Parse XML where data is pivoted

提问人:xE99 提问时间:8/30/2023 最后编辑:Dale KxE99 更新时间:8/31/2023 访问量:33

问:

我有以下 XML 数据

<browse result="1">
  <th>
    <td label="Company ID"></td>
    <td label="Company Name"></td>
    <td label="Country"></td>
    <td label="Region"></td>
  </th>
  <tr>
    <td>ABC01</td>
    <td>Company 1</td>
    <td>United States</td>
    <td>North America</td>
  </tr>
  <tr>
    <td>ABC02</td>
    <td>Company 2</td>
    <td>China</td>
    <td>Asia</td>
  </tr>
</browse>

我的最终表格应该是这样的

公司 ID 公司名称 国家 地区
ABC01 公司 1 美国 北美洲
ABC02型 公司 2 中国 亚洲

或其枢轴版本

标签 值1 值2
公司 ID ABC01 ABC02型
公司名称 公司 1 公司 2
国家 美国 中国
地区 北美洲 亚洲

这是我到目前为止尝试过的

declare @xmldata nvarchar(4000) = '<browse result="1">
  <th>
    <td label="Company ID"></td>
    <td label="Company Name"></td>
    <td label="Country"></td>
    <td label="Region"></td>
  </th>
  <tr>
    <td>ABC01</td>
    <td>Company 1</td>
    <td>United States</td>
    <td>North America</td>
  </tr>
  <tr>
    <td>ABC02</td>
    <td>Company 2</td>
    <td>China</td>
    <td>Asia</td>
  </tr>
</browse>'

select
     a.value('@label', 'varchar(max)') as label
    ,b.value('.', 'nvarchar(max)') as value
from (select top (1) CAST(REPLACE(CAST(@xmldata AS NVARCHAR(MAX)),'utf-8','utf-16') AS XML) as xmldata) as s
    outer apply s.xmldata.nodes('/browse/th/td') as l(a)
    outer apply s.xmldata.nodes('/browse/tr/td') as v(b)

但它给了我 32 行,其中大部分是 4 个标签与值的错误重复组合。我应该如何做到这一点?

sql-server xml xml 解析 xquery xquery-sql

评论

0赞 Charlieface 8/30/2023
列/标签名称是固定的还是动态的?他们可以更改订单吗?
0赞 xE99 8/30/2023
你好!它们是固定的。标签中声明的内容在整个文件中是固定的
2赞 Charlieface 8/30/2023
如果它们不是固定的,您可以使用一些 XQuery voodoo 来获取位置,然后在谓词 dbfiddle.uk/-jo-Loni 中引用它
0赞 Thom A 8/30/2023
那真的是一些巫毒魔法,@Charlieface.根据小提琴的名字,我们可以称之为“乔洛尼技术”吗?:)
0赞 Charlieface 8/31/2023
@ThomA 这是一个老把戏,我用过几次,我不记得我从哪里得到的。此外,这是我能找到的最古老的提及,stackoverflow.com/a/9863151/14868997 可能是从那里得到的https://stackoverflow.com/search?q=user%3A14868997+let+return+count+%5Bsql*%5D

答:

3赞 Thom A 8/30/2023 #1

如果我们可以假设这些值处于静态位置,那么你只需要查看节点,然后使用它们的序号位置从中获取每个节点:trtd

DECLARE @xml xml = '<browse result="1">
  <th>
    <td label="Company ID"></td>
    <td label="Company Name"></td>
    <td label="Country"></td>
    <td label="Region"></td>
  </th>
  <tr>
    <td>ABC01</td>
    <td>Company 1</td>
    <td>United States</td>
    <td>North America</td>
  </tr>
  <tr>
    <td>ABC02</td>
    <td>Company 2</td>
    <td>China</td>
    <td>Asia</td>
  </tr>
</browse>';

SELECT b.th.value('(td/text())[1]','varchar(20)') AS CompanyID,
       b.th.value('(td/text())[2]','varchar(20)') AS CompanyName,
       b.th.value('(td/text())[3]','varchar(20)') AS Country,
       b.th.value('(td/text())[4]','varchar(20)') AS Region
FROM @xml.nodes('browse/tr') b(th);

您可能需要调整数据类型,但我非常怀疑这是否合适;如果您使用的 ID 长度超过 8,000 个字符,则有问题。varchar(MAX)

评论

0赞 xE99 8/31/2023
请问如果某些TD节点为空,应该添加什么?例如<td>ABC03</td><td /> <td /> <td>Asia</td>。在这种情况下,“Asia”将直接转到公司名称,而不是停留在区域。
1赞 Thom A 8/31/2023
更改为 、 等 @xE99 。(td[1]/text())[1](td[2]/text())[1]