XQuery / XQuery 3.0: Gruppierungen mit group by

XQuery 3.0: Gruppierungen mit group by

XQuery 3.0: Gruppierungen mit group by

➪ In XQuery 3.0 sind mit group by auch Gruppierungen möglich.

Analog zu können Sie auch in XQuery einen Gruppierungsschlüssel individuell zusammenstellen.


xquery version "3.0";
<ergebnis>
  {
    for $m in //Mensch
    let $gehalt := xs:decimal($m/Gehalt/text())
    let $status := if ($gehalt > 5000 ) 
                   then ('reich') 
                   else if ($gehalt <= 5000 and $gehalt > 1000 ) 
                   then ('wohlhabend') 
                   else ('normal')    
    group by $status
    return
      <Kunde status="{$status}">
        {
          for $kk in $m
          order by $kk/Gehalt/text() descending
          return
          <k NN="{$kk/name/text()}" 
             VN="{$kk/vorname/text()}"
             EK="{$kk/Gehalt/text()}" 
             WO="{$kk/../name/text()}"/>            
        }
      </Kunde>
  }
</ergebnis>

Das Ergebnis können Sie hier sehen:


<ergebnis>
  <Kunde status="normal">
   <k NN="Sorglos" VN="Siggi" EK="987.58" WO="Neustadt"/>
   <k NN="Sinnlos" VN="Simone" EK="876.54" WO="Darmstadt"/>
   <k NN="Wertlos" VN="Werner" EK="777.77" WO="Darmstadt"/>
   <k NN="Herzlos" VN="Heini" EK="654.21" WO="Neustadt"/>
   <k NN="Hirnlos" VN="Horst" EK="546.77" WO="Darmstadt"/>
   <k NN="Kolos" VN="Karl" EK="456" WO="Darmstadt"/>
   <k NN="Rielos" VN="Lotte" EK="456" WO="Kapstadt"/>
   <k NN="Lustlos" VN="Ludwig" EK="357" WO="Darmstadt"/>
   <k NN="Rhodos" VN="Rudi" EK="333.33" WO="Darmstadt"/>
   <k NN="Sagblos" VN="Stefan" EK="321.45" WO="Neustadt"/>
   <k NN="Schlaflos" VN="Susi" EK="321" WO="Kapstadt"/>
   <k NN="Holzflos" VN="Hugo" EK="234.56" WO="Neustadt"/>
   <k NN="Ruhelos" VN="Rita" EK="234" WO="Kapstadt"/>
   <k NN="Muehelos" VN="Martin" EK="222" WO="Kapstadt"/>
   <k NN="Leinenlos" VN="Liane" EK="135" WO="Kapstadt"/>
  </Kunde>
  <Kunde status="wohlhabend">
   <k NN="Bodenlos" VN="Betty" EK="3450" WO="Kapstadt"/>
   <k NN="Nixlos" VN="Nicole" EK="1234.56" WO="Neustadt"/>
  </Kunde>
  <Kunde status="reich">
   <k NN="Wasistlos" VN="Willi" EK="6789" WO="Kapstadt"/>
   <k NN="Sprachlos" VN="Stefan" EK="5430" WO="Neustadt"/>
  </Kunde>
</ergebnis

Das Type-Casting auf xs:decimal zur exakten Zahlenberechnung lohnt sich auch in XQuery 3.0, wie das folgende Beispiel zeigt.


xquery version "3.0";
<ergebnis>  {
    for $k in //Kauf
    let $artikel := $k/bez/text()
    group by $artikel
    return
      <artikel
        name="{$artikel}">
        {
          for $kk in $k
          return
          <einkauf 
            anzahl="{$kk/anzahl}" 
            einzelpreis="{$kk/preis}" 
            gesamt="{$kk/Gesamt}" 
            gesamt2="{$kk/anzahl * $kk/preis}" 
            gesamt3="{
                 xs:decimal($kk/anzahl) 
                 * xs:decimal($kk/preis)
           }"/>            
        }
      </artikel>
  }</ergebnis>

