¿Cómo puedo consultar un valor en la columna XML de SQL Server?

127

Tengo el siguiente XML almacenado en una columna XML (llamada Roles) en una base de datos de SQL Server.

<root>
   <role>Alpha</role>
   <role>Beta</role>
   <role>Gamma</role>
</root>

Me gustaría enumerar todas las filas que tienen un rol específico en ellas. Este rol pasó por parámetro.

Pequeño restaurante
fuente

Respuestas:

198
select
  Roles
from
  MyTable
where
  Roles.value('(/root/role)[1]', 'varchar(max)') like 'StringToSearchFor'

Estas páginas le mostrarán más sobre cómo consultar XML en T-SQL:

Consultar campos XML usando t-sql

Acoplar datos XML en SQL Server

EDITAR

Después de jugar un poco más, terminé con esta increíble consulta que usa CROSS APPLY . Este buscará en cada fila (rol) el valor que pones en tu expresión similar ...

Dada esta estructura de tabla:

create table MyTable (Roles XML)

insert into MyTable values
('<root>
   <role>Alpha</role>
   <role>Gamma</role>
   <role>Beta</role>
</root>')

Podemos consultarlo así:

select * from 

(select 
       pref.value('(text())[1]', 'varchar(32)') as RoleName
from 
       MyTable CROSS APPLY

       Roles.nodes('/root/role') AS Roles(pref)
)  as Result

where RoleName like '%ga%'

Puede consultar el Fiddle de SQL aquí: http://sqlfiddle.com/#!18/dc4d2/1/0

Leniel Maccaferri
fuente
55
Responde a todas mis preguntas, ¿qué hace [1]en su respuesta?
Bistro
1
Gran respuesta, voto por esta, pero supongo que la cadena debería ser varchar
AaA
77
@Bistro Preguntar [1]fue una muy buena pregunta. Significa que elige el primer valor de rol del XML y significa que esto solo funcionará para encontrar Alphaen su xml de muestra. No encontrará la fila si la busca Beta.
Mikael Eriksson
1
En mi caso, tuve que consultar nodos con un valor de atributo específico. Esta respuesta fue la que condujo a mi solución. Solo tenía que poner comillas dobles alrededor del valor del atributo.
John N
Si el XML tiene un espacio de nombres, ¿cómo lo consultamos?
FMFF
36
declare @T table(Roles xml)

insert into @T values
('<root>
   <role>Alpha</role>
   <role>Beta</role>
   <role>Gamma</role>
</root>')

declare @Role varchar(10)

set @Role = 'Beta'

select Roles
from @T
where Roles.exist('/root/role/text()[. = sql:variable("@Role")]') = 1

Si desea que la consulta funcione como where col like '%Beta%'puede usarcontains

declare @T table(Roles xml)

insert into @T values
('<root>
   <role>Alpha</role>
   <role>Beta</role>
   <role>Gamma</role>
</root>')

declare @Role varchar(10)

set @Role = 'et'

select Roles
from @T
where Roles.exist('/root/role/text()[contains(., sql:variable("@Role"))]') = 1
Mikael Eriksson
fuente
13

si el nombre de su campo es Roles y el nombre de la tabla es table1, puede usar el siguiente para buscar

DECLARE @Role varchar(50);
SELECT * FROM table1
WHERE Roles.exist ('/root/role = sql:variable("@Role")') = 1
AaA
fuente
esto es bueno, ¿hay alguna forma de buscar usando like? forexample /root/role like ....
Bistro
2
usar en .value('(/root/role)[1]', 'varchar(max)') like '%yourtext%'lugar de existscomo Leniel explicó
AaA
44
¿Has probado esto? Encuentra todo, independientemente de lo que pones @Role.
Mikael Eriksson
6

Se me ocurrió un trabajo simple a continuación que también es fácil de recordar :-)

select * from  
(select cast (xmlCol as varchar(max)) texty
 from myTable (NOLOCK) 
) a 
where texty like '%MySearchText%'
Sagar
fuente
1
Se supone que no debemos buscar mediante la manipulación de cadenas, ya que eso resultaría en búsquedas demasiado lentas
Malcolm Salvador
5

Podrías hacer lo siguiente

declare @role varchar(100) = 'Alpha'
select * from xmltable where convert(varchar(max),xmlfield) like '%<role>'+@role+'</role>%'

Obviamente, esto es un truco y no lo recomendaría para ninguna solución formal. Sin embargo, encuentro esta técnica muy útil cuando hago consultas adhoc en columnas XML en SQL Server Management Studio para SQL Server 2012.

Craig B
fuente
2

Consejo útil Consultar un valor en la columna XML de SQL Server (XML con espacio de nombres)

p.ej

Table [dbo].[Log_XML] contains columns Parametrs (xml),TimeEdit (datetime)

por ejemplo, XML en parámetros:

<ns0:Record xmlns:ns0="http://Integration"> 
<MATERIAL>10</MATERIAL> 
<BATCH>A1</BATCH> 
</ns0:Record>

Por ejemplo, consulta:

select
 Parametrs,TimeEdit
from
 [dbo].[Log_XML]
where
 Parametrs.value('(//*:Record/BATCH)[1]', 'varchar(max)') like '%A1%'
 ORDER BY TimeEdit DESC
romangorbenko.com
fuente
1

Usé la siguiente declaración para recuperar los valores en el XML en la tabla SQL

with xmlnamespaces(default 'http://test.com/2008/06/23/HL.OnlineContract.ValueObjects')
select * from (
select
            OnlineContractID,
            DistributorID,
            SponsorID,
    [RequestXML].value(N'/OnlineContractDS[1]/Properties[1]/Name[1]', 'nvarchar(30)') as [Name]
   ,[RequestXML].value(N'/OnlineContractDS[1]/Properties[1]/Value[1]', 'nvarchar(30)') as [Value]
     ,[RequestXML].value(N'/OnlineContractDS[1]/Locale[1]', 'nvarchar(30)') as [Locale]
from [OnlineContract]) as olc
where olc.Name like '%EMAIL%' and olc.Value like '%EMAIL%' and olc.Locale='UK EN'
ranjit
fuente
¿Qué pasa si XML no contiene la definición del espacio de nombres?
Muflix
0

Puede consultar la etiqueta completa o solo el valor específico. Aquí uso un comodín para los espacios de nombres xml.

declare @myDoc xml
set @myDoc = 
'<Root xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://stackoverflow.com">
    <Child>my value</Child>
 </Root>'

select @myDoc.query('/*:Root/*:Child') -- whole tag
select @myDoc.value('(/*:Root/*:Child)[1]', 'varchar(255)') -- only value
FrankyHollywood
fuente