Zurück zur Artikelliste Artikel
11 Leseminuten

Was ist der Unterschied zwischen WHERE- und HAVING-Klauseln in SQL?

Da die Datenmenge in der Welt von Tag zu Tag wächst, steigt der Bedarf an einer effizienten Verwaltung und Abfrage von Daten. SQL bietet Möglichkeiten zur Manipulation und Abfrage von Daten in jeder Größenordnung. Ein wichtiger Teil davon sind die WHERE- und HAVING-Klauseln, mit denen Sie Daten nach Bedarf filtern können, aber sie sind nicht dasselbe. Wir werden die Unterschiede zwischen ihnen im Detail erklären.

Eine der häufigsten Aufgaben bei der Bearbeitung und Abfrage von Daten ist das Filtern mithilfe der Klauseln WHERE und HAVING. Obwohl beide Klauseln Daten auf der Grundlage von benutzerdefinierten Bedingungen und/oder Funktionen filtern, gibt es wichtige Unterschiede in der Art und Weise, wie jede Klausel ausgeführt wird.

In diesem Artikel wird ausführlich erläutert, wann WHERE oder HAVING verwendet werden sollte. Wir werden kurz den logischen Ablauf einer SQL-Abfrage erläutern, die die Klauseln WHERE und/oder HAVING enthält, und anschließend einige praktische Szenarien und Beispiele vorstellen, die wir gemeinsam lösen können.

Logischer Ablauf von Abfragen mit WHERE und HAVING

Die Reihenfolge, in der Sie eine SQL-Abfrage schreiben, unterscheidet sich von der Reihenfolge der Ausführung. Betrachten wir das Folgende als Beispiel:

SELECT country_id, city, MIN(salary), MAX(salary) 
FROM hr.emp_details_view
WHERE country_id IN ('US', 'UK')
GROUP BY country_id, city
HAVING MIN(salary) < 15000
ORDER BY country_id; 

Der logische Ablauf einer SQL-Abfrage ist in der folgenden Abbildung dargestellt.

Reihenfolge der Ausführung in SQL-Abfragen

Abbildung 1: Reihenfolge der Ausführung von SQL-Abfragen.


  1. Die logische Verarbeitung einer SQL-Abfrage beginnt mit einer FROM -Anweisung, die Daten aus den in der Abfrage aufgeführten Tabellen sammelt. Sie kann auch eine JOIN Klausel enthalten, die zwei oder mehr Tabellen mit dem ON Operator kombiniert.

    Beachten Sie, dass die in der WHERE Klausel verwendeten Bedingungen auch im ON Operator der JOIN Klausel verwendet werden können. Ebenso können die Tabellen, die mit den Bedingungen des ON -Operators der JOIN -Klausel kombiniert wurden, in der WHERE -Klausel verwendet werden. Sie sollten jedoch eine WHERE nur für Bedingungen verwenden, die einzelne Zeilen filtern. Dies verbessert die Lesbarkeit der Abfrage und ermöglicht es dem ON Operator, nur die Kombination der Tabellen zu verarbeiten, was sein Zweck ist.

  2. Der nächste Schritt im logischen Ablauf ist die WHERE Klausel, die die Datensätze auf diejenigen filtert, die die benutzerdefinierte(n) Bedingung(en) und/oder Funktion(en) erfüllen, und diese weitergibt.
  3. Auf die WHERE -Klausel folgt die GROUP BY -Klausel, die die von der WHERE -Bedingung erhaltenen Datensätze gruppiert. Die in der GROUP BY -Klausel aufgelistete(n) Spalte(n) können beispielsweise die Mannschaften sein, und andere Spalten werden durch die Aggregatfunktion(en) aggregiert und den entsprechenden Gruppen/Teams zugeordnet.
  4. Als nächstes folgt die Klausel HAVING, die nicht einzelne Datensätze, sondern die in GROUP BY erstellten Gruppen filtert.
  5. An diesem Punkt geht die logische Verarbeitung an den Befehl SELECT. Er wertet aus, welche Spalten an die Ausgabe gesendet werden sollen. Er wertet auch alle Schlüsselwörter wie UNIQUE, DISTINCT und TOP aus, falls sie enthalten sind.
  6. Die Klausel ORDER BY wird am Ende des logischen Ablaufs ausgeführt. Sie sortiert die Daten nach der/den in ihr angegebenen Spalte(n) und standardmäßig in aufsteigender Reihenfolge.

Zunächst zu den Essentials: Bedingungen in WHERE und HAVING spezifizieren

