Reputation: 790
Given the following snippet, I need a query that returns the text of the 'a' nodes and the text of the 1st following 'b' node.
declare @X xml = '
<root>
<a>cat</a>
<b>Cats don''t like milk</b>
<a>dog</a>
<c>not this</c>
<b>Dogs like everything</b>
<b>and not this</b>
</root>'
e.g. -
Animal | Preference
-------|---------------------
cat | Cats don't like milk
dog | Dogs like everything
Using the nodes method like this-
SELECT
c.x.value(N'text()[1]','varchar(max)') as animal
--,??? as preference
FROM
@X.nodes('root/a') c(x)
I don't think adjacent nodes are available from the 'x' object, because it's a table variable by that point. Clearly the XML is suboptimal, since the b nodes should more accurately be children of the a nodes, but that's the shape of the data as it comes to me. SQL Server is limited to a subset of XQuery, which makes this more difficult.
Upvotes: 2
Views: 1138
Reputation: 28789
With due thanks to this answer, which isn't quite what we need but which did point me in the direction of the >>
operator.
The lack of proper axes makes this more involved than necessary:
SELECT
c.a.value('text()[1]','varchar(max)') as animal,
c.a.query('
let $a := .
return (../b[. >> $a][1])/text()'
).value('text()[1]','varchar(max)') as preference
FROM
@x.nodes('root/a') c(a)
We have to assign the a
node to a variable in order to be able to query for the first b
node that follows it.
Upvotes: 1