2012-06-21 3 views
3

у меня есть столбец XML в базе данных SQL Server 2008 со значениями, как в следующих упрощенных примерах:Test для конкретного значения узла в столбце XML, включая потенциально пустые узлы

Case 1

<root> 
    <child>sometimes text here</child> 
    <otherstuff ..... /> 
</root> 

Случай 2

<root> 
    <child/> 
    <otherstuff ..... /> 
</root> 

Учитывая значение строки, я хотел бы иметь возможность выбирать те строки, которые имеют определенное значение в узле «ребенок», в том числе в случае выбора 2.

Так, например, если у меня локальную переменную:

declare @queryText nvarchar(MAX) 
select @queryText = 'sometimes text here' 

можно выбрать строку что соответствует случаю 1 по:

select * from [my_table] 
where [my_xml_column].exist('/root/child[text()=sql:variable("@queryText")]') = 1 

Однако для случая 2, где я ожидал бы @queryText = '' или @queryText = NULL для работы, ни спички.

В качестве временного решения можно использовать:

select * from [my_table] 
where [my_xml_column].value('(/root/child)[1], 'nvarchar(MAX)') = @queryText 

Это работает, но это оставляет меня чувство, что я что-то отсутствует и используя грязный обходной путь для проверки существования с .value(), а не .exist() ... Есть ли подобное выражение, которое я могу [и должен?] Использовать в .exist() для соответствия либо конкретному тексту, либо пустому узлу? Есть ли какая-то причина для ухода за читабельностью? Я с нетерпением жду своего надвигающегося лицевого шара, когда кто-то указывает на все очевидные вещи, которые я пропустил. :)

ответ

8

Вызов text() на пустой элемент приводит к тому, что NULL не является пустой строкой. Итак, в обоих случаях передача @queryText = '' или @queryText = NULL никогда не будет равна NULL. Помните, что ничто не равно NULL, даже NULL.

См. Ниже пример, который иллюстрирует, как использовать exist для заселенных или пустых поисков.

declare @my_table table (i int, my_xml_column xml) 
insert into @my_table 
    select 1, '<root><child>sometimes text here</child><otherstuff /></root>' union all 
    select 2, '<root><child/><otherstuff/></root>' 

declare @queryText varchar(100) = ''; 

select *, 
     [using_text()]=[my_xml_column].value('(/root/child/text())[1]', 'varchar(max)'), 
     [using_path]=[my_xml_column].value('(/root/child)[1]', 'varchar(max)') 
from @my_table 

select * 
from @my_table 
where [my_xml_column].exist('/root/child[.= sql:variable("@queryText")]') = 1 
+0

Cue the facepalm! :) Я мог бы поклясться, что попробовал эту форму [. = Sql: variable], но, думаю, нет. Работает как шарм - спасибо! –

+0

Как насчет чего-то вроде этого: http://stackoverflow.com/questions/33130499/how-to-replace-text-if-it-exists-otherwise-add-text-to-a-xml-node-using-using- SQL – Si8