Tengo una XML
columna que contiene datos con estructura similar:
<Root>
<Elements>
<Element Code="1" Value="aaa"></Element>
<Element Code="2" Value="bbb"></Element>
<Element Code="3" Value="ccc"></Element>
</Elements>
</Root>
¿Cómo puedo modificar los datos usando SQL Server para cambiar cada Value
atributo en un 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>
Actualizar:
Mi XML se parece más a esto:
<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>
Solo me gustaría mover el Value
atributo y preservar todos los demás atributos y elementos.
sql-server
xml
xquery
Wojteq
fuente
fuente
<Value>
elementos por cada uno<Element>
. Si no es así, mover el atributo a un elemento solo crea un XML más hinchado y posiblemente menos eficiente.<Value>
elemento o en su lugar.Respuestas:
Puede destruir el XML y reconstruirlo nuevamente usando XQuery.
Resultado:
Si
Elements
no es el primer elemento deRoot
la consulta, debe modificarse para agregar todos los elementos antes delElements
primero y todos los elementosElements
después.fuente
También puede usar los métodos del tipo de datos XML (por ejemplo, modificar ) y algunos XQuery para modificar el xml, por ejemplo
Este método no tiende a escalar bien en grandes piezas de XML, pero podría adaptarse mejor que un reemplazo mayorista de XML.
También puede adaptar fácilmente este método si su XML está almacenado en una tabla. Nuevamente, por experiencia, no recomendaría ejecutar una única actualización en una tabla de un millón de filas. Si su tabla es grande, considere pasar un cursor por ella o agrupar las actualizaciones. Aquí está la técnica:
fuente
ACTUALIZAR:
He actualizado el código, así como el XML de entrada y salida en la consulta de ejemplo a continuación para reflejar el último requisito, indicado en un comentario sobre la excelente respuesta de @ Mikael , que es:
Si bien una sola expresión puede coincidir correctamente con esta nueva variación, no parece haber una forma de omitir el
<Value/>
elemento vacío en una sola pasada, ya que la lógica condicional no está permitida en la cadena de reemplazo. Entonces, he adaptado esto para que sea una modificación de 2 partes: una pasada para obtener los@Value
atributos no vacíos y una pasada para obtener los@Value
atributos vacíos . No había necesidad de manejar si<Element>
faltaba el@Value
atributo ya que el deseo es no tener el<Value>
elemento de todos modos.Una opción es tratar el XML como una cadena normal y transformarlo en función de un patrón. Esto se logra fácilmente usando Expresiones regulares (específicamente la función "Reemplazar") que puede estar disponible a través del código SQLCLR.
El siguiente ejemplo utiliza el UDF escalar RegEx_Replace de la biblioteca SQL # (de la que soy autor, pero esta función RegEx está disponible en la versión gratuita, junto con muchas otras):
Las
PRINT
declaraciones están ahí solo para facilitar la comparación lado a lado en la pestaña "Mensajes". El resultado resultante es (modifiqué un poco el XML original para dejar muy claro que solo se tocaron las partes deseadas y nada más):Si desea actualizar un campo en una tabla, puede adaptar lo anterior para que sea el siguiente:
fuente
Probablemente hay mejores formas de hacerlo fuera de SQL Server. Sin embargo, aquí hay una forma de hacerlo.
El xml CTE transforma su variable xml en una tabla.
La selección principal luego transforma el CTE nuevamente en xml.
También se puede hacer usando
For XML Explicit
.fuente