Como posso consultar um valor na coluna XML do SQL Server

127

Eu tenho o seguinte XML armazenado em uma coluna XML (chamada Roles) em um banco de dados do SQL Server.

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

Eu gostaria de listar todas as linhas que têm uma função específica nelas. Esta função foi passada pelo parâmetro

Bistro
fonte

Respostas:

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

Estas páginas mostrarão mais sobre como consultar XML no T-SQL:

Consultando campos XML usando t-sql

Achatando dados XML no SQL Server

EDITAR

Depois de brincar um pouco mais, acabei com essa consulta incrível que usa o CROSS APPLY . Este pesquisará em cada linha (função) o valor que você coloca na sua expressão similar ...

Dada esta estrutura de tabela:

create table MyTable (Roles XML)

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

Podemos consultá-lo assim:

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%'

Você pode verificar o SQL Fiddle aqui: http://sqlfiddle.com/#!18/dc4d2/1/0

Leniel Maccaferri
fonte
5
Responde a todas as minhas perguntas, o que [1]faz na sua resposta?
Bistro
1
Grande resposta, eu voto para esta, mas cadeia deve ser varchar eu acho
AaA
7
@ Bistro Perguntar [1]foi uma pergunta muito boa. Isso significa que você escolhe o primeiro valor da função no XML e isso significa que isso funcionará apenas para encontrar Alphaem seu xml de amostra. Não encontrará a linha se você procurar Beta.
Mikael Eriksson
1
No meu caso, tive que consultar nós com valor de atributo específico. Esta resposta foi a liderança para a minha solução. Eu apenas tive que colocar aspas duplas em torno do valor do atributo.
John N
Se o XML tiver um espaço para nome, como o 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

Se você deseja que a consulta funcione, where col like '%Beta%'você pode 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
fonte
13

se o nome do seu campo for Funções e o nome da tabela for table1, você poderá usar o seguinte para pesquisar

DECLARE @Role varchar(50);
SELECT * FROM table1
WHERE Roles.exist ('/root/role = sql:variable("@Role")') = 1
AaA
fonte
isso é bom, existe alguma maneira de pesquisar usando like? forexample /root/role like ....
Bistro
2
usar .value('(/root/role)[1]', 'varchar(max)') like '%yourtext%', em vez de existscomo explicado Leniel
AaA
4
Você já tentou isso? Ele encontra tudo, independentemente do que você coloca @Role.
Mikael Eriksson
6

Eu vim com um trabalho simples por baixo, que também é fácil de lembrar :-)

select * from  
(select cast (xmlCol as varchar(max)) texty
 from myTable (NOLOCK) 
) a 
where texty like '%MySearchText%'
Sagar
fonte
1
Não devemos procurar através de manipulação de string, como que resultaria em vias pesquisas muito lento
Malcolm Salvador
5

Você pode fazer o seguinte

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

Obviamente, isso é um pouco complicado e eu não o recomendaria para nenhuma solução formal. No entanto, acho essa técnica muito útil ao fazer consultas adhoc em colunas XML no SQL Server Management Studio para SQL Server 2012.

Craig B
fonte
2

Dica útil. Consultar um valor na coluna XML do SQL Server (XML com espaço para nome)

por exemplo

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

por exemplo, XML nos parâmetros:

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

por exemplo, consulta:

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

Eu usei a instrução abaixo para recuperar os valores no XML na tabela 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
fonte
E se o XML não contiver a definição de Namespace?
Muflix 12/02
0

Você pode consultar a tag inteira ou apenas o valor específico. Aqui eu uso um curinga para os namespaces 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
fonte