Testen Sie auf einen bestimmten Knotenwert in einer XML-Spalte mit potenziell leeren Knoten

Ich habe eine XML-Spalte in einer SQL server 2008-database mit Werten wie die folgenden vereinfachten Beispiele:

Fall 1

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

Fall 2

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

Bei einem String-Wert möchte ich in der Lage sein, Zeilen auszuwählen, die einen bestimmten Wert im "Kind" -Knoten haben, einschließlich der Auswahl von Fall 2.

Also zum Beispiel, wenn ich eine lokale Variable habe:

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

Ich kann die Zeile auswählen, die dem Fall 1 entspricht:

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

Allerdings, für Fall 2, wo würde ich erwarten, dass @queryText = '' oder @queryText = NULL zu arbeiten, keine Spiele.

Als Umgehung kann ich:

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

Dies funktioniert, aber es lässt mich das Gefühl, dass ich etwas fehlt und mit einem schmutzigen Workaround zu testing für Existenz mit .value () anstatt .exist () … Gibt es einen ähnlichen Ausdruck kann ich [und sollte?] Verwenden in .exist (), um entweder bestimmten Text oder einen leeren Knoten zu entsprechen? Gibt es einen Grund, über die Lesbarkeit hinaus zu sorgen? Ich freue mich auf meine bevorstehende Facepalm, wenn jemand darauf hinweist, was eklatant offensichtlich, was ich vermisst habe. 🙂

Das Aufrufen von text() auf einem leeren Element führt zu NULL nicht zu einem leeren String. Also, in beiden Fällen passiert @queryText = '' oder @queryText = NULL wird nie gleich NULL. Denken Sie daran, dass nichts gleich NULL ist, nicht einmal NULL.

Siehe unten Beispiel, das veranschaulicht, wie zu verwenden exist für gefülltes oder leeres searchn.

 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