pic/foreachgroup.png

Das Ergebnis haben Sie zur besseren Übersicht auf einige wenige Resultate verkürzt. Das Gesamt-Attribut entstammt der Datenquelle, deren ursprünglicher Wert per Datenbankabfrage ermittelt wurde ("SELECT anzahl*preis as Gesamt ..."). Das gesamt2-Attribut arbeitet offenbar mit einem internen Double-Type-Cast, kommt aber zu einem anderen Ergebnis als die Datenbankabfrage. Erst das gesamt3-Attribut ermittelt durch den Type-Cast auf xs:decimal den korrekten Wert.


<?xml version="1.0" encoding="UTF-8"?>
<ergebnis>
   <artikel name="Hemd">
      <einkauf anzahl="11"
               einzelpreis="12.99"
               gesamt="142.89000000000002"
               gesamt2="142.89000000000001"
               gesamt3="142.89"/>
      <einkauf anzahl="22"
               einzelpreis="12.99"
               gesamt="285.78000000000003"
               gesamt2="285.78000000000003"
               gesamt3="285.78"/>
      <einkauf anzahl="44"
               einzelpreis="12.99"
               gesamt="571.56000000000006"
               gesamt2="571.5600000000001"
               gesamt3="571.56"/>
      ...
   </artikel>
   <artikel name="Hose">
      <einkauf anzahl="8"
               einzelpreis="25.99"
               gesamt="207.92"
               gesamt2="207.92"
               gesamt3="207.92"/>
      ...
   </artikel>
   <artikel name="Schuhe">
      <einkauf anzahl="6"
               einzelpreis="151.23"
               gesamt="907.37999999999988"
               gesamt2="907.3799999999999"
               gesamt3="907.38"/>
      ...
   </artikel>
</ergebnis>

Statt group by können Sie auch mit und distinct-values arbeiten. $k beinhaltet in diesem Fall die gruppierte Liste ("Hemd", "Hose", "Schuhe").


xquery version "3.0";
<ergebnis>
  {
    for $k in
      for-each(
        distinct-values(//Kauf/bez/text()),
        function ($pk) {$pk}
      )
    return
      <artikel
        name="{$k}">
        {
          for $kk in //Kauf[bez/text() = $k]
          return
            <einkauf
              anzahl="{$kk/anzahl}"
              einzelpreis="{$kk/preis}"
              gesamt3="{
                  xs:decimal($kk/anzahl)
                  * xs:decimal($kk/preis)
                }"/>
        }
      </artikel>
  }
</ergebnis>

Analog zu , ist eine vereinfachte Gruppierung auch in XQuery möglich.


<ergebnis>
{
  for $a in //Kauf[not(bez = following::Kauf/bez)]
  return
  <artikel name="{$a/bez/text()}"/>
}
</ergebnis>

Der Vorteil dieses Ansatzes ist auch hier, dass der Zugriff auf den XML-Input nicht verloren geht: Nachdem Sie bez in der Variable vbez gesichert haben, können Sie sie auch in for $b in //Kauf[bez/text() = $vbez] verwenden.


xquery version "1.0";
<ergebnis>
  {
    for $a in //Kauf[not(bez/text() = following::Kauf/bez/text())]
    let $vbez := $a/bez/text()
    return
      <artikel name="{$vbez}">
        {
          for $b in //Kauf[bez/text() = $vbez]
          return
            <einzelkauf>
              {
                for $c in $b/child::*
                return
                  attribute {$c/name()} {$c/text()}
              }
            </einzelkauf>
        }
      </artikel>
  }
</ergebnis>

wg / 15. September 2018



Fragen? Anmerkungen? Tipps?

Bitte nehmen Sie Kontakt zu mir auf.






Vielen Dank für Ihr Interesse an meiner Arbeit.


V.i.S.d.P.: Wilfried Grupe * Klus 6 * 37643 Negenborn

☎ 0151. 750 360 61 * eMail: info10@wilfried-grupe.de

www.wilfried-grupe.de/XQuery18.html