Bietet Rezepte, Lösungen und ausführliche Beispiele rund um gesundes SQL und zufriedene Datenbanken.
Top-Ten Listen und Statistische Auswertungen werden häufig benötigt. Zum Einen werden dafür Gruppierungen benötigt, zum anderen müssen "vertikale" Ergebnisse nebeneinander, also "horizontal" dargestellt werden. Diese Anforderung widerspricht eigentlich den üblichen Prinzipien von SQL, aber trotzdem will der Chef, der Controller und der VB (Vertriebsbeauftragte) seine gewohnte Auswertung. Also an's Werk...
* MySQL 5.1.30
Die Datenbank-Tabellen hierfür sehen wie folgt aus:
/*** Kunden*/CREATE TABLE kunde (id INT NOT NULL,name VARCHAR(30) NOT NULL,plz INT NOT NULL,PRIMARY KEY (id));/*** Rechnungen*/CREATE TABLE rechnung (id INT NOT NULL,kunde_id INT NOT NULL,datum DATE NOT NULL,betrag DEC(10,2) NOT NULL,PRIMARY KEY (id),CONSTRAINT fk_rechnung_01FOREIGN KEY (kunde_id)REFERENCES kunde (id));Nun noch die Testdaten für die nachfolgenden SQL-Abfragen.
/*** Kunden*/INSERT INTO kunde VALUES( 1, 'Kunde-1', 20000),( 2, 'Kunde-2', 30000),( 3, 'Kunde-3', 40000);/*** Rechnungen*/INSERT INTO rechnung VALUES( 1, 1, '2010-01-01', 100),( 2, 1, '2010-02-01', 500),( 3, 2, '2010-03-01', 200),( 4, 1, '2010-02-01', 100),( 5, 1, '2010-05-01', 400),( 6, 1, '2010-02-01', 500),( 7, 3, '2010-01-01', 200),( 8, 1, '2010-03-01', 200),( 9, 2, '2010-02-01', 100),(10, 3, '2010-06-01', 500),(11, 1, '2010-04-01', 500),(12, 3, '2010-07-01', 200),(13, 1, '2010-06-01', 200),(14, 2, '2010-04-01', 100),(15, 3, '2010-03-01', 500);Der Chef möchte seine Top Kunden. Also diese mit dem höchsten Umsatz im laufenden Jahr. Der Umsatz pro Kunde wird errechnet mit SUM(r.betrag). Die Spalte erhält nun den Namen "umsatz". Die Sortierung ist absteigend (DESC), folglich steht der Kunde mit dem höchsten Umsatz oben.
/*** TOP Kunden*/SELECT r.kunde_id, MAX(k.name) AS name, SUM(r.betrag) AS umsatzFROM rechnung rJOIN kunde kON k.id = r.kunde_idWHERE r.datum BETWEEN '2010-01-01' AND '2010-12-31'GROUP BY r.kunde_idORDER BY SUM(r.betrag) DESC;+----------+---------+---------+| kunde_id | name | umsatz |+----------+---------+---------+| 1 | Kunde-1 | 2500.00 || 3 | Kunde-3 | 1400.00 || 2 | Kunde-2 | 400.00 |+----------+---------+---------+3 rows in set (0.00 sec)Als kleine Variante zur obigen Abfrage, erfolgt hier die Sortierung direkt mit Hilfe der Spalte "umsatz" und nicht mehr nach der Summenberechnung "SUM(r.betrag)".
/*** TOP Kunden*/SELECT r.kunde_id, MAX(k.name) AS name, SUM(r.betrag) AS umsatzFROM rechnung rJOIN kunde kON k.id = r.kunde_idWHERE r.datum BETWEEN '2010-01-01' AND '2010-12-31'GROUP BY r.kunde_idORDER BY umsatz DESC;+----------+---------+---------+| kunde_id | name | umsatz |+----------+---------+---------+| 1 | Kunde-1 | 2500.00 || 3 | Kunde-3 | 1400.00 || 2 | Kunde-2 | 400.00 |+----------+---------+---------+3 rows in set (0.00 sec)Der Controller möchte seine Quartalsauswertung, soll er bekommen. Für uns natürlich kein Problem. Mit Hilfe des CASE Befehls erzeugen wir vier Spalten mit der Quartalszuordnung und summieren die Beträge.
/*** Quartalauswertung des Umsatzes*/SELECT SUM( CASEWHEN r.datum BETWEEN '2010-01-01' AND '2010-03-31' THEN r.betragEND) AS '1.Quartal',SUM( CASEWHEN r.datum BETWEEN '2010-04-01' AND '2010-06-30' THEN r.betragEND) AS '2.Quartal',SUM( CASEWHEN r.datum BETWEEN '2010-07-01' AND '2010-09-30' THEN r.betragEND) AS '3.Quartal',SUM( CASEWHEN r.datum BETWEEN '2010-10-01' AND '2010-12-31' THEN r.betragEND) AS '4.Quartal'FROM rechnung rWHERE r.datum BETWEEN '2010-01-01' AND '2010-12-31';+-----------+-----------+-----------+-----------+| 1.Quartal | 2.Quartal | 3.Quartal | 4.Quartal |+-----------+-----------+-----------+-----------+| 2400.00 | 1700.00 | 200.00 | NULL |+-----------+-----------+-----------+-----------+1 row in set (0.00 sec)Der VB benötigt eine Darstellung der umsatzstärksten Regionen nach Postleitzahl (plz) sortiert. Da wir nun richtig in Fahrt sind, ist auch dies keine echte Herausforderung mehr.
/*** Quartalauswertung der umsatzstärksten Regionen*/SELECT k.plz,SUM(r.betrag) AS umsatz,SUM( CASEWHEN r.datum BETWEEN '2010-01-01' AND '2010-03-31' THEN r.betragEND) AS '1.Quartal',SUM( CASEWHEN r.datum BETWEEN '2010-04-01' AND '2010-06-30' THEN r.betragEND) AS '2.Quartal',SUM( CASEWHEN r.datum BETWEEN '2010-07-01' AND '2010-09-30' THEN r.betragEND) AS '3.Quartal',SUM( CASEWHEN r.datum BETWEEN '2010-10-01' AND '2010-12-31' THEN r.betragEND) AS '4.Quartal'FROM rechnung rJOIN kunde kON k.id = r.kunde_idWHERE r.datum BETWEEN '2010-01-01' AND '2010-12-31'GROUP BY k.plzORDER BY umsatz;+-------+---------+-----------+-----------+-----------+-----------+| plz | umsatz | 1.Quartal | 2.Quartal | 3.Quartal | 4.Quartal |+-------+---------+-----------+-----------+-----------+-----------+| 30000 | 400.00 | 300.00 | 100.00 | NULL | NULL || 40000 | 1400.00 | 700.00 | 500.00 | 200.00 | NULL || 20000 | 2500.00 | 1400.00 | 1100.00 | NULL | NULL |+-------+---------+-----------+-----------+-----------+-----------+3 rows in set (0.00 sec)Mit Hilfe von GROUP BY, SUM und CASE lassen sich mit wenig Aufwand einfache, Pivot-ähnliche Auswertungen erzeugen. Damit können echte OLAP Funktionen nicht ersetzt werden, aber auf die schnelle so eine Liste zu erstellen, sollte nun kein Problem mehr sein.