2012-06-29 10 views
5

He intentado utilizar "FOR XML PATH", "FOR XML EXPLICIT" y "FOR XML AUTO", pero los datos nunca se estructuran con la jerarquía correctaCómo devolver XML desde SQL Server 2008 estructurado con selecciones múltiples que comparten un elemento primario común

Básicamente, tengo una tabla principal (Clientes) y 3 tablas secundarias. Cada tabla tiene una columna customerid. Hay una relación de uno a varios desde la tabla Clientes a cada una de las tres tablas secundarias.

Como ejemplo falso, tengo una tabla principal de "Clientes", y tengo otras 3 tablas, Productos, Aficiones y Vehículos, todas relacionadas con la tabla Clientes por un cliente.

¿Cuál es el código SQL para alcanzar el siguiente tipo de estructura -

<Customers> 
    <Customer customerid="1" name="Fred"> 
     <Products> 
      <Product productname="table" /> 
      <Product productname="chair" /> 
      <Product productname="wardrobe" /> 
     </Products> 
     <Hobbies> 
      <Hobby hobbyname="Golf" /> 
      <Hobby hobbyname="Swimming" /> 
     </Hobbies> 
     <Vehicles> 
      <Vehicle name="Car" color="Red" /> 
      <Vehicle name="Bicycle" color="Blue" /> 
     </Vehicles> 
    </Customer> 
    <Customer customerid="2" name="Sue"> 
     <Products> 
      <Product productname="CD player" /> 
      <Product productname="Picture frame" /> 
     </Products> 
     <Hobbies> 
      <Hobby hobbyname="Dancing" /> 
      <Hobby hobbyname="Reading" /> 
     </Hobbies> 
     <Vehicles> 
      <Vehicle name="Car" color="Yellow" /> 
     </Vehicles> 
    </Customer> 
</Customers> 

Respuesta

4

Usando FOR XML RAW

IF OBJECT_ID ('tempdb..#customer') IS NOT NULL DROP TABLE #Customer 
IF OBJECT_ID ('tempdb..#product') IS NOT NULL DROP TABLE #product 
IF OBJECT_ID ('tempdb..#vehicle') IS NOT NULL DROP TABLE #Vehicle 
IF OBJECT_ID ('tempdb..#hobbies') IS NOT NULL DROP TABLE #Hobbies 

CREATE TABLE #Customer (id INT,name NVARCHAR(20)) 
INSERT INTO #customer SELECT 1,'Fred' UNION ALL SELECT 2,'Sue' 

CREATE TABLE #product(customer_id INT, name NVARCHAR(20)) 
INSERT INTO #product 
SELECt 1 AS id, 'table' as product 
UNION ALL SELECT 1 AS id, 'chair' as product 
UNION ALL SELECT 1 AS id, 'wardrobe' as product 
UNION ALL SELECT 2 AS id, 'CD Player' as product 
UNION ALL SELECT 2 AS id, 'Picture Frame' as product 


CREATE TABLE #vehicle(customer_id INT, name NVARCHAR(20),colour NVARCHAR(20)) 
INSERT INTO #vehicle 
SELECt 1 AS id, 'Car' as vehicle,'red' as colour 
UNION ALL SELECT 1 AS id, 'bicycle' as vehicle,'Blue' AS colour 
UNION ALL SELECT 2 AS id, 'Car' as vehicle, 'Yellow' as colour 


CREATE TABLE #hobbies(customer_id INT, name NVARCHAR(20)) 
INSERT INTO #hobbies 
SELECt 1 AS id, 'Golf' as name 
UNION ALL SELECT 1 AS id, 'Swimming' as name 
UNION ALL SELECT 2 AS id, 'Dancing' as name 
UNION ALL SELECT 2 AS id, 'Reading' as name 

SELECT 
c.id AS id 
,c.name AS name 
,(SELECT p.name 
    FROM #product p 
    WHERE p.customer_id = c.id 
    FOR XML RAW('Products'),TYPE) AS Products 
,(SELECT h.name 
    FROM #hobbies h 
    WHERE h.customer_id = c.id 
    FOR XML RAW('Hobbies'),TYPE) AS Hobbies 
,(SELECT v.name,v.colour 
    FROM #vehicle v 
    WHERE v.customer_id = c.id 
    FOR XML RAW('Vehicle'),TYPE) AS Vehicle 
