Utilice una declaración LIKE en el tipo de datos XML de SQL Server


87

Si tiene un campo varchar, puede hacerlo fácilmente SELECT * FROM TABLE WHERE ColumnA LIKE '%Test%'para ver si esa columna contiene una determinada cadena.

¿Cómo se hace eso para XML Type?

Tengo lo siguiente que devuelve solo filas que tienen un nodo 'Texto' pero necesito buscar dentro de ese nodo

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

Respuestas:


70

Debería poder hacer esto con bastante facilidad:

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

El .valuemétodo le da el valor real y puede definir que se devuelva como VARCHAR (), que luego puede verificar con una declaración LIKE.

Eso sí, esto no va a ser demasiado rápido. Entonces, si tiene ciertos campos en su XML que necesita inspeccionar mucho, podría:

  • cree una función almacenada que obtenga el XML y devuelva el valor que está buscando como VARCHAR ()
  • defina un nuevo campo calculado en su tabla que llame a esta función y conviértalo en una columna PERSISTED

Con esto, básicamente "extraerías" una cierta porción del XML en un campo calculado, harías que persistiera, y luego podrás buscar de manera muy eficiente en él (diablos: ¡incluso puedes INDEX ese campo!).

Bagazo


1
Básicamente, estoy implementando una función de búsqueda, por lo que quiero buscar en la columna XML solo en los nodos 'Texto' y luego devolver una subcadena para indicar que la búsqueda ha encontrado una coincidencia. Por ejemplo, busque 'hola' en lugar de devolver toda la columna xml, solo devolvería una subcadena como 'el tipo dijo hola allí y llevó ...'
Jon

1
Gáname por 5 segundos. Otra posibilidad es considerar el uso de la búsqueda de texto libre, si sus datos son
compatibles

10
para buscar todo el archivo: DONDE xmlField.value ('.', 'varchar (max)') LIKE '% FOO%'
jhilden

tenga cuidado con los molestos espacios de nombres XML si recupera NULL
Simon_Weaver

87

Otra opción más es convertir el XML como nvarchar y luego buscar la cadena dada como si el XML fuera un campo nvarchar.

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

Me encanta esta solución porque es limpia, fácil de recordar, difícil de estropear y se puede utilizar como parte de una cláusula where.

EDITAR: Como lo menciona Cliff, podría usar:

... nvarchar si hay caracteres que no se convierten a varchar


3
Lo mismo ocurre con eso, o nvarchar si hay caracteres que no se convierten a varchar SELECT * FROM Table WHERE CAST (Column as nvarchar (max)) LIKE '% TEST%'
Cliff Coulter

[Err] 42000 - [SQL Server] Conversión de uno o más caracteres de XML a intercalación de destino imposible
digz6666

[Err] 22018 - [SQL Server] No se permite la conversión explícita del tipo de datos xml a texto.
digz6666

Parece que estás haciendo algo mal @ digz6666
Squazz

1
@Squazz Votó por última vez esta respuesta ayer. Su voto ahora está bloqueado a menos que se edite esta respuesta. :)
digz6666

10

Otra opción es buscar el XML como una cadena convirtiéndolo en una cadena y luego usando LIKE. Sin embargo, como una columna calculada no puede ser parte de una cláusula WHERE, debe envolverla en otro SELECT como este:

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

Tenga en cuenta que esto puede eludir cualquier índice xml selectivo que pueda tener y afectar el rendimiento.
Rudy Hinojosa

0

Esto es lo que voy a usar según la respuesta de 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

Devuelve una subcadena en la búsqueda donde existe el criterio de búsqueda


¿Necesito parámetros para evitar la inyección de alguna manera?
Jon

2
TENGA EN CUENTA: esas funciones XML distinguen entre mayúsculas y minúsculas: ¡DATA.VALUE no funcionará! Debe ser .value (...)
marc_s
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.