Die Kategorisierung von Daten ist ein häufiges Ziel für Auswertungen und Datawarehouse-Abfragen. Dabei werden oft GROUP BY Klausel und sogenannte Gruppen- oder Aggregatfunktionen verwendet, um die Wertemengen zu bearbeiten. Solche Funktionen sind COUNT, MIN, MAX, SUM, AVG usw..
Mehrere GROUP BY Klausel in eine SQL-Abfrage
Es kann sehr vorteilhaft sein, wenn eine einzige Abfrage alle gewünschten Ergebnisse liefert. Diese kann z.B. einfach als externe SQL-Abfrage in MS-Excel hinterlegt werden. Wertvolle Ad-hoc-Berichte können so schnell und einfach implementiert werden, ohne dass zusätzliche Kosten für die Entwicklung einer Benutzeroberfläche anfallen, um die Ergebnisse entsprechend aufzubereiten, zu sammeln und darzustellen.
Was aber, wenn die Ergebnisse mehrerer Kategorien gleichzeitig angezeigt werden sollen? Wie kann man mehrere GROUP BY-Klauseln in einer SQL-Abfrage implementieren?
Ein Praxisbeispiel:
Eine Datenbanktabelle beinhaltet einzelne Verkaufsabschlüsse - mit Datum und Gesamtwert der Einzelauftrag.
Um eine zukünftige Rabattaktion besser verfolgen zu können, möchte die Geschäftsführung die Verkaufsabschlüsse in 2 Wertebereiche kategorisieren und der Anzahl Abschlüsse sowie der Umsatzanteil pro Kategorie pro Kalenderwoche auflisten:
Kalenderwoche: | Anzahl Abschlüsse < €1000 |
Umsatzanteil % Abschlüsse< €1000 |
Anzahl Abschlüsse >= €1000 |
Umsatzanteil % Abschlüsse>= €1000 |
45 | 3 | 9,59 | 1 | 8,76 |
46 | 2 | 1,66 | 2 | 38,37 |
47 | 4 | 24,10 | 1 | 17,52 |
Die Ergebnisse für eine Kategorie sind per SQL relativ leicht zu ermitteln:
--Kategorie <€1000
SELECT
DATEPART(week, datum) AS Kalenderwoche,
COUNT(*) AS "Anz. Abschlüsse <€1000",
SUM(umsatz)*100/(SELECT SUM(umsatz) FROM DBAbschlusse) AS 'Umsatzanteil % Abschlüsse<€1000'
FROM DBAbschlusse WHERE Umsatz < 1000
GROUP BY DATEPART(week, datum);
--Kategorie >=€1000
SELECT
DATEPART(week, datum) AS Kalenderwoche,
COUNT(*) AS "Anz. Abschlüsse >=€1000",
SUM(umsatz)*100/(SELECT SUM(umsatz) FROM DBAbschlusse) AS 'Umsatzanteil % Abschlüsse>=€1000'
FROM DBAbschlusse WHERE Umsatz >= 1000
GROUP BY DATEPART(week, datum);
Aber wie können mehrere Wertebereiche in einer SQL-Abfrage vereint werden?
Hier ist eine Lösung:
SELECT
DATEPART(week, datum) AS Kalenderwoche,
SUM(anzkat1) AS "Anz. Abschlüsse <€1000",
SUM(umskat1)*100/(s.gesamtumsatz) AS "Umsatzanteil % Abschlüsse<€1000",
SUM(anzkat2) AS "Anz. Abschlüsse >=€1000",
SUM(umskat2)*100/(s.gesamtumsatz) AS "Umsatzanteil % Abschlüsse>=€1000"
FROM
(
SELECT datum,
CASE WHEN Umsatz < 1000 THEN 1 ELSE 0 END AS anzkat1,
CASE WHEN Umsatz < 1000 THEN umsatz ELSE 0 END AS umskat1,
CASE WHEN Umsatz >= 1000 THEN 1 ELSE 0 END AS anzkat2,
CASE WHEN Umsatz >= 1000 THEN umsatz ELSE 0 END AS umskat2
FROM DBAbschlusse
) t,
(
SELECT SUM(umsatz) AS gesamtumsatz FROM DBAbschlusse
) s
GROUP BY gesamtumsatz, DATEPART(week, datum);
Die obere Syntax funktioniert für MS-SQL-Server
- Für Oracle, muss DATEPART(week, Datum) durch TO_CHAR(Datum, 'IW') ersetzt werden.
- Für PostgreSQL muss DATEPART(week, Datum) durch DATE_PART('week', datum) ersetzt werden.