FROM #customer c 
FOR XML RAW('Customer'), ROOT('Customers') 
5

Pruebe algo como esto - que utiliza para XML PATH y subselects para crear el "ligado" subnodos para un cliente determinado () Limité esto a dos subtablas, pero debería obtener la "esencia" y poder extenderlo a cualquier cantidad de subtablas vinculadas):

SELECT 
    CustomerID AS '@CustomerID', 
    CustName AS '@Name', 

    (SELECT ProductName AS '@productname' 
    FROM dbo.Products p 
    WHERE p.CustomerID = c.CustomerID 
    FOR XML PATH('Product'), TYPE) AS 'Products', 

    (SELECT HobbyName AS '@hobbyname' 
    FROM dbo.Hobbies h 
    WHERE h.CUstomerID = c.CustomerID 
    FOR XML PATH('Hobby'), TYPE) AS 'Hobbies' 
FROM 
    dbo.Customers c 
FOR XML PATH('Customer'), ROOT('Customers') 

me da una salida algo así como:

<Customers> 
    <Customer CustomerID="1" Name="Fred"> 
    <Products> 
     <Product productname="Table" /> 
     <Product productname="Wardrobe" /> 
     <Product productname="Chair" /> 
    </Products> 
    <Hobbies> 
     <Hobby hobbyname="Golf" /> 
     <Hobby hobbyname="Swimming" /> 
    </Hobbies> 
    </Customer> 
    <Customer CustomerID="2" Name="Sue"> 
    <Products> 
     <Product productname="CD Player" /> 
     <Product productname="Picture frame" /> 
    </Products> 
    <Hobbies> 
     <Hobby hobbyname="Dancing" /> 
     <Hobby hobbyname="Gardening" /> 
     <Hobby hobbyname="Reading" /> 
    </Hobbies> 
    </Customer> 
</Customers> 
+0

haría con PATH XML sea más eficiente que XML RAW para grandes conjuntos de datos? – Dibstar

+0

@Davin: no estoy seguro acerca de * efficiency * - Encuentro que FOR XML PATH es más legible y me da más flexibilidad para dar forma al resultado XML –

-1
USE [EAPP_BranchDb] 
GO 

/****** Object: StoredProcedure [dbo].[SP_procXMLOutput] Script Date: 09/05/2013 15:14:05 ******/ 
SET ANSI_NULLS ON 
GO 

SET QUOTED_IDENTIFIER ON 
GO 


CREATE PROCEDURE [dbo].[SP_procXMLOutput] 
        @Data XML OUTPUT 
AS 
BEGIN 

DECLARE @myDoc xml, 
     @myDoc1 xml, 
     @var_Doc1 nvarchar(max), 
     @myDoc2 xml, 
     @var1 nvarchar(max), 
     @var2 nvarchar(max), 
     @var3 nvarchar(max), 
     @var_id as int, 
     @var_id1 as nvarchar(10), 
     @var_grp_id1 as nvarchar(10), 
     @var_parent_id as bigint, 
     @var_grp_id as nvarchar(10), 
     @var_parent_type as nvarchar(1), 
     @var_type as nvarchar(10), 
     @xml XML, 
     @grp1 nvarchar(max), 
     @grp2 nvarchar(max) 

DECLARE xml_cur_id CURSOR FOR 
SELECT id, parent_id, grp_id, parent_type,type FROM xml_table where parent_type='P' order by id 

DECLARE xml_cur_grpid CURSOR FOR 
SELECT GRP_ID FROM xml_table WHERE parent_id=6 and parent_type='C' group by GRP_ID 

