SQL Server: per XML Percorso - Nesting / Grouping
-
11-12-2019 - |
Domanda
Ho dei dati che sembrano:
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
.
Voglio scrivere una query T-SQL in SQL Server per restituire i dati come questo:
<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>
.
Ho provato a restituire la query in XML utilizzando:
FOR XML PATH ('Order'), root ('Root')
.
Ma questo mi dà un nodo Order
per ogni riga (totale in totale) vs. solo un nodo ordine per ogni orderId
(2 in totale).
Qualche idea?
Soluzione
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')
. Altri suggerimenti
Per il completamento: Ecco una soluzione senza sottoselezione, che dovrebbe eseguire più veloce per le grandi tabelle.Invece raggruppa il tavolo tutte le volte in quanto ci sono livelli nell'XML e identifica il livello con Grouping_id (vedere https://technet.microsoft.com/en-us/library/bb522495 (v= sql.105) .aspx e https://docs.microsoft.com/en-US / SQL / relational-database / XML / Uso-Explicit-mode-with-for-XML ):
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
.