HAVING in SQL
HAVING ist ein WHERE für Statistikfunktionen.
- HAVING-Abfrage
SELECT PERSON, AVG( GEHALT )
FROM WERDEGANG
WHERE PERSON < 10
GROUP BY PERSON
HAVING AVG( GEHALT )> 70000;+--------+--------------+
| person | avg(gehalt) |
+--------+--------------+
| 1 | 73000.000000 |
| 7 | 78000.000000 |
+--------+--------------+
2 rows in set (0.08 sec)
Eine WHERE-Klausel wird vor einer eventuellen Gruppierung berücksichtigt, um festzulegen, welche Zeilen aus der Tabelle für eine eventuelle Gruppierung verwendet werden.
WARNINGS; SET sql_mode = 'ANSI,TRADITIONAL';
SET div_precision_increment = 4;
DROP SCHEMA S; CREATE SCHEMA S; USE S;
CREATE TABLE T
( C INT COMMENT 'Beispielspalte ohne Sinn',
C1 INT COMMENT 'Beispielspalte ohne Sinn',
C2 INT COMMENT 'Beispielspalte ohne Sinn' )
COMMENT = 'sinnlose Beispieltabelle';INSERT INTO T ( C, C1, C2 )
VALUES ( 0, 0, 0 ),
( 1, 2, 0 ),
( 0, 4, 0 ),
( 1, 3, 0 ),
( 0, 0, 1 ),
( 1, 4, 1 ),
( 0, 8, 1 ),
( 1, 6, 1 );SELECT * FROM T;
SELECT SUM( C1 ) FROM T WHERE C2 = 0 GROUP BY C;
- Ausgabe
+------+------+------+
| C | C1 | C2 |
+------+------+------+
| 0 | 0 | 0 |
| 1 | 2 | 0 |
| 0 | 4 | 0 |
| 1 | 3 | 0 |
| 0 | 0 | 1 |
| 1 | 4 | 1 |
| 0 | 8 | 1 |
| 1 | 6 | 1 |
+------+------+------++-----------+
| SUM( C1 ) |
+-----------+
| 4 |
| 5 |
+-----------+
Da die WHERE-Bedingungen vor der Gruppierung und Anwendung von Statistikfunktionen angewendet werden, ist es nicht möglich sich schon in der WHERE-Klausel auf Ergebnisse der Gruppierung oder Statistikfunktionen zu beziehen.
Die WHERE-Klausel erlaubt es, Zeilen auszuschließen, welche nicht zur Gruppierung herangezogen werden sollen, während eine HAVING-Klausel Zeilen aus dem Ergebnis der Gruppierung ausschließen kann.
Entsprechend können in einer HAVING-Klausel außerhalb von Statistikfunktionen nur Spaltennamen verwendet werden, die in der GROUP-BY-Klausel vorkommen.
Die Reihenfolge der Klauseln im Quelltext ist: SELECT, FROM, WHERE, GROUP BY, HAVING und ORDER BY.
<table expression> ::=
<from clause>
[ <where clause> ]
[ <group by clause> ]
[ <having clause> ]
[ <order by clause> ]
Bei Ausführung der Abfrage, werden die folgenden Schritte in dieser Reihenfolge ausgeführt:
- Verbindung der Tabellen hinter FROM (kartesisches Produkt)
- Selektion von Zeilen gemäß einer eventuellen WHERE-Klausel
- Gruppierung von Zeilen gemäß einer eventuellen GROUP-BY-Klausel
- Selektion der Ergebnisse aus dem vorherigen Schritt gemäß einer eventuellen HAVING-Klausel
- Sortierung der Ergebnisse gemäß einer eventuellen ORDER-BY-Klausel
Teilnehmerfrage
- „Könnte man immer »HAVING« statt »WHERE« verwenden?“
»WHERE« kann auch in »UPDATE« oder »DELETE«-Anweisungen verwendet werden, wo »HAVING« nicht erlaubt ist.
Eine Equirestriktion mit »WHERE« kann einen vorhandenen Index zur Beschleunigung verwenden, dies geht bei »HAVING« nicht, da »HAVING« immer eine vorherige Gruppierung annimmt und nach einer Gruppierung Indizes nicht mehr verwendbar sind.
Abgesehen davon könnte man in vielen einfachen Abfragen auch »HAVING« an Stelle von »WHERE« verwenden, das folgende Beispiel zeigt aber, daß dies nicht grundsätzlich immer möglich ist – etwa sobald »GROUP BY« verwendet wird.
- MySQL-Konsole
CREATE TABLE T2 ( I INTEGER, S VARCHAR ( 255 ) );
INSERT INTO T2 VALUES ( 0, 'A' ), ( 1, 'B' ), ( 2, 'B' );
SELECT I, S FROM T2;
SELECT I FROM T2 WHERE S = 'B' GROUP BY I;
SELECT I FROM T2 GROUP BY I HAVING S = 'B';