Utilizzare un'istruzione LIKE sul tipo di dati XML di SQL Server


89

Se hai un campo varchar puoi facilmente SELECT * FROM TABLE WHERE ColumnA LIKE '%Test%'vedere se quella colonna contiene una certa stringa.

Come si fa per il tipo XML?

Ho quanto segue che restituisce solo le righe che hanno un nodo "Testo" ma devo cercare all'interno di quel nodo

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

Risposte:


70

Dovresti essere in grado di farlo abbastanza facilmente:

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

Il .valuemetodo fornisce il valore effettivo e puoi definirlo da restituire come VARCHAR (), che puoi quindi controllare con un'istruzione LIKE.

Intendiamoci, non sarà molto veloce. Quindi, se hai determinati campi nel tuo XML che devi ispezionare molto, potresti:

  • crea una funzione memorizzata che ottiene l'XML e restituisce il valore che stai cercando come VARCHAR ()
  • definisci un nuovo campo calcolato sulla tua tabella che chiama questa funzione e rendila una colonna PERSISTED

Con questo, fondamentalmente "estrai" una certa parte dell'XML in un campo calcolato, lo rendi persistente, e poi puoi cercare in modo molto efficiente su di esso (diamine: puoi persino INDICE quel campo!).

Marc


1
Fondamentalmente sto implementando una funzione di ricerca, quindi voglio cercare nella colonna XML solo sui nodi "Testo" e quindi restituire una sottostringa per indicare che la ricerca ha trovato una corrispondenza. Ad esempio, cerca "ciao là" invece di restituire l'intera colonna xml, restituirei semplicemente una sottostringa come "il tizio ha detto ciao e portato ..."
Jon

1
Battimi su di esso di 5 secondi. Un'altra possibilità è considerare l'utilizzo della ricerca di testo libero, se i tuoi dati sono suscettibili ...
RickNZ

10
per cercare l'intero file: WHERE xmlField.value ('.', 'varchar (max)') LIKE '% FOO%'
jhilden

fai attenzione ai fastidiosi spazi dei nomi Xml se ricevi NULL indietro
Simon_Weaver

89

Un'altra opzione è lanciare l'XML come nvarchar, quindi cercare la stringa data come se l'XML fosse un campo nvarchar.

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

Adoro questa soluzione perché è pulita, facile da ricordare, difficile da incasinare e può essere utilizzata come parte di una clausola where.

EDIT: come dice Cliff, potresti usare:

... nvarchar se sono presenti caratteri che non vengono convertiti in varchar


3
Idem su questo, o nvarchar se ci sono caratteri che non si convertono in varchar SELEZIONA * DA TABELLA WHERE CAST (Colonna come nvarchar (max)) COME '% TEST%'
Cliff Coulter

[Err] 42000 - [SQL Server] Conversione di uno o più caratteri da XML a confronto di destinazione impossibile
digz6666

[Err] 22018 - [SQL Server] La conversione esplicita dal tipo di dati xml al testo non è consentita.
digz6666

Sembra che tu stia facendo qualcosa di sbagliato @ digz6666
Squazz

1
@Squazz Hai votato l'ultima volta su questa risposta ieri. Il tuo voto è ora bloccato a meno che questa risposta non venga modificata. :)
digz6666

10

Un'altra opzione è cercare l'XML come stringa convertendolo in una stringa e quindi utilizzando LIKE. Tuttavia, poiché una colonna calcolata non può far parte di una clausola WHERE, è necessario racchiuderla in un altro SELECT come questo:

SELECT * FROM
    (SELECT *, CONVERT(varchar(MAX), [COLUMNA]) as [XMLDataString] FROM TABLE) x
WHERE [XMLDataString] like '%Test%'

Tieni presente che questo potrebbe aggirare qualsiasi indice XML selettivo che potresti avere in atto e avere un impatto sulle prestazioni.
Rudy Hinojosa

0

Questo è quello che userò in base alla risposta di marc_s:

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

Restituisce una sottostringa nella ricerca in cui esistono i criteri di ricerca


Ho bisogno di parametri per prevenire l'iniezione in qualche modo?
Jon

2
ATTENZIONE: quelle funzioni XML fanno distinzione tra maiuscole e minuscole - DATA.VALUE non funzionerà! Deve essere .value (...)
marc_s
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.