tipo tabla ser recuperar nodos método modify literal leer extraer debe datos cadena atributos argumento sql xml tsql xpath

recuperar - xml a tabla sql server



Seleccionar nodos XML como filas (5)

Estoy seleccionando de una tabla que tiene una columna XML usando T-SQL. Me gustaría seleccionar un cierto tipo de nodo y crear una fila para cada uno.

Por ejemplo, supongamos que estoy seleccionando de una tabla de personas . Esta tabla tiene una columna XML para direcciones . El XML tiene un formato similar al siguiente:

<address> <street>Street 1</street> <city>City 1</city> <state>State 1</state> <zipcode>Zip Code 1</zipcode> </address> <address> <street>Street 2</street> <city>City 2</city> <state>State 2</state> <zipcode>Zip Code 2</zipcode> </address>

¿Cómo puedo obtener resultados como este?

Nombre Ciudad Estado

Joe Baker Seattle WA

Joe Baker Tacoma WA

Fred Jones Vancouver BC


Si puede usarlo, la API apk es conveniente para XML:

var addresses = dataContext.People.Addresses .Elements("address") .Select(address => new { street = address.Element("street").Value, city = address.Element("city").Value, state = address.Element("state").Value, zipcode = address.Element("zipcode").Value, });


Así es como lo hago genéricamente:

Destruí el código fuente XML a través de una llamada como

DECLARE @xmlEntityList xml SET @xmlEntityList = '' <ArbitrarilyNamedXmlListElement> <ArbitrarilyNamedXmlItemElement><SomeVeryImportantInteger>1</SomeVeryImportantInteger></ArbitrarilyNamedXmlItemElement> <ArbitrarilyNamedXmlItemElement><SomeVeryImportantInteger>2</SomeVeryImportantInteger></ArbitrarilyNamedXmlItemElement> <ArbitrarilyNamedXmlItemElement><SomeVeryImportantInteger>3</SomeVeryImportantInteger></ArbitrarilyNamedXmlItemElement> </ArbitrarilyNamedXmlListElement> '' DECLARE @tblEntityList TABLE( SomeVeryImportantInteger int ) INSERT @tblEntityList(SomeVeryImportantInteger) SELECT XmlItem.query(''//SomeVeryImportantInteger[1]'').value(''.'',''int'') as SomeVeryImportantInteger FROM [dbo].[tvfShredGetOneColumnedTableOfXmlItems] (@xmlEntityList)

mediante la utilización de la función de valor escalar

/* Example Inputs */ /* DECLARE @xmlListFormat xml SET @xmlListFormat = '' <ArbitrarilyNamedXmlListElement> <ArbitrarilyNamedXmlItemElement>004421UB7</ArbitrarilyNamedXmlItemElement> <ArbitrarilyNamedXmlItemElement>59020UH24</ArbitrarilyNamedXmlItemElement> <ArbitrarilyNamedXmlItemElement>542514NA8</ArbitrarilyNamedXmlItemElement> </ArbitrarilyNamedXmlListElement> '' declare @tblResults TABLE ( XmlItem xml ) */ -- ============================================= -- Author: 6eorge Jetson -- Create date: 01/02/3003 -- Description: Shreds a list of XML items conforming to -- the expected generic @xmlListFormat -- ============================================= CREATE FUNCTION [dbo].[tvfShredGetOneColumnedTableOfXmlItems] ( -- Add the parameters for the function here @xmlListFormat xml ) RETURNS @tblResults TABLE ( -- Add the column definitions for the TABLE variable here XmlItem xml ) AS BEGIN -- Fill the table variable with the rows for your result set INSERT @tblResults SELECT tblShredded.colXmlItem.query(''.'') as XmlItem FROM @xmlListFormat.nodes(''/child::*/child::*'') as tblShredded(colXmlItem) RETURN END --SELECT * FROM @tblResults


Aquí está su solución:

/* TEST TABLE */ DECLARE @PEOPLE AS TABLE ([Name] VARCHAR(20), [Address] XML ) INSERT INTO @PEOPLE SELECT ''Joel'', ''<address> <street>Street 1</street> <city>City 1</city> <state>State 1</state> <zipcode>Zip Code 1</zipcode> </address> <address> <street>Street 2</street> <city>City 2</city> <state>State 2</state> <zipcode>Zip Code 2</zipcode> </address>'' UNION ALL SELECT ''Kim'', ''<address> <street>Street 3</street> <city>City 3</city> <state>State 3</state> <zipcode>Zip Code 3</zipcode> </address>'' SELECT * FROM @PEOPLE -- BUILD XML DECLARE @x XML SELECT @x = ( SELECT [Name] , [Address].query('' for $a in //address return <address street="{$a/street}" city="{$a/city}" state="{$a/state}" zipcode="{$a/zipcode}" /> '') FROM @PEOPLE AS people FOR XML AUTO ) -- RESULTS SELECT [Name] = T.Item.value(''../@Name'', ''varchar(20)''), street = T.Item.value(''@street'' , ''varchar(20)''), city = T.Item.value(''@city'' , ''varchar(20)''), state = T.Item.value(''@state'' , ''varchar(20)''), zipcode = T.Item.value(''@zipcode'', ''varchar(20)'') FROM @x.nodes(''//people/address'') AS T(Item) /* OUTPUT*/ Name | street | city | state | zipcode ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Joel | Street 1 | City 1 | State 1 | Zip Code 1 Joel | Street 2 | City 2 | State 2 | Zip Code 2 Kim | Street 3 | City 3 | State 3 | Zip Code 3


En caso de que esto sea útil para cualquier otra persona que busque una solución "genérica", creé un procedimiento CLR que puede tomar un fragmento Xml como el anterior y "triturarlo" en un conjunto de resultados tabular, sin que usted proporcione ninguna información adicional sobre los nombres o tipos de columnas, o personalizando su llamada de cualquier forma para el fragmento Xml dado:

http://architectshack.com/ClrXmlShredder.ashx

Por supuesto, hay algunas restricciones (el xml debe ser de naturaleza "tabular" como esta muestra, la primera fila debe contener todos los elementos / columnas que se admitirán, etc.) - pero espero que esté unos pasos por delante de lo que está disponible incorporado.


Aquí hay una solución alternativa:

;with cte as ( select id, name, addresses, addresses.value(''count(/address/city)'',''int'') cnt from @demo ) , cte2 as ( select id, name, addresses, addresses.value(''((/address/city)[sql:column("cnt")])[1]'',''nvarchar(256)'') city, cnt-1 idx from cte where cnt > 0 union all select cte.id, cte.name, cte.addresses, cte.addresses.value(''((/address/city)[sql:column("cte2.idx")])[1]'',''nvarchar(256)''), cte2.idx-1 from cte2 inner join cte on cte.id = cte2.id and cte2.idx > 0 ) select id, name, city from cte2 order by id, city

FYI: He publicado otra versión de este SQL en el sitio de revisión de código aquí: https://codereview.stackexchange.com/questions/108805/select-field-in-an-xml-column-where-both-xml- and-table-contains-multiple-matches