Use uma instrução LIKE no tipo de dados XML do SQL Server


87

Se você tiver um campo varchar, poderá facilmente SELECT * FROM TABLE WHERE ColumnA LIKE '%Test%'verificar se essa coluna contém uma determinada string.

Como você faz isso para o tipo XML?

Eu tenho o seguinte, que retorna apenas as linhas que têm um nó 'Texto', mas preciso pesquisar dentro desse nó

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

Respostas:


70

Você deve ser capaz de fazer isso facilmente:

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

O .valuemétodo fornece o valor real e você pode defini-lo para ser retornado como um VARCHAR (), que você pode verificar com uma instrução LIKE.

Veja bem, isso não vai ser muito rápido. Portanto, se você tiver determinados campos em seu XML que precise inspecionar muito, poderá:

  • crie uma função armazenada que obtém o XML e retorna o valor que você está procurando como um VARCHAR ()
  • definir um novo campo computado em sua tabela que chama esta função, e torná-lo uma coluna PERSISTED

Com isso, você basicamente "extrairia" uma determinada parte do XML em um campo computado, tornaria-o persistente e, então, poderia pesquisar com muita eficiência (diabos: você pode até INDEXAR esse campo!).

Marc


1
Basicamente, estou implementando um recurso de pesquisa, portanto, desejo pesquisar a coluna XML apenas nos nós 'Texto' e, em seguida, retornar uma substring para indicar que a pesquisa encontrou uma correspondência. Por exemplo, pesquise 'oi lá' em vez de retornar a coluna inteira xml. Eu apenas retornaria uma substring como 'o cara disse oi e carregou ...'
Jon

1
Chegue 5 segundos antes de mim. Outra possibilidade é considerar o uso de pesquisa de texto livre, se seus dados estiverem acessíveis ...
RickNZ

10
para pesquisar todo o campo: WHERE xmlField.value ('.', 'varchar (max)') LIKE '% FOO%'
jhilden

cuidado com os incômodos namespaces Xml se você receber NULL de volta
Simon_Weaver

87

Outra opção é converter o XML como nvarchar e, em seguida, pesquisar a string fornecida como se o XML fosse um campo nvarchar.

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

Adoro esta solução porque é limpa, fácil de lembrar, difícil de bagunçar e pode ser usada como parte de uma cláusula where.

EDIT: Como Cliff menciona, você pode usar:

... nvarchar se houver caracteres que não são convertidos em varchar


3
Idem, ou nvarchar se houver caracteres que não são convertidos em varchar SELECT * FROM Table WHERE CAST (coluna como nvarchar (max)) LIKE '% TEST%'
Cliff Coulter

[Err] 42000 - [SQL Server] Conversão de um ou mais caracteres de XML para agrupamento de destino impossível
digz6666

[Err] 22018 - [SQL Server] A conversão explícita do tipo de dados xml em texto não é permitida.
digz6666

Parece que você está fazendo algo errado @ digz6666
Squazz

1
@Squazz Você votou nesta resposta pela última vez ontem. Seu voto agora está bloqueado, a menos que esta resposta seja editada. :)
digz6666

10

Outra opção é pesquisar o XML como string, convertendo-o em string e usando LIKE. No entanto, como uma coluna computada não pode fazer parte de uma cláusula WHERE, você precisa envolvê-la em outro SELECT como este:

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

Esteja ciente de que isso pode ignorar quaisquer índices xml seletivos que você possa ter em vigor e prejudicar o desempenho.
Rudy Hinojosa de

0

Isso é o que vou usar com base na resposta 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

Retorna uma substring na pesquisa onde os critérios de pesquisa existem


Preciso de parâmetros para evitar a injeção de alguma forma?
Jon

2
ATENÇÃO: essas funções XML diferenciam maiúsculas de minúsculas - DATA.VALUE não funcionará! Precisa ser .valor (...)
marc_s
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.