Es gibt eine ganze Reihe von Operatoren, mit denen wir Bedingungen in WHERE und HAVING Klauseln erstellen und kombinieren können:

  • Vergleichszeichen: <, >, <=, >=, =, <>
  • Nullwertprüfung: IS NULL, IS NOT NULL
  • Wildcards: LIKE, '%=_'
  • Bereichsprüfung: BETWEEN
  • Prüfung des Vorhandenseins in einer Menge: IN
  • Existenzprüfung: EXISTS
  • Quantifizierte Vergleichszeichen: ALL, ANY, SOME
  • logische Kombination der Bedingungen: AND, OR, NOT

Die Operanden in einer WHERE -Klausel können die in SELECT aufgeführten Spalten umfassen, mit Ausnahme der in Aggregatfunktionen verwendeten Spalten. Im Gegensatz dazu filtert HAVING nach den Ergebniswerten der Aggregatfunktion, wie z. B. SUM(), COUNT(), und AVG(), unter anderem.

Beispiele

Die Tabellen employee und emp_details_viewwerden in den folgenden Beispielen teilweise verwendet.

SELECT * 
FROM hr.employees;
EMPLOYEE_IDLAST_NAMEMANAGER_IDHIRE_DATESALARYJOB_ID
101Kochhar10021-SEP-0517000AD_VP
102De Haan10013-JAN-0117000AD_VP
108Greenberg10117-AUG-0212008FI_MGR
103Hunold10203-JAN-069000IT_PROG
105Austin10325-JUN-054800IT_PROG
116Baida11424-DEC-052900PU_CLERK
117Tobias11424-JUL-052800PU_CLERK
145Russell10001-OCT-0414000SA_MAN
148Cambrault10015-OCT-0711000SA_MAN
SELECT * 
FROM hr.emp_details_view;
EMPLOYEE_IDLAST_NAMEFIRST_NAMESALARYDEPARTMENT_IDCOUNTRY_IDCITYLOCATION_ID
103HunoldAlexander900060USSouthlake1400
105AustinDavid480060USSouthlake1400
101KochharNeena1700090USSeattle1700
102De HaanLex1700090USSeattle1700
108GreenbergNancy12008100USSeattle1700
116BaidaShelli290030USSeattle1700
117TobiasSigal280030USSeattle1700
145RussellJohn1400080UKOxford2500
148CambraultGerald1100080UKOxford2500

Szenario I: Die WHERE-Klausel

Die Klausel WHERE wird verwendet, um einzelne Zeilen von Daten zu filtern, die mit SELECT aus der Datenbank geholt wurden. Die Datensätze, die die WHERE Bedingung(en) nicht erfüllen, werden nicht in die Ausgabe aufgenommen.

Schauen wir uns ein Beispiel an:

where age > 25 AND city='New York'

Es werden nur die Datensätze übergeben, deren Alter größer als 25 ist und deren city New York ist.

In der Abfragesyntax wird die WHERE -Klausel direkt nach SELECT und FROM verwendet. Sie filtert einzelne Zeilen - rohe, nicht gruppierte Datensätze -, die von der Abfrage abgerufen werden, um zu bestimmen, welche Datensätze an die GROUP BY -Klausel weitergegeben werden sollen.

Untersuchen wir die Ausgabe der folgenden Abfrage, die die WHERE -Klausel verwendet.

SELECT last_name, hire_date, manager_id 
FROM hr.employees
WHERE last_name LIKE '%a%' 
AND (hire_date BETWEEN '01-JAN-05' AND '01-JAN-07') 
AND manager_id IS NOT NULL;
LAST_NAMEHIRE_DATEMANAGER_ID
Baida24-DEC-05114
Kochhar21-SEP-05100
Tobias24-JUL-05114

Das obige Beispiel gibt die Spalten last_name, hire_date, und manager_id aus der Tabelle hr.employee. Die WHERE Klausel filtert die Ausgabe wie folgt:

  • last_name muss einen Buchstaben "a" enthalten;
  • hire_date muss größer als oder gleich 01-JAN-05 und kleiner als oder gleich 01-JAN-07 sein; und
  • manager_id muss einen Wert haben und darf nicht null sein.

Nur die Datensätze, die die Bedingungen von WHERE erfüllen, werden in der Ausgabe angezeigt.

Sehen wir uns ein weiteres Beispiel aus demselben Szenario an:

