T-SQL: Leer parámetros XML y convertirlos en tablas

xml

Recientemente en un proyecto nos hemos encontrado con la necesidad de leer un parametro XML desde una función T-SQL y convertirla en una tabla para poder realizar un JOIN con los valores de otra tabla de la base de datos. En este caso no nos sirven las nuevas Table-Value de SQL Server 2008, ya que el resultado proviene de un campo XML y el servidor es un 2005, así que tuvimos que explorar las distintas posibilidades de trabajo XML de SQL Server 2005.

Anteriormente, en algunas ocasiones había usado parámetros XML para enviar varios valores a un stored procedure o a una función, pero siempre con un sólo campo (el clásico ejemplo de cómo pasar varios IDs a un SP para hacer un JOIN y filtrar valores de una tabla).

Leer valores simples de un parámetro XML

Partiendo de un valor XML como este:

<Usuarios>
  <ID>S-1-5-21-823518204-1220945662-725345543-1138</ID>
  <ID>S-1-5-21-823518204-1220945662-725345543-1133</ID> 
  <ID>S-1-1-0</ID> 
  <ID>S-1-5-32-545</ID> 
  <ID>S-1-5-32-544</ID> 
  <ID>S-1-5-4</ID> 
  <ID>S-1-5-11</ID> 
  <ID>S-1-2-0</ID> 
  <ID>S-1-5-21-823518204-1220945662-725345543-1231</ID> 
  <ID>S-1-5-21-823518204-1220945662-725345543-512</ID> 
  <ID>S-1-5-21-823518204-1220945662-725345543-1123</ID> 
  <ID>S-1-5-21-823518204-1220945662-725345543-1219</ID> 
  <ID>S-1-5-21-823518204-1220945662-725345543-513</ID> 
</Usuarios>

Deseamos enviarlo a un SP y hacer un JOIN con los datos de una tabla de usuarios:

UserSID UserName UserType
S-1-5-21-823518204-1220945662-725345543-1138 OLIMPUS\Zeus A
S-1-5-21-823518204-1220945662-725345543-1137 OLIMPUS\Apolo B
S-1-5-21-1960408961-1788223648-839522115-500 OLIMPUS\Guest NULL
S-1-5-32-544 USERMACHINE\Administrator A

Para ello en un SP o función declaramos el parámetro (@IDUsuarios As XML) y una tabla temporal en la que almacenar los datos de XML:

DECLARE @Usuarios TABLE (ID varchar(50)) 
INSERT INTO @Usuarios (ID) 
SELECT ParamValues.ID.value('.','VARCHAR(50)')
FROM @IdUsuarios.nodes('/Usuarios/ID') as ParamValues(ID) 

Y a continuación realizamos el JOIN entre las dos tablas. Simple, sencillo y elegante.

SELECT U.* FROM Users U
INNER JOIN @Usuarios UIDS
ON UIDS.ID = U.UserSID

Leer múltiples campos de un parámetro XML

Pero... ¿Y si el parámetro XML contiene más de un valor o campo? Supongamos un XML como el siguiente:

<Orders>
  <Order OrderID="13000" CustomerID="ALFKI" OrderDate="2006-09-20Z" EmployeeID="2"></Order>
  <Order OrderID="13001" CustomerID="VINET" OrderDate="2006-09-20Z" EmployeeID="1"></Order>
</Orders>

En este caso la dificultad esta en que el XML contiene más de un campo, con lo que el uso de la sintaxis ParamValues.ID.value no es válida. De modo que vamos a usar la sintaxis @Parametro.nodes para devolver cada elemento 'Orders' como una fila y Item.value para acceder a cada uno de los campos:

SELECT OrderID    = T.Item.value('@OrderID', 'int'),
       CustomerID = T.Item.value('@CustomerID', 'nchar(5)'),
       OrderDate  = T.Item.value('@OrderDate',  'datetime'),
       EmployeeId = T.Item.value('@EmployeeID', 'smallint')
FROM   @x.nodes('Orders/Order') AS T(Item)

Bien, bien, bien... Ya hemos visto como transformar un xml en una tabla, ahora que más?

Leer subnodos de un parámetro XML

