2012-06-29 10 views
5

Ho provato a utilizzare "FOR XML PATH", "FOR XML EXPLICIT" e "FOR XML AUTO" ma i dati non sono mai strutturati con la corretta gerarchia.Come restituire XML da SQL Server 2008 strutturato con selezioni multiple che condividono un genitore comune

Fondamentalmente, ho una tabella padre (Clienti) e 3 tabelle figlio. Ogni tabella ha una colonna customerid. Esiste una relazione uno-a-molti dalla tabella Clienti a ciascuna delle 3 tabelle figlio.

Come esempio di simulazione, ho una tabella "Clienti" principale e ho altri 3 tavoli - Prodotti, Hobby e veicoli - tutti correlati alla tabella Clienti da un cliente.

Qual è il codice SQL per ottenere il seguente tipo di struttura -

<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> 

risposta

4

Utilizzando 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

provare qualcosa di simile - che utilizza per XML PATH e subselect per creare il "collegato" sottonodi per un determinato cliente (Ho limitato questo a due sotto tabelle, ma dovresti ottenere il "succo" di esso ed essere in grado di estenderlo a qualsiasi numero di sottotitoli collegati):

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') 

mi dà un qualcosa di output come:

<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

stesse usando XML PATH essere più efficiente di XML RAW per set di dati più grandi? – Dibstar

+0

@Davin: non sono sicuro dell'efficienza * - Trovo più leggibile il percorso FOR XML e mi dà più flessibilità per modellare l'output 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

CODICE PER GENERAZIONE XML DA SQL SERVER2008 –

+0

Sono sicuro che questo fa qualcosa di utile per te ma come è pertinente alla domanda? –

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') 
Problemi correlati