SQL 服务器网站 XML 到 table

SQL Server web XML to table

我想从网络中获取数据 XML URL 并将结果转换为具有值的标准 table。

我有以下代码:

IF OBJECT_ID('tempdb..#xml') IS NOT NULL 
      DROP TABLE #xml

CREATE TABLE #xml (yourXML XML)
GO

DECLARE @URL NVARCHAR(max) 

SELECT @URL = 'https://www.boi.org.il/currency.xml' 

DECLARE @Response varchar(8000)
DECLARE @XML xml
DECLARE @Obj int 
DECLARE @Result int 
DECLARE @HTTPStatus int 
DECLARE @ErrorMsg varchar(MAX)

EXEC @Result = sp_OACreate 'MSXML2.XMLHttp', @Obj OUT 

EXEC @Result = sp_OAMethod @Obj, 'open', NULL, 'GET', @URL, false
EXEC @Result = sp_OAMethod @Obj, 'setRequestHeader', NULL, 'Content-Type', 'application/x-www-form-urlencoded'
EXEC @Result = sp_OAMethod @Obj, send, NULL, ''
EXEC @Result = sp_OAGetProperty @Obj, 'status', @HTTPStatus OUT 

INSERT #xml ( yourXML )
EXEC @Result = sp_OAGetProperty @Obj, 'responseXML.xml'--, @Response OUT 


SELECT x.*, y.c.query('.')
FROM #xml x
    CROSS APPLY x.yourXML.nodes('/CURRENCIES/CURRENCY') y(c)

现在这段代码的结果是一个 XML“超链接”查询,我想将它作为标准值查询结果,最终我可以使用这些数据。

查询结果结构列应该是:

LAST_UPDATE | NAME | UNIT | CURRENCYCODE | RATE

我强烈建议你不要从 T-SQL 发出网络请求,这不是它的地方。在 Powershell、C# 或 Java 中执行,在 SQL 服务器外部。

SQL 服务器未设计为有额外的线程等待网络请求。在 sp_oa 函数中调试错误也非常困难。
此外,这些功能存在诸多问题,尤其是多年未更新,疑似存在安全问题。似乎对于要保持安全的数据库服务器来说,最糟糕的事情之一就是让它“上网冲浪”。

另请参阅以下内容以获取更多信息:
How to avoid sp_OACreate limits?
sp_OACreate error on SQL Server 2005
When did sp_OACreate et. al. become deprecated?


加载后SQL中的XML仍然可以解析,方法如下:

使用/text()获取节点的内部文本,比只使用节点名更快。确保数据类型符合您的要求。

SELECT
    x.yourXML.value('(/CURRENCIES/LAST_UPDATE/text())[1]','date') Last_Update,
    n.c.value('(/NAME/text())[1]','nvarchar(50)') Name,
    n.c.value('(/UNIT/text())[1]','decimal(18,10)') Unit,
    n.c.value('(/CURRENCYCODE/text())[1]','nchar(3)') CurrencyCode,
    n.c.value('(/RATE/text())[1]','decimal(18,10)') Rate
FROM #xml x
    CROSS APPLY x.yourXML.nodes('/CURRENCIES/CURRENCY') n(c);

你的结果:

EXEC @Result = sp_OAMethod @Obj, 'close';--, NULL, 'GET', @URL, false

SELECT d.value('(./LAST_UPDATE)[1]', 'DATETIME') AS LAST_UPDATE,
       c.value('(./NAME)[1]', 'NVARCHAR(64)') AS NAME,
       c.value('(./UNIT)[1]', 'SMALLINT') AS UNIT,
       c.value('(./CURRENCYCODE )[1]', 'NVARCHAR(64)') AS CURRENCYCODE, 
       c.value('(./RATE)[1]', 'DECIMAL(38,2)') AS RATE
FROM #xml x
    CROSS APPLY x.yourXML.nodes('/CURRENCIES/CURRENCY') y(c)
    CROSS APPLY x.yourXML.nodes('/CURRENCIES') z(d);

不要忘记关闭您的 OA 对象。 并最终禁用使用它的可能性:

EXEC sp_configure 'Ole Automation Procedures', 0;
RECONFIGURE;

当然,我更喜欢这个带有 table 变量的版本:

DECLARE @vxml TABLE (an_xml XML);
DECLARE @URL NVARCHAR(max) = 'https://www.boi.org.il/currency.xml',
        @Obj int, 
        @Result int,
        @HTTPStatus int; 

EXEC sp_configure 'Ole Automation Procedures', 1;
RECONFIGURE;

EXEC @Result = sp_OACreate 'MSXML2.XMLHttp', @Obj OUT; 
EXEC @Result = sp_OAMethod @Obj, 'open', NULL, 'GET', @URL, false;
EXEC @Result = sp_OAMethod @Obj, 'setRequestHeader', NULL, 'Content-Type', 'application/x-www-form-urlencoded';
EXEC @Result = sp_OAMethod @Obj, send, NULL, '';
EXEC @Result = sp_OAGetProperty @Obj, 'status', @HTTPStatus OUT; 

INSERT @vxml ( an_xml )
EXEC @Result = sp_OAGetProperty @Obj, 'responseXML.xml';

EXEC @Result = sp_OAMethod @Obj, 'close';

EXEC sp_configure 'Ole Automation Procedures',0;
RECONFIGURE;

SELECT d.value('(./LAST_UPDATE)[1]', 'DATETIME') AS LAST_UPDATE,
       c.value('(./NAME)[1]', 'NVARCHAR(64)') AS NAME,
       c.value('(./UNIT)[1]', 'SMALLINT') AS UNIT,
       c.value('(./CURRENCYCODE )[1]', 'NVARCHAR(64)') AS CURRENCYCODE, 
       c.value('(./RATE)[1]', 'DECIMAL(38,2)') AS RATE
FROM @vxml AS x
    CROSS APPLY x.an_xml.nodes('/CURRENCIES/CURRENCY') y(c)
    CROSS APPLY x.an_xml.nodes('/CURRENCIES') z(d);