<Orders>
  <Order OrderID="13000" CustomerID="ALFKI" OrderDate="2006-09-20Z" EmployeeID="2">
     <OrderDetails ProductID="76" Price="123" Qty = "10"/>
     <OrderDetails ProductID="16" Price="3.23" Qty = "20"/>
  </Order>
  <Order OrderID="13001" CustomerID="VINET" OrderDate="2006-09-20Z" EmployeeID="1">
     <OrderDetails ProductID="12" Price="12.23" Qty = "1"/>
  </Order>
</Orders>

En este caso tenemos un documento XML más complejo, con una jerarquía de elementos 'Order' que a su vez contienen elementos 'OrderDetails'. Ok, si queremos acceder a todos los elementos 'OrderDetail' del XML basta con cambiar la consulta XPath y el tipo de los elementos devueltos:

SELECT OrderID    = T.Item.value('../@OrderID', 'int'),
       ProductID  = T.Item.value('@ProductID',  'smallint'),
       Price      = T.Item.value('@Price',      'decimal(10,2)'),
       Qty        = T.Item.value('@Qty',        'int')
FROM   @x.nodes('Orders/Order/OrderDetails') AS T(Item)

Y si sólamente deseamos obtener algunos de ellos, podemos hacer uso de la cláusula WHERE de este modo:

SELECT OrderID    = T.Item.value('../@OrderID', 'int'),
       ProductID  = T.Item.value('@ProductID',  'smallint'),
       Price      = T.Item.value('@Price',      'decimal(10,2)'),
       Qty        = T.Item.value('@Qty',        'int')
FROM   @x.nodes('Orders/Order/OrderDetails') AS T(Item)
WHERE T.Item.value('../@OrderID', 'int') = 13000

Sencillo, verdad? Pues ahora a probarlo.

Demo

Puedes pegar este código en el analizador de consultas y pruébalo:

DECLARE @x xml
SELECT @x =
  N'<Orders>
      <Order OrderID="13000" CustomerID="ALFKI" OrderDate="2006-09-20Z" EmployeeID="2">
         <OrderDetails ProductID="76" Price="123" Qty = "10"/>
         <OrderDetails ProductID="16" Price="3.23" Qty = "20"/>
      </Order>
      <Order OrderID="13001" CustomerID="VINET" OrderDate="2006-09-20Z" EmployeeID="1">
         <OrderDetails ProductID="12" Price="12.23" Qty = "1"/>
      </Order>
    </Orders>'
 
SELECT OrderID    = T.Item.value('@OrderID', 'int'),
       CustomerID = T.Item.value('@CustomerID', 'nchar(5)'),
       OrderDate  = T.Item.value('@OrderDate',  'datetime'),
       EmployeeId = T.Item.value('@EmployeeID', 'smallint')
FROM   @x.nodes('Orders/Order') AS T(Item)
 
SELECT OrderID    = T.Item.value('../@OrderID', 'int'),
       ProductID  = T.Item.value('@ProductID',  'smallint'),
       Price      = T.Item.value('@Price',      'decimal(10,2)'),
       Qty        = T.Item.value('@Qty',        'int')
FROM   @x.nodes('Orders/Order/OrderDetails') AS T(Item)

Por cierto, ya sabeis por que en XML siempre es necesario cerrar las etiquetas verdad? Porque si no en un caso como el siguiente el efecto visual sería bastante feo...

xmlmodelo

Ya se que este no es lugar para estas cosas, pero no he podido resistirme... :-P

Un saludo desde Andorra,

Published 12/3/2008 16:56 por Lluis Franco
Archivado en: ,
Comparte este post:

Comentarios

# re: T-SQL: Leer parámetros XML y convertirlos en tablas

Thursday, March 13, 2008 3:20 PM por csegura

Muy bueno, muy pero que muy bueno ... I love XML ..

(estoy hablando de la foto ehh.. :-)

Voy a probarlo ahora mismito, que tengo un monton de XML que importar...

# re: T-SQL: Leer parámetros XML y convertirlos en tablas

Wednesday, July 16, 2008 5:38 PM por piyey

Hola, gracias por la contribución.

Hace algunos meses me había entrado lo del xml para sql server, hice algunas pruebas en sql server 2000 y lo miré interesante, pero por cuestiones que no recuerdo no pude adentrarme en este tema.

