在 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 |
+----------+----------+
需要在某些工具中存储 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 |
+----------+----------+