在 SQL 查询中解析 XML 元素的属性

Parse XML element's attributes in SQL query

需要在某些工具中存储 ECB 汇率,其中存储了 MS SQL 服务器查询,并且无法从 XML 网页获取信息。

这是带有汇率的网络来源 XML https://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml

这些是我的实验:我创建 XML 变量并用 XML 填充(稍后 XML 将在 table 的 nvarchar 列中)

DECLARE @RateXML XML
SELECT @RateXML = '
<?xml version="1.0" encoding="UTF-8"?>
<gesmes:Envelope xmlns:gesmes="http://www.gesmes.org/xml/2002-08-01" xmlns="http://www.ecb.int/vocabulary/2002-08-01/eurofxref">
    <gesmes:subject>Reference rates</gesmes:subject>
    <gesmes:Sender>
        <gesmes:name>European Central Bank</gesmes:name>
    </gesmes:Sender>
    <Cube>
        <Cube time="2022-02-16">
            <Cube currency="USD" rate="1.1372"/>
            <Cube currency="JPY" rate="131.56"/>
            <Cube currency="BGN" rate="1.9558"/>
        </Cube>
    </Cube>
</gesmes:Envelope>';

我试过这些,没有一个有效。

WITH XMLNAMESPACES ('uri' as gesmes)
select a.currency.query('Cube/@currency') as currency from @RateXML.nodes('gesmes:Envelope/Cube/Cube') as a(currency);
--Error: Attribute may not appear outside of an element
    
WITH XMLNAMESPACES ('uri' as gesmes)
select a.currency.value('Cube/@currency', 'varchar(max)') as currency from @RateXML.nodes('gesmes:Envelope/Cube/Cube') as a(currency);
-- 'value()' requires a singleton (or empty sequence), found operand of type 'xdt:untypedAtomic *'
    
WITH XMLNAMESPACES ('uri' as gesmes)
select @RateXML.query('gesmes:Envelope/Cube/Cube/Cube/@currency') as currency;
-- Attribute may not appear outside of an element

有什么不同的简单方法吗?我想 select 一个临时的 table 有 2 列,currenty 和 rate。感谢您的尝试...

这是正确的做法。

两个命名空间都应该注意。正如@RonenAriely 提到的,您需要声明并使用 命名空间。

later XML will be in nvarchar column in a table

最好使用 XML 数据类型的列。

好处:

  • XML数据类型存储比NVARCHAR(MAX)
  • 少很多
  • XML 数据类型具有强大的 XQuery API 来处理 XML 的任何操作 数据。
  • XML 数据类型有特殊的 XML 性能指标。 3种索引。

SQL

DECLARE @RateXML XML =
'<?xml version="1.0" encoding="UTF-8"?>
<gesmes:Envelope xmlns:gesmes="http://www.gesmes.org/xml/2002-08-01" xmlns="http://www.ecb.int/vocabulary/2002-08-01/eurofxref">
    <gesmes:subject>Reference rates</gesmes:subject>
    <gesmes:Sender>
        <gesmes:name>European Central Bank</gesmes:name>
    </gesmes:Sender>
    <Cube>
        <Cube time="2022-02-16">
            <Cube currency="USD" rate="1.1372"/>
            <Cube currency="JPY" rate="131.56"/>
            <Cube currency="BGN" rate="1.9558"/>
        </Cube>
    </Cube>
</gesmes:Envelope>';

;WITH XMLNAMESPACES (DEFAULT 'http://www.ecb.int/vocabulary/2002-08-01/eurofxref'
    , 'http://www.gesmes.org/xml/2002-08-01' AS gesmes)
SELECT c.value('@currency', 'CHAR(3)') AS currency
    , c.value('@rate', 'DECIMAL(10,4)') AS rate
FROM @RateXML.nodes('/gesmes:Envelope/Cube/Cube/Cube') AS t(c);

输出

+----------+----------+
| currency |   rate   |
+----------+----------+
| USD      |   1.1372 |
| JPY      | 131.5600 |
| BGN      |   1.9558 |
+----------+----------+