Search code examples
xmlxqueryxmlspy

SUM and GROUP BY in xquery with 1 xml file


I have an SQL query:

SELECT ShipVia, SUM(Freight)
FROM Orders
GROUP BY ShipVia

which returns the values below from the access database

Ship Via  TotalFreight
   1       $16,185.33
   2       $28,244.85
   3       $20,512.51

I am trying to convert this to xquery (using xquery 1.0)

So far I have this,

xquery version "1.0";
for $x in doc("Orders.xml")/dataroot/Orders
return
<OrderDetails>
{
    $x/ShipVia,
    <TotalFreight>{sum($x/Freight)}</TotalFreight>
}
</OrderDetails>

This however, outputs every single order along with the freight cost as if I did

SELECT ShipVia, Freight
FROM Orders

in SQL

How do I make the xquery actually add each one up as the SQL command does

These are three orders from the Orders.xml file for example

<dataroot>
    <Orders>
        <ShipVia>1</ShipVia>
        <Freight>32.38</Freight>
    </Orders>
    <Orders>
        <ShipVia>1</ShipVia>
        <Freight>11.61</Freight>
    </Orders>
    <Orders>
        <ShipVia>2</ShipVia>
        <Freight>65.83</Freight>
    </Orders>
</dataroot>

EDIT: Stripped Unnecessary Nodes (Added Duplicate)


Solution

  • The following is one approach to doing this in XQuery 1.0 (which lacks XQuery 3.0's native group by operator):

    let $doc := 
        <dataroot>
            <Orders>
                <ShipVia>1</ShipVia>
                <Freight>32.38</Freight>
            </Orders>
            <Orders>
                <ShipVia>1</ShipVia>
                <Freight>11.61</Freight>
            </Orders>
            <Orders>
                <ShipVia>2</ShipVia>
                <Freight>65.83</Freight>
            </Orders>
        </dataroot>
    
    let $ship_via_values := distinct-values($doc/Orders/ShipVia/text())
    for $ship_via_value in $ship_via_values
    return
      <OrderDetails>
        <ShipVia>{$ship_via_value}</ShipVia>
        <TotalFreight>{
          sum($doc/Orders[ShipVia=$ship_via_value]/Freight)
        }</TotalFreight>
      </OrderDetails>
    

    This query returns the following result:

    <OrderDetails>
      <ShipVia>1</ShipVia>
      <TotalFreight>43.99</TotalFreight>
    </OrderDetails>
    <OrderDetails>
      <ShipVia>2</ShipVia>
      <TotalFreight>65.83</TotalFreight>
    </OrderDetails>
    

    ...which appears to be desired output.