In SQL server, I have a table with an XML column, and from each XML, I have nodes under a parent node and I want to select each value in the node into a separate row for each XML.
How do I accomplish that?
Below is a sample of how the table looks:
Name | Message
John | <User><Data><Valuelist><Value>123</Value><Value>456</Value><Value>789</Value><Value>654</Value></ValueList></Data></User>
Jack | <User><Data><ValueList><Value>555</Value><Value>455</Value></ValueList></Data></User>
Jane | <User><Data><Valuelist><Value>576</Value><Value>854</Value><Value>933</Value></ValueList></Data></User>
Below is a sample XML from the Message column I'm trying to query from, for better clarity:
<User>
<Data>
<ValueList>
<Value>123</Value>
<Value>456</Value>
<Value>789</Value>
<Value>654</Value>
</ValueList>
</Data>
</User>
And below is what I expect to see in the result:
Name | Values
John | 123
John | 456
John | 789
John | 654
Jack | 555
Jack | 455
Jane | 576
Jane | 854
Jane | 933
I have been attempting to use the below query:
select t.Name, x.y.value('(Value)', 'nvarchar(10)') [Values]
from TABLE t
cross apply t.Message.nodes('//ValueList') as x(y)
But it gives me the below error:
'value()' requires a singleton (or empty sequence), found operand of type 'xdt:untypedAtomic *'
I'm only able to select one of the values using:
select t.Name, x.y.value('(Value[1])', 'nvarchar(10)') [Values]
from TABLE t
cross apply t.Message.nodes('//ValueList') as x(y)
I have been googling around but couldn't quite find something for what I'm trying to do.
What should I do here?
My SQL server version is 2016 SP2.
Thanks in advance!
CodePudding user response:
Please try the following solution.
SQL
-- DDL and sample data population, start
DECLARE @tbl table (ID INT IDENTITY PRIMARY KEY, Name VARCHAR(20), Message XML);
INSERT INTO @tbl (Name, Message) VALUES
('John', N'<User><Data><ValueList><Value>123</Value><Value>456</Value><Value>789</Value><Value>654</Value></ValueList></Data></User>'),
('Jack', N'<User><Data><ValueList><Value>555</Value><Value>455</Value></ValueList></Data></User>'),
('Jane', N'<User><Data><ValueList><Value>576</Value><Value>854</Value><Value>933</Value></ValueList></Data></User>');
-- DDL and sample data population, end
SELECT t.ID, t.Name
, c.value('(./text())[1]', 'nvarchar(10)') AS [Values]
FROM @tbl AS t
CROSS APPLY Message.nodes('/User/Data/ValueList/Value') as t1(c);
Output
---- ------ --------
| ID | Name | Values |
---- ------ --------
| 1 | John | 123 |
| 1 | John | 456 |
| 1 | John | 789 |
| 1 | John | 654 |
| 2 | Jack | 555 |
| 2 | Jack | 455 |
| 3 | Jane | 576 |
| 3 | Jane | 854 |
| 3 | Jane | 933 |
---- ------ --------