2012-07-25 24 views
15

gibi görünüyor veriler var: Böyle veri döndürmek için SQL Server T-SQL sorgusu yazmak istiyorumSQL Server: XML PATH İÇİN - yuvalama/gruplama

OrderID CustomerID ItemID ItemName 
10000 1234  111111 Product A 
10000 1234  222222 Product B 
10000 1234  333333 Product C 
20000 5678  111111 Product A 
20000 5678  222222 Product B 
20000 5678  333333 Product C 

:

<Root> 
    <Order> 
    <OrderID>10000</OrderID> 
    <CustomerID>1234</CustomerID> 
    <LineItem> 
     <ItemID>11111</ItemId> 
     <ItemName>Product A</ItemName> 
    </LineItem> 
    <LineItem> 
     <ItemID>22222</ItemId> 
     <ItemName>Product B</ItemName> 
    </LineItem> 
    <LineItem> 
     <ItemID>33333</ItemId> 
     <ItemName>Product B</ItemName> 
    </LineItem> 
    </Order> 
    <Order> 
    <OrderID>20000</OrderID> 
    <CustomerID>5678</CustomerID> 
    <LineItem> 
     <ItemID>11111</ItemId> 
     <ItemName>Product A</ItemName> 
    </LineItem> 
    <LineItem> 
     <ItemID>22222</ItemId> 
     <ItemName>Product B</ItemName> 
    </LineItem> 
    <LineItem> 
     <ItemID>33333</ItemId> 
     <ItemName>Product B</ItemName> 
    </LineItem> 
    </Order> 
</Root> 

kullandığım XML sorgu dönen denedim:

FOR XML PATH ('Order'), root ('Root') 

Ama bu bana her satır için bir Order düğümü (6 verir toplam) ve her orderId için bir sipariş düğümü (toplamda 2).

Herhangi bir fikrin var mı?

cevap

24
select 
    OrderID, 
    CustomerID, 
    (
     select 
     ItemID, 
     ItemName 
     from @Orders rsLineItem 
     where rsLineItem.OrderID = rsOrders.OrderID 
     for xml path('LineItem'), type 
    ) 
from (select distinct OrderID, CustomerID from @Orders) rsOrders 
FOR XML PATH ('Order'), root ('Root') 
+1

Teşekkür Bert. 'Type', 'xml yolu için' alt sorgusunda ne yapar? – jared

+4

@jared Bunun anlamı, 'bunu XML veri türü olarak döndür.' Yani yukarıdaki sorguda, alt sorguyu yalnızca küçük bir xml parçası olarak döndürüyor. – Bert

+0

Müthiş. Teşekkürler! – jared

0

Tamamlama için: burada büyük seçimlik olmayan, büyük tablolar için daha hızlı gerçekleştirmesi gereken bir çözüm var. Orada XML düzeyi vardır ve tanımlayan Bunun yerine gruplar tablo kadar pek çok kez GROUPING_ID ile seviyesi (https://technet.microsoft.com/en-us/library/bb522495(v=sql.105).aspx ve https://docs.microsoft.com/en-us/sql/relational-databases/xml/use-explicit-mode-with-for-xml bakınız):

with rsOrders as (
    select '10000' OrderID, '1234' CustomerID, '111111' ItemID, 'Product A' ItemName union 
    select '10000' orderId, '1234' customerID, '222222' itemID, 'Product B' ItemName union 
    select '10000' orderId, '1234' customerID, '333333' itemID, 'Product C' ItemName union 
    select '20000' orderId, '5678' customerID, '111111' itemID, 'Product A' ItemName union 
    select '20000' orderId, '5678' customerID, '222222' itemID, 'Product B' ItemName union 
    select '20000' orderId, '5678' customerID, '333333' itemID, 'Product C' ItemName 
) 
select case 
     when GROUPING_ID(ItemID) = 0 then 3 
     when GROUPING_ID(OrderID) = 0 then 2 
     else 1 
     end as tag, 
     case 
      when GROUPING_ID(ItemID) = 0 then 2 
     when GROUPING_ID(OrderID) = 0 then 1 
     else null 
     end as parent, 
     null  as 'Root!1', 
     OrderID as 'Order!2!OrderID!element', 
     CustomerID as 'Order!2!CustomerID!element', 
     ItemID  as 'LineItem!3!ItemID!element', 
     ItemName as 'LineItem!3!ItemName!element' 
    from rsOrders 
group by grouping sets ((), (OrderID, CustomerID), (OrderID, CustomerID, ItemID, ItemName)) 
order by OrderID, CustomerID, ItemID, ItemName 
    for xml explicit, type