2012-06-29 5 views
5

Próbowałem używać "FOR XML PATH", "DLA DOSKONAŁEGO XML" i "DLA XML AUTO", ale dane nigdy nie są uporządkowane za pomocą poprawna heirarchia.Jak zwrócić kod XML z SQL Server 2008, który jest podzielony na wiele wyborów współużytkujących wspólnego rodzica

Zasadniczo mam jedną tabelę nadrzędną (Klienci) i 3 tabele potomne. Każda tabela ma kolumnę customerid. Istnieje relacja jeden-do-wielu z tabeli Klienci do każdego z trzech tabel podrzędnych.

Jako przykładowy przykład mam tabelę "Klienci" nadrzędnej, a także mam 3 inne tabele - Produkty, Hobby i Pojazdy - wszystkie związane z tabelą Klienci przez klienta.

Co to jest kod SQL, aby osiągnąć następujące rodzaje konstrukcji -

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

Odpowiedz

4

Korzystanie 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

Spróbuj coś takiego - to wykorzystuje do XML PATH i obsługę żądań, aby stworzyć "połączony" pod-węzły dla danego klienta (Ograniczam to do dwóch podrzędnych tabel - ale powinieneś uzyskać "istotę" tego i być w stanie rozszerzyć go na dowolną liczbę powiązanych subtabli):

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

daje mi coś podobnego wyjściowego:

<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

Byłoby za pomocą XML PATH być bardziej wydajny niż XML RAW dla większych zbiorów danych? – Dibstar

+0

@Davin: nie wiem na temat * efektywności * - Uważam, że FOR XML PATH jest bardziej czytelny i daje mi więcej elastyczności do kształtowania wyjściowego 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

KODEKS DO GENERACJI XML Z SQL SERVER2008 –

+0

Jestem pewien, że robi to coś pożytecznego dla ciebie, ale jak to ma znaczenie dla pytania? –

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') 
Powiązane problemy