SQL Academy
Premium

Der HAVING-Operator

Wir haben uns bereits die Query angeschaut, mit der wir den durchschnittlichen Mietpreis pro Unterkunftstyp ermitteln:

MySQL 8.4
SELECT home_type, AVG(price) as avg_price FROM Rooms
GROUP BY home_type
home_typeavg_price
Private room89.4286
Entire home/apt148.6667
Shared room40

Bauen wir die Query so um, dass im Ergebnis nur die Gruppen erscheinen, deren Durchschnittspreis größer als 50 ist.

Aus dem bisherigen Wissen entsteht schnell die Versuchung, dafür WHERE zu verwenden. Beim Versuch, eine solche Query auszuführen, liefert das DBMS aber zwangsläufig einen Fehler und weist darauf hin, dass die Syntax WHERE avg_price > 50 so nicht korrekt ist.

MySQL 8.4
SELECT home_type, AVG(price) as avg_price FROM Rooms
GROUP BY home_type
WHERE avg_price > 50

Vorab so viel: Zum Filtern von Gruppen brauchen wir den Operator HAVING:

MySQL 8.4
SELECT home_type, AVG(price) as avg_price FROM Rooms
GROUP BY home_type
HAVING avg_price > 50
MySQL 8.4
SELECT home_type, AVG(price) as avg_price FROM Rooms
GROUP BY home_type
HAVING AVG(price) > 50
home_typeavg_price
Private room89.4286
Entire home/apt148.6667

Ausführungsreihenfolge einer SQL-Query

Aber warum konnten wir WHERE nicht verwenden und wozu braucht es überhaupt einen eigenen Operator dafür? Die Antwort liegt in der Reihenfolge, in der eine SQL-Query ausgeführt wird.

Schema der Ausführungsreihenfolge einer SQL-Query

Unsere erste Query war falsch, weil wir das Feld avg_price der entstehenden Gruppen schon vor deren Bildung benutzen wollten – WHERE wird nämlich vor der Gruppierung ausgeführt.

WHERE weiss zum Zeitpunkt seiner Ausführung also nichts von der späteren Gruppierung; es arbeitet ausschließlich mit den Datensätzen aus der Tabelle. So können wir damit zum Beispiel die Datensätze der Tabelle Rooms nach Preis filtern, bevor die Gruppierung greift, und erst danach den Durchschnittspreis der Gruppen der übrigen Unterkünfte berechnen:

MySQL 8.4
SELECT home_type, AVG(price) as avg_price FROM Rooms
WHERE price > 50
GROUP BY home_type
home_typeavg_price
Private room96.875
Entire home/apt148.6667

Allgemeine Struktur einer Query mit HAVING

MySQL 8.4
SELECT auswahl_felder
FROM tabellen_name
[WHERE zeilen_bedingung]
GROUP BY gruppierungsfeld [, ...]
HAVING gruppen_bedingung
[ORDER BY sortier_feld];
  • [ ]optionaler Teil
  • ...kann wiederholt werden
auswahl_felder

Was für jede Gruppe ausgegeben wird: Literale, Aggregatfunktionen und Gruppierungsfelder.

tabellen_name
Die Tabelle, aus der die Zeilen kommen.
zeilen_bedingung

Filtert die Zeilen der Tabelle vor der Gruppierung. Aggregatfunktionen kannst du darin nicht verwenden.

Optional
gruppierungsfeld

Die Spalte, nach der die Zeilen in Gruppen aufgeteilt werden. Du kannst mehrere Spalten durch Kommas getrennt angeben.

gruppen_bedingung

Filtert die Gruppen nach der Gruppierung, zum Beispiel COUNT(*) >= 5. Darin kannst du Aggregatfunktionen verwenden.

sortier_feld

Die Spalte oder der Ausdruck, nach dem das Ergebnis sortiert wird.

Optional

Anwendungsbeispiel für HAVING

Ermitteln wir als Beispiel den Mindestpreis pro Unterkunftstyp mit Fernseher. Uns interessieren dabei nur Unterkunftstypen, zu denen mindestens 5 Wohnungen gehören.

Um zu diesem Ergebnis zu kommen, müssen wir:

  • zuerst alle Daten aus der Tabelle holen

    MySQL 8.4
    SELECT ... FROM Rooms;
    
  • dann aus allen Datensätzen der Tabelle Rooms nur die uns interessierenden auswählen, also nur Unterkünfte mit Fernseher

    MySQL 8.4
    SELECT ... FROM Rooms
    WHERE has_tv = true
    
  • anschließend die Datensätze der Unterkünfte nach Typ gruppieren

    MySQL 8.4
    SELECT ... FROM Rooms
    WHERE has_tv = true
    GROUP BY home_type
    
  • danach die entstandenen Gruppen nach unserer Bedingung filtern. Uns interessieren Gruppen mit mindestens 5 Vertretern

    MySQL 8.4
    SELECT ... FROM Rooms
    WHERE has_tv = true
    GROUP BY home_type
    HAVING COUNT(*) >= 5
    
  • und zum Schluss schauen, was in der Aufgabe verlangt ist, und die nötigen Felder ausgeben. In unserem Fall brauchen wir den Namen des Unterkunftstyps und seinen Mindestpreis.

    MySQL 8.4
    SELECT home_type, MIN(price) as min_price FROM Rooms
    WHERE has_tv = true
    GROUP BY home_type
    HAVING COUNT(*) >= 5;