如何从SQL Server中的多个XML文件读取数据?

时间:2019-01-14 14:38:43

标签: sql sql-server xml tsql

背景:

我想从多个XML文件(存储在数据库中)中获取数据,并将其提取到一个结果集中。具有单个XML文件的基本工作解决方案看起来与此类似:

DECLARE @xml xml
SET @xml = 
(SELECT TOP 1 convert(varchar(max), convert(varbinary(max), [XML_FILE]))
  FROM [SOME_TABLE])
SELECT
    b.value('(./SomeNode/text())[1]','nvarchar(100)')) as [Some_Text],
    b.value('(./SomeOtherNode/@VAL)[1]','int')) as [Some_Val]
FROM @xml.nodes('Example/File') as a(b)

很明显,这不适用于返回许多行(许多XML文件)的SELECT。可以使用游标来实现次优解决方案(遍历集合->将数据推送到临时表中->从temporary_table中进行SELECT(*)),但是,我认为这不是必需的,并且可以实现更直接的解决方案。

问题:

如何在不使用光标的情况下,将通过SELECT查询获得的多个XML文件中的数据提取到单个结果集中?

FILE_NAME ||   Value 1   ||   Value 2  || ...
----------------------------------------------
XML_FILE_1 || Node1Value || Node2Value || ...
XML_FILE_2 || Node1Value || Node2Value || ...

2 个答案:

答案 0 :(得分:1)

确定不需要CURSOR方法,这完全是错误的...

一般方法应该是这样的:

SELECT
    b.value('(./SomeNode/text())[1]','nvarchar(100)') as [Some_Text],
    b.value('(./SomeOtherNode/@VAL)[1]','int') as [Some_Val]
FROM [SOME_TABLE]
CROSS APPLY [XML_FILE].nodes('Example/File') as a(b);

但是还有很多问题:

  • 谈论 xml文件有点令人困惑……我希望正确理解这一点,因为所有这些XML都位于表的列中。
  • 如果第一个是正确的:所有这些XML是否都具有相同的结构?如果没有,您将需要某种过滤。
  • 表列中的XML是否已经是本机XML类型?您的示例广泛使用CONVERT ...您将需要本机XML才能使用.nodes()
  • 如果没有本机XML:您是否必须处理无效/不可广播的数据?
  • 是否有没有数据的行,但是您仍然想查看它们?在这种情况下,您可以尝试使用OUTER APPLY代替CROSS APPLY

为演示运行的独立样机:

DECLARE @mockup TABLE(ID INT IDENTITY, [XML_FILE] XML);
INSERT INTO @mockup VALUES('<Example><File><SomeNode>blah</SomeNode><SomeOtherNode VAL="1"/></File></Example>')
                         ,('<Example><File><SomeNode>blub</SomeNode><SomeOtherNode VAL="2"/></File></Example>')

SELECT
    ID,
    b.value('(SomeNode/text())[1]','nvarchar(100)') as [Some_Text],
    b.value('(SomeOtherNode/@VAL)[1]','int') as [Some_Val]
FROM @mockup
CROSS APPLY [XML_FILE].nodes('Example/File') as a(b)

答案 1 :(得分:1)

由于@Shnugo的回答,我找到了解决方案。

如果xml-container列的类型与XML MS-SQL专用的类型不同,则应执行两次CROSS APPLY。下面的示例:

DECLARE @mockup TABLE(ID INT IDENTITY, [XML_DATA] VARBINARY(MAX));
INSERT INTO @mockup VALUES('<Example><File><SomeNode>blah</SomeNode><SomeOtherNode VAL="1"/></File></Example>')
                         ,('<Example><File><SomeNode>blub</SomeNode><SomeOtherNode VAL="2"/></File></Example>')

SELECT
    ID,
    b.value('(SomeNode/text())[1]','nvarchar(100)') as [Some_Text],
    b.value('(SomeOtherNode/@VAL)[1]','int') as [Some_Val]
FROM @mockup
CROSS APPLY (SELECT CAST(convert(varbinary(max), [XML_DATA]) as XML)) as RAW_XML(xml_field)
CROSS APPLY RAW_XML.xml_field.nodes('Example/File') as a(b)