我在SQL Server 2008数据库中有一个XML列,其值类似于以下简化示例:
案例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()中使用以匹配特定文本或空节点?有没有理由关注可读性?当有人指出我错过的任何明显的东西时,我期待着即将到来的脸谱。 :)
答案 0 :(得分: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