Как сравнение в SQL Server XML datatype


У меня есть таблица БД со столбцом типа данных XML. Столбец содержит следующие значения:

<NameValuePairCollection>
  <NameValuePair Name="Foo" Value="One" />
  <NameValuePair Name="Bar" Value="Two" />
  <NameValuePair Name="Baz" Value="Three" />
</NameValuePairCollection>

Я пытаюсь запросить все строки, в которых столбец XML datatype имеет значение "One" для "Foo". У меня возникли проблемы с созданием соответствующего XQuery для фильтрации результатов.

Я нашел пару связанных таким образом вопросов, которые помогли мне в моей попытке, но я все еще не могу заставить его работать.

Как я могу запросить значение в столбце SQL Server XML
используйте подобное утверждение на SQL Server XML Datatype

Вот SQL, который у меня есть до сих пор:

select * 
from MyTable 
where [XmlDataColumn].value('((/NameValuePairCollection/NameValuePair)[@Name="Foo"])[@Value]', 'varchar(max)') = 'One'
order by ID desc 

Вот ошибка, которую я получаю прямо сейчас:

XQuery [MyTable.XmlDataColumn.value()]: Cannot atomize/apply data() on expression that contains type 'NameValuePair' within inferred type 'element(NameValuePair,#anonymous) *'

Обновление (В ответ на предложение @LeoWörteler по)

Основываясь на вашем ответе, я изменил свой SQL на следующий:

select * 
from MyTable with(nolock) 
where [XmlDataColumn].value('/NameValuePairCollection/NameValuePair[@Name="Subject"]/@Value', 'varchar(max)') = 'One'
order by ID desc 
Но это все равно не работает. Я получаю следующую ошибку:
XQuery [MyTable.XmlDataColumn.value()]: 'value()' requires a singleton (or empty sequence), found operand of type 'xs:string *'
2 4

2 ответа:

Если вы хотите выбрать значение атрибута Value вместо целого элемента NameValuePair с выражением XPath в [XmlDataColumn].value(...), это должно работать:

/NameValuePairCollection/NameValuePair[@Name="Foo"]/@Value

Ваше выражение проверяет только, имеет ли NameValuePair атрибут Value.

Если существует несколько элементов с правильным именем и вы хотите проверить, имеет ли какой-либо из них значение "One", Вы можете использовать exist(...) метод:

where [XmlDataColumn].exist(
  '/NameValuePairCollection/NameValuePair[@Name="Subject" and @Value="One"]') = 1

Другой вариант-привести XML как varchar, а затем искать заданную строку, как если бы XML был полем varchar.

SELECT * 
FROM Table
WHERE CAST(Column as nvarchar(max)) LIKE '%Name="Foo" Value="One"%'

Мне нравится это решение, поскольку оно чистое, легко запоминается, трудно запутывается и может использоваться как часть предложения where.

Это не так динамично и полно, как ответ, предоставленный Лео, но в зависимости от обстоятельств это может быть "быстрый и грязный" способ получить необходимые данные.