PatrickSchenker
PatrickSchenker

Reputation: 13

XQuery: Grouping by an element and calculations based on elements that hold the same grouping criteria

this is my second post only and I hope you can help me. I found similar quesions, but either they were slightly different or I am unable to transfer the solutions to my problem.

I do have the following source:

<?xml version="1.0" encoding="UTF-8"?>
<goods>
    <item>
        <groupIdentification>001</groupIdentification>
        <measures>
            <measure type="piece">
                <value>100</value>
                <unit>PK</unit>
            </measure>
            <measure type="weight">
                <value>100</value>
                <unit>KG</unit>
            </measure>
        </measures>
    </item>
    <item>
        <groupIdentification>002</groupIdentification>
        <measures>
            <measure type="piece">
                <value>200</value>
                <unit>PK</unit>
            </measure>
            <measure type="weight">
                <value>200</value>
                <unit>KG</unit>
            </measure>
        </measures>
    </item>
    <item>
        <groupIdentification>001</groupIdentification>
        <measures>
            <measure type="piece">
                <value>300</value>
                <unit>PK</unit>
            </measure>
            <measure type="weight">
                <value>300</value>
                <unit>KG</unit>
            </measure>
        </measures>
    </item>
</goods>

Based on distinct group identification value I want to produce one instance of a <groupedItem>. Within the <groupedItem> I want to refer to the <groupIdentification> (but only one value) and sum up different measures, or any other value, that share the same group Identification.

The target structure I want to achieve therefore is:

<?xml version="1.0" encoding="UTF-8"?>
<goods>
    <groupedItem>
        <groupIdentification>001</groupIdentification>
        <measures>
            <measure type="piece">
                <value>400</value>
                <unit>PK</unit>
            </measure>
            <measure type="weight">
                <value>400</value>
                <unit>KG</unit>
            </measure>
        </measures>
    </groupedItem>
    <groupedItem>
        <groupIdentification>002</groupIdentification>
        <measures>
            <measure type="piece">
                <value>200</value>
                <unit>PK</unit>
            </measure>
            <measure type="weight">
                <value>200</value>
                <unit>KG</unit>
            </measure>
        </measures>
    </groupedItem>
</goods>

Please help me to explain how I can achieve this and what the mechanism is. I somewhat struggle to tell the query to sum things that share the same "grouping element".

Thanks in advance.

EDIT

If I use the following query, I only get 2 groupedItems, but I fail continuing in the lower levels.

xquery version "3.0";
<goods>
{
for $item in goods/item
let $group := $item/groupIdentification
group by $group 
return
<groupedItem>
    {
    for $groupIdentification in goods/item/groupIdentification
    (: this is where I fail to get the connection :)
    return
    <groupIdentification>{ data($groupIdentification) }</groupIdentification>
    }
    (: no need for measure here yet, first need to solve the problem itself :)
</groupedItem>
}
</goods>

I get:

<?xml version="1.0" encoding="UTF-8"?>
<goods>
<groupedItem>
    <groupIdentification>001</groupIdentification><groupIdentification>002</groupIdentification><groupIdentification>001</groupIdentification>
</groupedItem>
<groupedItem>
    <groupIdentification>001</groupIdentification><groupIdentification>002</groupIdentification><groupIdentification>001</groupIdentification>
</groupedItem>
</goods>

Upvotes: 0

Views: 373

Answers (1)

Daniel Haley
Daniel Haley

Reputation: 52858

...but I fail continuing in the lower levels

You need to group a second time. You might also want to group on unit in addition to @type.

Example...

XML Input (modified to introduce a second unit)

<goods>
    <item>
        <groupIdentification>001</groupIdentification>
        <measures>
            <measure type="piece">
                <value>100</value>
                <unit>PK</unit>
            </measure>
            <measure type="weight">
                <value>220</value>
                <unit>LB</unit>
            </measure>
            <measure type="weight">
                <value>100</value>
                <unit>KG</unit>
            </measure>
        </measures>
    </item>
    <item>
        <groupIdentification>002</groupIdentification>
        <measures>
            <measure type="piece">
                <value>200</value>
                <unit>PK</unit>
            </measure>
            <measure type="weight">
                <value>200</value>
                <unit>KG</unit>
            </measure>
        </measures>
    </item>
    <item>
        <groupIdentification>001</groupIdentification>
        <measures>
            <measure type="piece">
                <value>300</value>
                <unit>PK</unit>
            </measure>
            <measure type="weight">
                <value>300</value>
                <unit>KG</unit>
            </measure>
            <measure type="weight">
                <value>661</value>
                <unit>LB</unit>
            </measure>
        </measures>
    </item>
</goods>

XQuery 3.0

xquery version "3.0";
<goods>{
for $item in /goods/item
let $key := $item/groupIdentification
group by $key 
order by $key
return
<groupedItem>
    <groupIdentification>{$key}</groupIdentification>
    <measures>{
    for $measure in $item/measures/measure
    let $type := $measure/@type
    let $unit := $measure/unit
    group by $type,$unit
    order by $type,$unit
    return
        <measure type="{$type}">{
        <value>{sum($measure/value)}</value>,
        <unit>{$unit}</unit>
        }</measure>
    }</measures>
</groupedItem>
}</goods>

Output

<goods>
   <groupedItem>
      <groupIdentification>001</groupIdentification>
      <measures>
         <measure type="piece">
            <value>400</value>
            <unit>PK</unit>
         </measure>
         <measure type="weight">
            <value>400</value>
            <unit>KG</unit>
         </measure>
         <measure type="weight">
            <value>881</value>
            <unit>LB</unit>
         </measure>
      </measures>
   </groupedItem>
   <groupedItem>
      <groupIdentification>002</groupIdentification>
      <measures>
         <measure type="piece">
            <value>200</value>
            <unit>PK</unit>
         </measure>
         <measure type="weight">
            <value>200</value>
            <unit>KG</unit>
         </measure>
      </measures>
   </groupedItem>
</goods>

Upvotes: 1

Related Questions