3

SQL Server2008データベースに次の簡略化された例のような値の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

ただし、@ queryText=''または@queryText=NULLが機能すると予想されるケース2の場合、どちらも一致しません。

回避策として、次を使用できます。

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

これは機能しますが、何かが足りないように感じ、汚い回避策を使用して、.exist()ではなく.value()で存在をテストします...使用できる[そしてすべきか]同様の式はありますか? .exist()で、特定のテキストまたは空のノードのいずれかに一致しますか?読みやすさを超えて気にする理由はありますか?誰かが私が見逃した露骨に明白なことを指摘するとき、私は私の差し迫ったfacepalmを楽しみにしています。:)

4

1 に答える 1

8

空の要素を呼び出すtext()と、空の文字列ではなくNULLになります。したがって、どちらの場合も、NULLに合格する@queryText = ''か、@queryText = 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
于 2012-06-22T08:30:09.240 に答える