Ahora, estoy haciendo un proyecto donde creo que la mejor solución es usar xml para pasar parametros a un procedimiento, he estado buscando para ver si encuentro donde vi el ejemplo la vez pasada pero no veo nada... ahora, vine a caer por aca y quise probar el ejemplo para ver si me iba con esto, pero no me funcionó (estoy usando sql server 2005).

El error que me presenta es el siguiente:

Msg 170, Level 15, State 1, Line 17

Line 17: Incorrect syntax near '.'.

Msg 170, Level 15, State 1, Line 23

Line 23: Incorrect syntax near '.'.

Me gustaría saber si tienen alguna idea de como solucionar esto.

Gracias de antemano... y... también me gustó el ejemplo de cerrar tags xD

# re: T-SQL: Leer parámetros XML y convertirlos en tablas

Friday, August 01, 2008 11:34 PM por Oscar Medina

Hola, muy interesante la contribución, pero tengo un problema. En el segundo ejemplo que detallas es para dos tablas padre - hijo que sus datos estan dentro de atributos, pero existe la manera de leer los datos juntando los dos tipos de lectura.

Te envío un ejemplo de como ocupo leer el XML

Saludos

<Orders>

<OrderID ID="790459" CusotmerID="Alfky">

<OrderDetails>

<ProductID>CO</ProductID>

<Price>1234</Price>

</OrderDetails>

<OrderDetails>

<ProductID>AA</ProductID>

<Price>3423</Price>

</OrderDetails>

</OrderID>

<OrderID ID="790460" CusotmerID="pp">

<OrderDetails>

<ProductID>TR</ProductID>

<Price>8784</Price>

</OrderDetails>

<OrderDetails>

<ProductID>AA</ProductID>

<Price>5481</Price>

</OrderDetails>

</OrderID>

</Orders>

# re: T-SQL: Leer parámetros XML y convertirlos en tablas

Wednesday, August 13, 2008 12:35 AM por Jorge

Con esos <***>(.)(.)<***>

Quien no quiere aprender xml....

Chao amigos....

# re: T-SQL: Leer parámetros XML y convertirlos en tablas

Monday, July 13, 2009 8:31 PM por Ivan Muñoz

Muy bueno tu ejemplo y la vdd es irresistible no ver esa foto, :D jajajaja

Gracias por el apoyo.

Saludos

# re: T-SQL: Leer parámetros XML y convertirlos en tablas

Friday, December 04, 2009 9:37 PM por cesar villamil

Buenas tardes, muy bueno el documento, pero quisiera saber si tienen documentación sobre el tema, gracias

# re: T-SQL: Leer parámetros XML y convertirlos en tablas

Friday, September 03, 2010 6:08 PM por Leyton espitia

lo qe as aportado es genial se pasa de los limites gracias.....

tengo una duda .... como leer un archivo xml desde sql server para luego pasarlo como parametro a un procedimiento almacenado..... respueta publica o mi correo

leyton_espitia@hotmail.com

# re: T-SQL: Leer parámetros XML y convertirlos en tablas

Friday, December 17, 2010 3:31 AM por Jorge Villamil

Ok, me queda mas que claro como leer parametros de un XML que ya está en una variable

Pero cuando tengo un archivo XML como puedo hacer la carga de este a la memoria y asignarlo a una variable? para entonces poder hacer lo siguiente, espero me puedan ayudar, gracias y saludos...

P.D. por cierto, estoy usando SQLServer 2000 aunque creo que no han cambiado mucho las instrucciones para el uso de XML

# re: T-SQL: Leer parámetros XML y convertirlos en tablas

Tuesday, January 18, 2011 8:47 PM por osman

excelente aportacion, muy interesante,,, kisiera saber si tienes algo para manejar el xml en una aplicacion visual basic 2005

# re: T-SQL: Leer parámetros XML y convertirlos en tablas

Tuesday, January 18, 2011 8:49 PM por osman

mi correo es edmundulloa7@gmail.com

saludos desde Guatemala

# re: T-SQL: Leer parámetros XML y convertirlos en tablas

Thursday, March 10, 2011 6:32 PM por Jhonny Vargas

Siempre me ha gustado el contenido del xml.

Un abrazo desde Chile!

# re: T-SQL: Leer parámetros XML y convertirlos en tablas

Tuesday, August 23, 2011 11:40 PM por Humberto

qué espectáculo trabajar con XML en T-SQL.

Gracias Luis Franco.