Język SQL dostarcza jeszcze jedną metodę filtrowania wyników zapytań — jeżeli grupujemy wyniki (a więc używamy klauzuli
GROUP BY), możemy sprawdzić, czy te grupy wierszy spełniają jakiś warunek. Wiemy już, że po zastosowaniu klauzuli
WHERE wyniki zapytania najpierw są filtrowane, a potem grupowane. Klauzula
HAVING, tak jak
WHERE, umożliwia określenie testu logicznego, ale w jej przypadku będzie on zastosowany do grup, a nie pojedynczych wierszy.
Testy logiczne zawarte w klauzuli HAVING wykonywane są na całych grupach, a nie na pojedynczych rekordach. Tak więc klauzula ta służy do wybierania interesujących nas grup, a klauzula
WHERE — interesujących nas wierszy. Warunek umieszczony w klauzuli
HAVING wyrażony jest za pomocą dowolnej funkcji grupowej (listing 6.21).
Listing 6.21. Informacje o zamówieniach, których wartość przekroczyła 30. Iloczyn
quantity*sell_price jest wyliczany dla każdego sprzedanego towaru, a następnie wyliczana jest suma wartości dla każdej grupy, czyli w tym przypadku dla każdego zamówienia. Na końcu klauzula
HAVING usuwa z wyniku te grupy (zamówienia), których wartość nie przekroczyła 30.
SELECT orderinfo_id, SUM(quantity*sell_price)
FROM orderinfo JOIN orderline USING (orderinfo_id)
JOIN item USING (item_id)
GROUP BY orderinfo_id
HAVING SUM(quantity*sell_price)> 30;
+--+--+
| orderinfo_id | SUM(quantity*sell_price) |
+--+--+
| 2 | 69.83 |
| 3 | 33.44 |
+--+--+
Klauzule
HAVING i
WHERE mogą wystąpić w tym samym zapytaniu — w takim przypadku najpierw będzie zastosowany test z klauzuli
WHERE, a następnie — z klauzuli
HAVING (listing 6.22).
Listing 6.22. Wyniki poprzedniego zamówienia ograniczone do zamówień złożonych w pierwszej połowie 2000 roku.
SELECT orderinfo_id, SUM(quantity*sell_price)
FROM orderinfo JOIN orderline USING (orderinfo_id)
JOIN item USING (item_id)
WHERE date_placed BETWEEN '2000-01-01' AND '2000-06-31'
GROUP BY orderinfo_id
HAVING SUM(quantity*sell_price)> 30;
+--+--+
| orderinfo_id | SUM(quantity*sell_price) |
+--+--+
| 2 | 69.83 |
+--+--+
Zapisanie w klauzuli
HAVING warunku, który jest sprawdzany na poziomie wierszy nie jest błędem składniowym (czyli MySQL prawidłowo zinterpretuje i wykona takie zapytanie), ale taka instrukcja jest nie tylko nieelegancka i nieczytelna, ale również może być dłużej wykonywana (listing 6.23).
Listing 6.23. Klauzula
HAVING użyta do wybierania wierszy
SELECT item_id, SUM(quantity*sell_price)
FROM orderinfo JOIN orderline USING (orderinfo_id)
JOIN item USING (item_id)
GROUP BY item_id
HAVING item_id IN (1,2,3,4);
++--+
| item_id | SUM(quantity*sell_price) |
++--+
| 1 | 65.85 |
| 2 | 11.49 |
| 3 | 2.49 |
| 4 | 11.97 |
++--+
W takim przypadku należy użyć klauzuli
WHERE (listing 6.24).
Listing 6.24. Funkcjonalnie takie samo, ale czytelniejsze i szybsze rozwiązanie
SELECT item_id, SUM(quantity*sell_price)
FROM orderinfo JOIN orderline USING (orderinfo_id)
JOIN item USING (item_id)
WHERE item_id IN (1,2,3,4)
GROUP BY item_id;
++--+
| item_id | SUM(quantity*sell_price) |
++--+
| 1 | 65.85 |
| 2 | 11.49 |
| 3 | 2.49 |
| 4 | 11.97 |
++--+