SELECT employee_id, salary, job_id 
FROM hr.employees
WHERE (salary < 3000 OR salary = 9000) 
AND job_id IN ('IT_PROG', 'FI_MGR', 'PU_CLERK'); 
EMPLOYEE_IDSALARYJOB_ID
1039000IT_PROG
1162900PU_CLERK
1172800PU_CLERK

Dieses Beispiel gibt die Spalten employee_id, salary, und job_id aus der Tabelle hr.employee. Die WHERE Klausel filtert die Ausgabe wie folgt:

  • salary muss kleiner als 3000 sein, oder gleich 9000 sein; und
  • job_id muss gleich einem beliebigen Wert sein, der im Operator IN aufgeführt ist.

Wie bei der vorherigen Abfrage enthält die Ausgabe nur die Datensätze, die die Bedingung WHERE erfüllen.

Beachten Sie, dass WHERE keine Bedingungen enthalten kann, die Aggregatfunktionen beinhalten. Das ist die Aufgabe von HAVING.

Szenario II: Die HAVING-Klausel

HAVING wird verwendet, um Gruppen von Datensätzen zu filtern, die durch die GROUP BY Klausel erstellt wurden. Aus diesem Grund muss die HAVING -Klausel auf die GROUP BY -Klausel folgen. Sie ähnelt der WHERE -Klausel, die die SELECT -Ausgabe filtert, nur dass WHERE einzelne Datensätze filtert, während HAVING Gruppen filtert.

Aggregatfunktionen wie SUM(), MAX(), MIN(), AVG() und COUNT() stehen im Mittelpunkt der HAVING -Klausel.

Sehen wir uns das in den Beispielen an.

SELECT SUM(salary), department_id 
FROM hr.emp_details_view
GROUP BY department_id
HAVING SUM(salary) > 10000; 
SUM(SALARY)DEPARTMENT_ID
3400090
1380060
12008100
2500080

Im obigen Beispiel werden die Abteilungen zusammen mit der Summe aller Gehälter in jeder Abteilung aufgelistet. In der Ausgabe werden nur die department_idaufgeführt, deren Gehaltssumme größer als 10000 ist. Diejenigen, die die durch die Klausel HAVING festgelegte Bedingung nicht erfüllen, werden herausgefiltert.

Schauen wir uns ein anderes Beispiel an:

SELECT COUNT(employee_id), job_id, salary
FROM hr.employees
WHERE salary > 12000
GROUP BY job_id, salary
HAVING COUNT(employee_id) < 10; 
COUNT(EMPLOYEE_ID)JOB_IDSALARY
1SA_MAN14000
2AD_VP17000
1FI_MGR12008

Diese Abfrage listet die Anzahl der Mitarbeiter für jede Kombination von job_id und Gehalt auf. Die WHERE Klausel filtert die Datensätze auf diejenigen mit einem Gehalt von mehr als 12000. Die GROUP BY -Klausel, die auf eine WHERE folgt, gibt die Gruppierung nach den nicht aggregierten Spalten job_id und salary an. Schließlich legt die HAVING Klausel fest, dass der aggregierte Wert COUNT(employee_id) kleiner als 10 sein muss.

Szenario III: Die GROUP BY-Klausel

WHERE mit einer GROUP BY-Klausel

Die Klausel WHERE muss immer vor GROUP BY stehen. Der Grund dafür ist, dass WHERE einzelne Datenzeilen filtert, nicht Gruppen von Zeilen. Die GROUP BY -Klausel nimmt die einzelnen Zeilen aus dem Ergebnis des Filters auf Zeilenebene WHERE, um Gruppen von Zeilen zu erstellen.

Hier ist ein Beispiel:

SELECT job_id, SUM(salary) 
FROM hr.employees
WHERE manager_id IN (100, 101, 102, 103)
GROUP BY job_id; 
JOB_IDSUM(SALARY)
AD_VP34000
FI_MGR12008
IT_PROG13800
SA_MAN25000

Die obige Abfrage wird wie folgt ausgewertet:

  1. Die WHERE -Klausel filtert zunächst die Datensätze mit manager_id heraus, die nicht in der Liste nach dem IN -Operator enthalten sind.
  2. Die GROUP BY Klausel gruppiert dann die Datensätze nach job_id, die die WHERE Bedingung erfüllen.

Die Abfrage berechnet die Gesamtgehälter der Mitarbeiter, die von jedem der angegebenen Manager (manager_ids 100, 101, 102, 103) verwaltet werden. Die Gehälter der Mitarbeiter, die anderen Managern unterstellt sind, werden bei der Berechnung dieser Summe nicht berücksichtigt.

