Verwenden Sie eine LIKE-Anweisung für den SQL Server-XML-Datentyp

86

Wenn Sie ein Varchar-Feld haben, können Sie leicht feststellen SELECT * FROM TABLE WHERE ColumnA LIKE '%Test%', ob diese Spalte eine bestimmte Zeichenfolge enthält.

Wie machen Sie das für XML Type?

Ich habe das Folgende, das nur Zeilen zurückgibt, die einen 'Text'-Knoten haben, aber ich muss innerhalb dieses Knotens suchen

select * from WebPageContent where data.exist('/PageContent/Text') = 1
Jon
quelle

Antworten:

69

Sie sollten dies ganz einfach tun können:

SELECT * 
FROM WebPageContent 
WHERE data.value('(/PageContent/Text)[1]', 'varchar(100)') LIKE 'XYZ%'

Die .valueMethode gibt Ihnen den tatsächlichen Wert an, und Sie können diesen als VARCHAR () zurückgeben, der Sie dann mit einer LIKE-Anweisung überprüfen können.

Wohlgemerkt, das wird nicht besonders schnell gehen. Wenn Sie also bestimmte Felder in Ihrem XML haben, die Sie häufig überprüfen müssen, können Sie:

  • Erstellen Sie eine gespeicherte Funktion, die das XML abruft und den gesuchten Wert als VARCHAR () zurückgibt.
  • Definieren Sie ein neues berechnetes Feld in Ihrer Tabelle, das diese Funktion aufruft, und machen Sie es zu einer PERSISTED-Spalte

Damit würden Sie im Grunde genommen einen bestimmten Teil des XML in ein berechnetes Feld "extrahieren", es beibehalten und dann sehr effizient danach suchen (zum Teufel: Sie können dieses Feld sogar INDEXIEREN!).

Marc

marc_s
quelle
1
Grundsätzlich implementiere ich eine Suchfunktion, daher möchte ich die XML-Spalte nur auf den 'Text'-Knoten durchsuchen und dann einen Teilstring zurückgeben, um anzuzeigen, dass die Suche eine Übereinstimmung gefunden hat. Wenn Sie beispielsweise nach "Hallo" suchen, anstatt die gesamte XML-Spalte zurückzugeben, würde ich einfach einen Teilstring zurückgeben, z. B. "Der Kerl hat Hallo gesagt und ..."
Jon
1
Schlage mich um 5 Sekunden. Eine andere Möglichkeit ist die Verwendung der
Freitextsuche
9
um die gesamte Datei zu durchsuchen: WHERE xmlField.value ('.', 'varchar (max)') LIKE '% FOO%'
jhilden
Achten
84

Eine weitere Option besteht darin, das XML als nvarchar umzuwandeln und dann nach der angegebenen Zeichenfolge zu suchen, als ob das XML ein nvarchar-Feld wäre.

SELECT * 
FROM Table
WHERE CAST(Column as nvarchar(max)) LIKE '%TEST%'

Ich liebe diese Lösung, da sie sauber, leicht zu merken, schwer durcheinander zu bringen und als Teil einer where-Klausel verwendet werden kann.

EDIT: Wie Cliff es erwähnt, könnten Sie verwenden:

... nvarchar, wenn es Zeichen gibt, die nicht in varchar konvertiert werden

Squazz
quelle
3
Das Gleiche gilt für nvarchar, wenn es Zeichen gibt, die nicht in varchar konvertiert werden. SELECT * FROM Table WHERE CAST (Spalte als nvarchar (max)) LIKE '% TEST%'
Cliff Coulter
[Err] 42000 - [SQL Server] Konvertierung eines oder mehrerer Zeichen von XML in
Zielsortierung
[Err] 22018 - [SQL Server] Eine explizite Konvertierung vom Datentyp xml in Text ist nicht zulässig.
digz6666
Klingt so, als ob Sie etwas falsch machen @ digz6666
Squazz
1
@Squazz Du hast gestern zuletzt über diese Antwort abgestimmt. Ihre Stimme ist jetzt gesperrt, sofern diese Antwort nicht bearbeitet wird. :)
digz6666
10

Eine andere Möglichkeit besteht darin, das XML als Zeichenfolge zu durchsuchen, indem Sie es in eine Zeichenfolge konvertieren und dann LIKE verwenden. Da eine berechnete Spalte jedoch nicht Teil einer WHERE-Klausel sein kann, müssen Sie sie wie folgt in ein anderes SELECT einschließen:

SELECT * FROM
    (SELECT *, CONVERT(varchar(MAX), [COLUMNA]) as [XMLDataString] FROM TABLE) x
WHERE [XMLDataString] like '%Test%'
Carl Onager
quelle
Beachten Sie, dass dies möglicherweise alle ausgewählten XML-Indizes umgeht und die Leistung beeinträchtigt.
Rudy Hinojosa
0

Dies ist, was ich basierend auf der Antwort von marc_s verwenden werde:

SELECT 
SUBSTRING(DATA.value('(/PAGECONTENT/TEXT)[1]', 'VARCHAR(100)'),PATINDEX('%NORTH%',DATA.value('(/PAGECONTENT/TEXT)[1]', 'VARCHAR(100)')) - 20,999)

FROM WEBPAGECONTENT 
WHERE COALESCE(PATINDEX('%NORTH%',DATA.value('(/PAGECONTENT/TEXT)[1]', 'VARCHAR(100)')),0) > 0

Geben Sie eine Teilzeichenfolge für die Suche zurück, in der die Suchkriterien vorhanden sind

Jon
quelle
Benötige ich Parameter, um die Injektion irgendwie zu verhindern?
Jon
2
ACHTUNG: Bei diesen XML-Funktionen wird zwischen Groß- und Kleinschreibung unterschieden - DATA.VALUE funktioniert nicht ! Es muss .value (...) sein
marc_s