BEGIN 
    SET @myDoc = N'<frameSet label="Personal Details" id="1"   
        </frameSet'; 

    SET @var_Doc1='<field pid="6" type="ROW" /</field';    
    OPEN xml_cur_id 
     FETCH NEXT FROM xml_cur_id INTO @var_id, @var_parent_id, @var_grp_id, @var_parent_type,@var_type 
      WHILE @@FETCH_STATUS = 0 
      BEGIN 

      IF @var_type<'TABLE' and @var_parent_type='P' 
      BEGIN 
       SET @myDoc1=(SELECT id, name, type, isMandtory, isDependent, isDependentValue,dataType, lookupPath, lookupName, defaultValue, minDate, maxDate, fieldLabel, maxLength, readonly, disabled, onChangeEvent, reloadEvent, validationMessage, tabindex FROM xml_table WHERE [email protected]_id FOR XML RAW('field')) 
       SET @myDoc.modify('insert sql:variable("@myDoc1") as last into (/frameSet)[1] ') 
      END 


      IF @var_type='TABLE' and @var_parent_type='P' 
      BEGIN 
       /*table parent creation START*/ 
       SET @myDoc1=(SELECT id, name, type,fieldLabel FROM xml_table WHERE [email protected]_id FOR XML RAW('field')) 
       SET @myDoc.modify('insert sql:variable("@myDoc1") as last into (/frameSet)[1] ') 
       /*table parent creation END*/ 

       /*table COLUMN creation START*/ 
       SELECT @var1=(SELECT type,fieldLabel FROM XML_RELATION_TABLE WHERE Parent_id=6 order by id FOR XML RAW('field')) 
       SELECT @var2=(SELECT '<field type="ROW"'[email protected]+'</field') 
       SELECT @[email protected] 
       SET @[email protected]_id 
       /*table COLUMN creation START*/ 
       /*TABLE CHILD row creation START*/ 
       SET @var3='' 
       OPEN xml_cur_grpid 
        FETCH NEXT FROM xml_cur_grpid INTO @var_grp_id1 
         WHILE @@FETCH_STATUS = 0 
         BEGIN 

          SELECT @grp1=(SELECT id, name, type, isMandtory, isDependent, isDependentValue,dataType, lookupPath, 
          lookupName, defaultValue, minDate, maxDate, fieldLabel, maxLength, 
          readonly, disabled, onChangeEvent, reloadEvent, validationMessage, tabindex FROM xml_table 
          WHERE [email protected]_parent_id and parent_type='C' and [email protected]_grp_id1 order by id 
          FOR XML RAW('field')) 

          SELECT @grp2=(SELECT '<field type="ROW"'[email protected]+'</field') 
          SET @[email protected][email protected] 

         FETCH NEXT FROM xml_cur_grpid INTO @var_grp_id1 
         END 
       CLOSE xml_cur_grpid 
       DEALLOCATE xml_cur_grpid    
       /*TABLE CHILD row creation END*/ 


       SELECT @[email protected][email protected] 
       SET @myDoc.modify('insert sql:variable("@myDoc1") into (/frameSet/field[@id=sql:variable("@var_id1")])[1] ') 
       SET @var2='' 
       SET @var3='' 
      END 

      FETCH NEXT FROM xml_cur_id INTO @var_id, @var_parent_id, @var_grp_id, @var_parent_type,@var_type 
      END 
    CLOSE xml_cur_id 
    DEALLOCATE xml_cur_id 


    SET @[email protected] 

END   

END  

GO 
+0

CÓDIGO PARA GENERACIÓN XML FROM SQL SERVER2008 –

+0

Estoy seguro de que esto hace algo útil para usted, pero ¿Cómo es relevante para la pregunta? –

2
select 
    c.customerid, 
    c.name, 
    (
     select p.productname 
     from Products as p 
     where p.customerid = c.customerid 
     for xml raw('Product'), root('Products'), type 
    ), 
    (
     select h.hobbyname 
     from Hobbies as h 
     where h.customerid = c.customerid 
     for xml raw('Hobby'), root('Hobbies'), type 
    ), 
    (
     select v.name, v.color 
     from Vehicles as v 
     where v.customerid = c.customerid 
     for xml raw('Vehicle'), root('Vehicles'), type 
    ) 
from Customers as c 
for xml raw('Customer'), root('Customers') 

=> sql fiddle demo

0
DECLARE @sampleCount int =10 
SET STATISTICS TIME ON 


SELECT 

    (SELECT TOP (@sampleCount) * FROM [Table1]TABLESAMPLE(100 PERCENT) FOR XML PATH('tbl1'), TYPE) AS 'tbl1', 
    (SELECT top (@sampleCount) * FROM [Table2] TABLESAMPLE(100 PERCENT) FOR XML PATH('tbl2'), TYPE) AS 'tbl2', 
    (SELECT top (@sampleCount) * FROM [Table3] TABLESAMPLE(100 PERCENT) FOR XML PATH('tbl3'), TYPE) AS 'tbl3' 


FOR XML PATH(''), ROOT('Table') 
Cuestiones relacionadas