HAVING mit einer GROUP BY-Klausel

Die GROUP BY Klausel wird häufig mit Aggregatfunktionen verwendet. Sie erzeugt Summenwerte für die in GROUP BY aufgeführten Spalten.

Im Gegensatz dazu folgt HAVING immer auf eine GROUP BY Klausel, da HAVING mit den durch GROUP BY erstellten Gruppen arbeitet.

Betrachten wir einen Fall, in dem HAVING verwendet wird und die GROUP BY nicht weggelassen werden kann. Dies ist der Fall, wenn in SELECT Spalten aufgeführt sind, die von den Aggregatfunktionen nicht verwendet werden, wie z. B. department_id im folgenden Beispiel. Diese nicht aggregierten Spalten müssen in GROUP BY aufgeführt werden, um Daten zu gruppieren.

SELECT avg(salary), department_id 
FROM hr.emp_details_view
GROUP BY department_id
HAVING avg(salary) < 15000; 
AVG(SALARY)DEPARTMENT_ID
285030
690060
12008100
1250080

HAVING kann jedoch ohne eine begleitende GROUP BY verwendet werden. Beachten Sie, dass in diesem Fall HAVING auf die gesamte Ausgabe von SELECT angewendet wird und diese als eine einzige Gruppe behandelt wird. Nachstehend finden Sie ein Beispiel:

SELECT round(avg(salary))
FROM hr.emp_details_view
HAVING avg(salary) < 11000; 
ROUND(AVG(SALARY))
10056

Die Abfrage gibt einen einzigen Wert zurück, der den Durchschnitt aller Gehälter enthält. Beachten Sie, dass die HAVING Klausel eine Grenze für diesen aggregierten Wert setzt. Wäre der berechnete Durchschnitt größer als 11000 gewesen, hätte die Abfrage keine Datensätze zurückgegeben.

Das nächste Beispiel ist ein Pseudo-Aggregat, bei dem Aggregatfunktionen anstelle einer GROUP BY verwendet werden:

SELECT MIN(first_name), MIN(department_id), MAX(salary)
FROM hr.emp_details_view
HAVING MIN(salary) > 1000; 
MIN(FIRST_NAME)MIN(DEPARTMENT_ID)MAX(SALARY)
Alexander3017000

Die Funktion MIN() wird hier für die Spalten first_name und department_id verwendet. Sie wird nicht in einer typischen Verwendung von Aggregatfunktionen aufgerufen, sondern um eine GROUP BY zu vermeiden. In diesem Fall ist die Ausgabe nur ein einziger Datensatz, der aus dem Minimalwert für first_name, dem Minimalwert für department_id und dem Maximalwert für Gehalt besteht, jeweils aus der gesamten Tabelle. Beachten Sie, dass diese 3 Werte aus 3 verschiedenen Datensätzen stammen können, wie es in diesem Beispiel der Fall ist. Außerdem würde die Abfrage in diesem Fall keinen Datensatz zurückgeben, wenn das Mindestgehalt in der gesamten Tabelle 1000 oder weniger betragen würde.

Dieses Beispiel ist ein wenig künstlich, damit wir Ihnen etwas Einfacheres zeigen können. Pseudo-Aggregation ist zwar weniger verbreitet als GROUP BY, kann aber in Abfragen verwendet werden, die alle eingeschlossenen Zeilen als eine Gruppe behandeln.

Die Verwendung von HAVING mit oder ohne GROUP BY kann je nach Datenbank variieren. Wenn Sie mehr über die GROUP BY Klausel erfahren möchten, lesen Sie bitte den Artikel GROUP BY Klausel.

Szenario IV: Gemeinsame Verwendung der WHERE- und HAVING-Klauseln

Die Syntax für die Verwendung von WHERE und HAVING in einer Abfrage folgt der unten dargestellten spezifischen Reihenfolge:

  1. SELECT: wählt die Spalten aus der Datenbank aus, die im Ergebnis ausgegeben werden sollen.
  2. FROMListe der Tabellen, die in der Abfrage verwendet werden sollen.
  3. WHEREFiltert einzelne Datensätze.
  4. GROUP BY: gruppiert die Datensätze auf der Grundlage der angegebenen Spalte(n).
  5. HAVING: filtert die durch GROUP BY definierten Gruppen.
  6. ORDER BY: sortiert die Ausgabedatensätze nach der/den angegebenen Spalte(n).

