Reputation: 433
I want to obtain data from multiple XML files (stored in database) and fetch them into one result set. The basic working solution, with single XML file looks similar to this one :
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)
Obviously this won't work with SELECT that returns many rows (many XML files). Sub-optimal solution could be achieved using cursor (iterating over collection -> pushing data into temporary table -> SELECT (*) FROM temporary_table) however, I believe thats not necessary and more straightforward solution can be achieved.
How to fetch data from multiple XML files, obtained via SELECT query, into a single result-set, without using cursor?
FILE_NAME || Value 1 || Value 2 || ...
----------------------------------------------
XML_FILE_1 || Node1Value || Node2Value || ...
XML_FILE_2 || Node1Value || Node2Value || ...
Upvotes: 2
Views: 2518
Reputation: 433
I've found solution thanks to @Shnugo answer.
If the type of xml-container column is different then XML MS-SQL dedicated one, then double CROSS APPLY should be performed. Example below :
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)
Upvotes: 3
Reputation: 67311
For sure the CURSOR
approach is not needed and would be wrong entirely...
The general approach should be something like this:
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);
But there are questions open:
CONVERT
extensivly... You will need a native XML in order to use .nodes()
OUTER APPLY
instead of CROSS APPLY
.For demonstration a running stand-alone mockup:
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)
Upvotes: 2