There are multiple ways to achieve this.
Filtering key with predicate on xquery expression
Use an xquery expression with a predicate to filter to <p>
nodes that contain a <k>
child node with the desired string literal (i.e. "Attribute Name 2") using the value() function:
SELECT m.xml.value('(/p[k/text()="Attribute Name 2"]/v/text())[1]',N'varchar(max)')
from m
See it demonstrated in this sqlfiddle.
And if there is a possibility of unicode characters in the data, prefix the xquery string with N
and select the value as nvarchar(max)
:
SELECT m.xml.value(N'(/p[k/text()="Attribute Name 2"]/v/text())[1]',N'nvarchar(max)')
from m
Select key and value as fields and apply WHERE condition
Borrowing from the second query in this answer, CROSS APPLY can be used in a sub-query with .nodes() to select the text of the <k>
and <v>
nodes as fields using value().
Then in the outer-query, a WHERE condition can be added to restrict <p>
nodes to only those with a <k>
with text Attribute Name 2.
select [key], value
from (
select x.value('(k/text())[1]','varchar(max)') as [key],
x.value('(v/text())[1]','varchar(max)') as value
FROM m
CROSS APPLY xml.nodes('//p') as p(x)
) as Result
where [key] = 'Attribute Name 2'
See a demonstration of this in this SQL fiddle.
This could be simplified by removing the sub-query and just selecting the text from the <v>
node where the text of the <k>
node matches the search string:
SELECT x.value('(v/text())[1]','varchar(max)') as value
FROM m
CROSS APPLY xml.nodes('//p') as p(x)
WHERE x.value('(k/text())[1]','varchar(max)') = 'Attribute Name 2'
See this demonstrated in this SQL fiddle.