Schauen wir uns ein Beispiel an, das alle oben genannten Punkte verwendet.

SELECT country_id, city, MIN(salary), MAX(salary) 
FROM hr.emp_details_view
WHERE country_id IN ('US', 'UK')
GROUP BY country_id, city
HAVING MIN(salary) < 15000
ORDER BY country_id; 
COUNTRY_IDCITYMIN(SALARY)MAX(SALARY)
UKOxford1100014000
USSeattle280017000
USSouthlake48009000

Die Abfrage ruft das Minimum salary und das Maximum salary für jede Kombination von city und country_id ab, wobei letzteres durch die Bedingung WHERE nur auf die USA und das Vereinigte Königreich beschränkt ist.

Angenommen, Sie haben 10 Datensätze mit den USA als country_id, und darin sind 5 Datensätze mit New York als Stadt und weitere 5 mit Los Angeles als Stadt. Wenn Sie die obige Abfrage ausführen, werden aus diesen 10 Datensätzen 2 Datensätze:

  • ein Datensatz für die USA und New York, mit den Mindest- und Höchstgehältern,
  • ein weiterer Datensatz für die USA und Los Angeles, ebenfalls mit den Mindest- und Höchstgehältern.

Weitere Informationen zu den Unterschieden zwischen WHERE und HAVING finden Sie im Artikel über SQL HAVING vs. WHERE.

Szenario V: WHERE und HAVING mit JOINs

Das folgende Beispiel geht noch einen Schritt weiter und verwendet ein JOIN mit WHERE und HAVING. Es verbindet die Daten aus zwei Tabellen auf der Grundlage einer gemeinsamen Spalte, employee_id. Die Klauseln WHERE und HAVING folgen der soeben besprochenen Reihenfolge der Ausführung.

SELECT e.job_id, edv.location_id, SUM(e.salary)
FROM hr.employees e
JOIN hr.emp_details_view edv
ON e.employee_id=edv.employee_id
WHERE e.job_id IN ('IT_PROG', 'SA_MAN')
GROUP BY e.job_id, edv.location_id
HAVING SUM(e.salary) > 5000
ORDER BY e.job_id; 
JOB_IDLOCATION_IDSUM(E.SALARY)
IT_PROG140013800
SA_MAN250025000

In diesem Beispiel wird die Spalte job_id aus der Tabelle hr.employee, die Spalte location_id aus der Tabelle hr.emp_details_viewund die Gesamtgehälter für jede Kombination von job_id und location_id. Die Bedingung für die Verknüpfung der Tabellen ist im Operator ON aufgeführt. Diese Bedingung basiert auf der gemeinsamen Spalte employee_id.

Als nächstes filtert die WHERE -Klausel die Datensätze auf job_ids, die entweder IT_PROG oder SA_MAN sind. Die GROUP BY -Klausel gruppiert die Datensätze nach der Kombination der Spalten job_id und location_id. Schließlich filtert die HAVING -Klausel den aggregierten Wert SUM(e.salary) auf diejenigen, die größer als 5000 sind.

Die Klausel ORDER BY sortiert die Ausgabedatensätze (standardmäßig in aufsteigender Reihenfolge) nach der Spalte job_id. Weitere Informationen zu den Klauseln GROUP BY und ORDER BY finden Sie in dem Artikel GROUP BY vs. ORDER BY.

Unterschied zwischen WHERE- und HAVING-Klauseln in SQL

Hier ist eine Zusammenfassung der Unterschiede zwischen WHERE und HAVING Klauseln in SQL:

WHERE clauseHAVING clause
FilteringFilters individual rows fetched by SELECT, i.e., the output of the SELECT commandFilters groups of rows created by GROUP BY, i.e., the output of the GROUP BY clause
ConditionsCannot have conditions containing aggregate functionsFocuses on conditions containing aggregate functions
SyntaxWHERE comes before GROUP BY in the syntaxHAVING comes after GROUP BY in the syntax
Order of evaluationWHERE clause is evaluated before GROUP BY in the process flow, before aggregation is performedHAVING clause is evaluated after GROUP BY in the process flow, after aggregation is performed
With/without GROUP BYCan be used with or without GROUP BY, since WHERE and GROUP BY are not relatedShould be used with GROUP BY; otherwise, the output of SELECT is treated as one group

WHERE und HAVING sind ein wichtiger Bestandteil beim Erlernen von SQL. Schauen Sie sich den SQL für Anfänger Kurs, um Ihre SQL-Kenntnisse zu verbessern.