Eu tenho uma XML
coluna que contém dados com estrutura semelhante:
<Root>
<Elements>
<Element Code="1" Value="aaa"></Element>
<Element Code="2" Value="bbb"></Element>
<Element Code="3" Value="ccc"></Element>
</Elements>
</Root>
Como posso modificar os dados usando o SQL Server para alterar cada Value
atributo em um elemento?
<Root>
<Elements>
<Element Code="1">
<Value>aaa</Value>
</Element>
<Element Code="2">
<Value>bbb</Value>
</Element>
<Element Code="3">
<Value>ccc</Value>
</Element>
</Elements>
</Root>
Atualizar:
Meu XML se parece mais com isso:
<Root attr1="val1" attr2="val2">
<Elements>
<Element Code="1" Value="aaa" ExtraData="extra" />
<Element Code="2" Value="bbb" ExtraData="extra" />
<Element Code="3" Value="ccc" ExtraData="extra" />
<Element Code="4" Value="" ExtraData="extra" />
<Element Code="5" ExtraData="extra" />
</Elements>
<ExtraData>
<!-- Some XML is here -->
</ExtraData>
</Root>
Eu gostaria apenas de mover o Value
atributo e preservar todos os outros atributos e elementos.
sql-server
xml
xquery
Wojteq
fonte
fonte
<Value>
elementos por cada<Element>
. Caso contrário, mover o atributo para um elemento torna o XML mais inchado e possivelmente menos eficiente.<Value>
elemento ou em vez dele.Respostas:
Você pode destruir o XML e reconstruí-lo novamente usando o XQuery.
Resultado:
Se
Elements
não for o primeiro elemento naRoot
consulta, precisará ser modificado para adicionar todos os elementos antes doElements
primeiro e todos os elementos depois doElements
depois.fonte
Você também pode usar os métodos do tipo de dados XML (por exemplo, modificar ) e alguns XQuery para modificar o xml, por exemplo
Esse método não tende a escalar bem em grandes pedaços de XML, mas pode ser melhor para você do que uma substituição por atacado do XML.
Você também pode adaptar facilmente esse método se seu XML estiver armazenado em uma tabela. Novamente, por experiência, eu não recomendaria executar uma única atualização em uma tabela de um milhão de linhas. Se a sua tabela for grande, considere executar um cursor nela ou, em outro caso, colocar em lotes as atualizações. Aqui está a técnica:
fonte
ATUALIZAR:
Atualizei o código, bem como o XML de entrada e saída na consulta de exemplo abaixo para refletir o requisito mais recente, declarado em um comentário sobre a boa resposta do @ Mikael , que é:
Embora uma única expressão possa corresponder corretamente a essa nova variação, não parece haver uma maneira de omitir o
<Value/>
elemento vazio em uma única passagem, pois a lógica condicional não é permitida na sequência de substituição. Então, eu adaptei isso para ser uma modificação em duas partes: uma passagem para obter os@Value
atributos não vazios e uma passagem para obter os@Value
atributos vazios . Não havia necessidade de lidar com<Element>
a falta do@Value
atributo, pois o desejo é não ter o<Value>
elemento de qualquer maneira.Uma opção é tratar o XML como uma sequência regular e transformá-lo com base em um padrão. Isso é feito facilmente usando expressões regulares (especificamente a função "Substituir") que podem ser disponibilizadas via código SQLCLR.
O exemplo abaixo usa o UDF escalar RegEx_Replace da biblioteca SQL # (da qual sou autor, mas essa função RegEx está disponível na versão Free, juntamente com muitas outras):
As
PRINT
instruções estão aí apenas para facilitar a comparação lado a lado na guia "Mensagens". A saída resultante é (modifiquei um pouco o XML original para deixar bem claro que apenas as partes desejadas foram tocadas e nada mais):Se você deseja atualizar um campo em uma tabela, pode adaptar o acima para ser o seguinte:
fonte
Provavelmente, existem maneiras melhores de fazê-lo fora do SQL Server. No entanto, aqui está uma maneira de fazê-lo.
O CTE xml transforma sua variável xml em uma tabela.
A seleção principal transforma o CTE novamente em xml.
Também pode ser feito usando
For XML Explicit
.fonte