|
Daten zusammenfassen mit Aggregatsfunktionen
| Erscheinungsmonat |
APEX-Version |
Datenbankversion |
| April 2012 |
alle |
ab 9.2 |
Die Verwendung von Berichten und damit von SQL-Abfragen aller Art ist
für den APEX-Entwickler alltäglich. Das Zusammenfassen von Daten mit Hilfe
von Aggregatsfunktionen wie AVG, SUM, MIN oder MAX ist dabei nichts Besonderes.
Dieser Tipp stellt verschiedene Aggregatsfunktionen und deren Anwendung in
SQL-Abfragen vor. Wir beginnen mit einfachen GROUP BY-Varianten, leiten über
zu weniger bekannten Funktionen wie der linearen Regression und schließen
mit einem Abschnitt über analytische Funktionen,
also solchen, bei denen das "Datenfenster"
zur Anwendung der Aggregatsfunktion dynamisch definiert werden kann.
Die Beispiele gehen von folgender Tabelle aus. Das SQL-Skript
verkauf.sql
legt die Tabelle in Ihrem Datenbankschema an.
GROUP BY und mehr ...
Wir beginnen mit einem sehr einfachen Beispiel. Für jedes Jahr
soll die Summe, der Durchschnitt, der minimale und der maximale
Umsatz (Spalte UMSATZ_EUR) ermittelt werden. Das erledigt eine
ganz normale SQL-Abfrage mit Aggregatsfunktion und GROUP BY.
So weit, so gut. Allerdings erlaubt GROUP BY wesentlich mehr als nur das: Mit
der Erweiterung ROLLUP wird der Ergebnismenge ein Aggregat "über alles" hinzugefügt.
Ohne ROLLUP bräuchte es hierfür eine zusätzliche SQL-Abfrage, deren Ergebnisse
mit UNION ALL angefügt werden. Im Vergleich dazu ist diese Variante wesentlich effizienter;
gerade auf großen Datenmengen. Nimmt man auch
die Spalte MONAT in die ROLLUP-Klausel, so bekommt man die Zeilen
selbst, Aggregate für das einzelne Jahr und "über alles".
Es ist auch möglich, nur die Zwischenaggregate pro Jahr zu berechnen und das
Aggregat über alles zu unterdrücken. Dazu braucht es aber die Klausel GROUPING SETS: Mit
dieser können Sie gewünschten Gruppen explizit anfordern. GROUP BY ROLLUP (JAHR, MONAT) bedeutet das gleiche wie
GROUP BY GROUPING SETS (JAHR, MONAT), (JAHR), (). Wir brauchen
ein GROUPING SET pro Monat (JAHR, MONAT) und eins pro Jahr (JAHR).
Die Gruppe "über alles" () brauchen wir nicht.
Liegen noch mehr "Dimensionsspalten" vor, so lassen sich mit ROLLUP und
den anderen GROUP BY-Klauseln CUBE und GROUPING SETS Aggregate für alle
möglichen Spaltenkombinationen berechnen. Mehr dazu und weiterführende Links finden Sie in der
Oracle-Dokumentation: SQL Language Reference.
Weitere Aggregatsfunktionen
Die verwendeten Aggregatsfunktionen SUM, AVG, MIN und MAX sind sicherlich
die am häufigsten verwendeten. Aber die Oracle-Datenbank bietet noch mehr an: Im folgenden
sind zwei Beispiele vorgestellt ...
Ab Oracle11g Release 2 können Zeichenketten mit der LISTAGG-Funktion zusammengefasst werden;
das ist ein für den Entwickler sehr nützliches und häufig benötigtes Feature.
Die Funktionen zur einfachen linearen Regression zeigen, wie mächtig der
Standardumfang der Datenbank bereits ist. Sie ermitteln den absoluten Betrag und
die Steigung einer linearen Funktion, die anhand der Daten mit der "Methode der
kleinsten Quadrate" gebildet wurde.
Die Regressionsfunktion für den Umsatz anhand der Ausgaben für TV-Werbung lautet also:
Und natürlich kann dies - direkt in der gleichen SQL-Abfrage - auch angewendet werden.
So macht das folgende Beispiel (anhand des Regressionsmodells) eine Prognose
für den Umsatz bei Ausgaben von 200.000 für TV-Werbung.
Abbildung 1 zeigt die Anwendung dieser SQL-Funktion im Zusammenspiel mit einem
APEX-Diagramm. Die grüne Kurve stellt das Ergebnis der angewendeten Regressionsfunktion dar. Liegen
konkrete Zahlen für den Umsatz vor, so kann man die "Prognose" mit den tatsächlichen Daten
vergleichen. Neben REGR_SLOPE und REGR_INTERCEPT stehen noch andere SQL-Funktionen zur Verfügung, mit
denen unter anderem statistische Werte zur Güte der gefundenen Funktion abgerufen werden können.
Abbildung 1: Regressionsfunktionen in einer APEX-Anwendung
In der
Oracle Dokumentation - SQL Language Reference finden Sie
eine vollständige Übersicht über die vorhandenen Aggregatsfunktionen.
Eigene Aggregatsfunktionen erstellen
Wie in der Dokumentation erkennbar ist, stellt die
Datenbank eine ganze Menge Aggregatsfunktionenen bereit - aber es fehlt auch was: So gibt es keine Aggregatsfunktion
für das "Produkt". Man könnte sich nun zwar eine einfache PL/SQL-Funktion schreiben, die wäre aber nicht in jeder SQL-Abfrage
im Zusammenspiel mit GROUP BY nutzbar. Doch auch hier bietet die Oracle-Datenbank Abhilfe: Hält man sich an ein
bestimmtes Programmierschema, so kann man sich eigene Aggregatsfunktionen bauen - und diese Aggregatsfunktionen
können genauso genutzt werden, wie die eingebauten Pendants. Das Programmierschema ist im kaum bekannten, aber
dafür hochinteressanten Handbuch
Data Cartridge Developers' Guide beschrieben. Einige fertige Implementierungen
für benutzerdefinierte Aggregatsfunktionen finden Sie im Blog
von Thomas Uhren und
im Blog SQL und PL/SQL in Oracle.
Hat man, zum Beispiel, die Aggregatsfunktion AGG_PRODUCT eingespielt, so lässt sich diese ganz normal mit
GROUP BY nutzen. Auch die beschriebenen GROUP BY-Klauseln ROLLUP, GROUPING SETS und CUBE können verwendet werden.
Basiernd darauf ließen sich bspw. viele Kennzahlen aus der Finanzmathematik
recht einfach in benutzerdefinierte Aggregatsfunktionen überführen.
Dynamische Aggregatsfenster: Analytische Funktionen
Das mit der GROUP-BY-Klausel definierte "Fenster", über welches die Aggregate gebildet werden,
ist eher statischer Natür: Zur Abfragezeit werden die Daten in feste Abschnitte, eben die Gruppen,
aufgeteilt. Manche Aufgaben, wie das Berechnen eines gleitenden Durchschnitts, erfordern jedoch
mehr Möglichkeiten:
Hier helfen die analytischen Varianten weiter - jede Aggregatsfunktion steht in einer analytischen
Variante bereit - und darüber hinaus gibt es noch zusätzliche analytische Funktionen. Eine vollständige
Übersicht findet sich wiederum in der
Oracle Dokumentation.
Ein wichtiges Merkmal der analytischen Funktionen ist, dass die Aggregate für jede Zeile
der Ergebnismenge
berechnet werden - im Gegensatz zu den "klassischen" Aggregatsfunktionen, welche das Aggregat nur einmal
pro Gruppe ausrechnen und für jede Gruppe nur noch eine Zeile ausgeben.
Allen analytischen Funktionen ist die Klausel OVER gemein - in dieser wird das Aggregats-"Fenster"
definiert (analytische Funktionen werden manchmal auch als Window-Funktionen) bezeichnet. Die OVER-Klausel
besteht wiederum aus drei Teilen:
- Mit PARTITION BY werden die Daten in Gruppen unterteilt. Dies ähnelt sehr stark dem klassischen GROUP BY
- Mit ROWS BETWEEN wird das Aggregatsfenster über eine bestimmte Menge an Zeilen,
ausgehend vom "über die Ergebnismenge laufenden Cursor" gebildet.
- Mit ORDER BY wird die Sortierung innerhalb des Aggregatfensters festgelegt.
Diese doch eher theoretischen Beschreibungen werden nun anhand eines Beispiels deutlich gemacht. Über die Umsatzzahlen
(UMSATZ_EUR) der Tabelle VERKAUF soll ein gleitender Durchschnitt gebildet werden. Die Periode soll dabei
drei Monate sein - achten Sie auf das ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING. Diese Klausel legt fest, dass
das Aggregatsfenster für jede Zeile immer von der Zeile davor bis zur Zeile danach gehen soll. Eine solche
Klausel erfordert natürlich eine Sortierung - das wird mit dem ORDER BY innerhalb der OVER-Klausel erledigt.
Analog dazu bilden wir die laufende Summe - für jedes Jahr sollen die Umsatzzahlen fortlaufend aufsummiert werden;
allerdings soll die Summierung im neuen Jahr neu beginnen. Dazu benötigen wir alle drei Elemente der OVER-Klausel
wie folgt.
Zunächst werden die Daten mit der PARTITION BY-Klausel nach Jahren gruppiert. Jede Gruppe wird
intern nach dem Monat sortiert und das "Aggregatsfenster" läuft vom Anfang (UNBOUNDED PRECEDING)
bis zur aktuellen Zeile.
Für häufige Aufgabenstellungen gibt es eigene analytische Funktionen. So berechnet
RATIO_TO_REPORT für jede Zeile den prozentualen Anteil an der Gesamtmenge. Angewendet auf das
Umsatzbeispiel sähe die Abfrage wie folgt aus:
Analytische Funktionen lassen sich auch mit den klassichen Pendants kombinieren. So wäre es
nett, wenn diesem Bericht noch eine Zeile mit den Summen für das jeweilige Jahr hinzugefügt
würde. Das geht mit der am Anfang besprochenen Funktion ROLLUP.
Hätten Sie vorher gedacht, dass ein solcher Report nur mit SQL möglich ist oder hätten Sie
eine PL/SQL Table Function geschrieben ...?
Fazit
Aggregatsfunktionen sind in der Oracle Datenbank mehr als nur einfaches SUM, AVG und GROUP BY. Mit
den GROUP BY-Klauseln ROLLUP, CUBE und GROUPING SETS lassen sich sehr elegant zusätzliche Aggregate
entlang der vorhandenen "Dimensionen" berechnen. Analytische Funktionen erlauben das sehr flexible
Bilden von Aggregatsfenstern. Und wenn das alles nicht reicht, können sogar eigene Aggregatsfunktionen
erstellt werden. Besser geht es eigentlich nicht.
Zurück zur Community-Seite
|