Salt la conținutul principal
Modulul 3 · Lecția 4 din 412/57 în curs~8 min
Lecții din modul (4/4)

Grupuri de filtrare: HAVING

Odată ce aveți un rezultat pe grup (lecția anterioară), de multe ori doriți pastreaza doar grupele care indeplinesc o conditie: departamente cu mai multe peste 2 persoane, proiecte cu un buget mediu peste 100k, utilizatori cu minim 10 comenzi. Pentru a face acest lucru WHERE nu este suficient.

De ce UNDE nu este suficient

WHERE filtrează rândurile de tabel, înainte de agregare. Deci nu poate vedea rezultatul COUNT(*) sau AVG(...): până la rularea WHERE, cei valorile nu au fost încă calculate.

SQL
-- ERROR: COUNT(*) doesn't exist yet when WHERE is evaluated
SELECT department_id, COUNT(*) AS count
FROM   employees
WHERE  COUNT(*) > 2     -- ❌ doesn't work
GROUP BY department_id;

Pentru a filtra după agregare există o clauză dedicată: HAVING.

Sintaxa

SQL
SELECT grouping_column, AGGREGATE_FUNCTION(...)
FROM   table
GROUP BY grouping_column
HAVING   condition_on_aggregate;
SQL
-- Departments with more than 2 employees:
SELECT department_id, COUNT(*) AS count
FROM   employees
GROUP BY department_id
HAVING   COUNT(*) > 2;

HAVING este să GROUP BY ceea ce WHERE este să FROM: aceeași idee („filtru”), dar aplicat după grupare, pe ansamblu.

Ordinea logică a clauzelor

Pentru a nu confunda niciodată WHERE și HAVING, amintiți-vă ordinea în care SQL le execută mental:

  1. FROM / JOIN — construiește tabelul de pornire prin alăturarea surselor.
  2. WHERE — renunță la rândurile care nu vă interesează.
  3. GROUP BY — colectează rândurile rămase în grupuri.
  4. HAVING — elimină grupurile de care nu vă interesează.
  5. SELECT — calculează coloanele finale (inclusiv agregatele).
  6. ORDER BY / LIMIT — reordonați și tăiați.

Note importante:

  • în WHERE poți folosi doar coloane de tabel;
  • în HAVING puteți folosi gruparea coloanelor și agregatelor.
SQL
-- Classic combo: filter first, group, filter the groups, sort.
SELECT d.name, AVG(e.salary) AS average
FROM   employees   AS e
JOIN   departments AS d ON e.department_id = d.id
WHERE  e.hired_on >= '2018-01-01'   -- filter rows
GROUP BY d.name
HAVING   AVG(e.salary) > 35000      -- filter groups
ORDER BY average DESC;

Încearcă

Exercițiu#sql.m3.l4.e1
Încercări: 0Se încarcă…

Pentru fiecare departament, arătați numele (departments.name) și numărul de angajați, DAR numai pentru departamentele cu cel puțin 2 angajați. Două coloane, un rând pentru fiecare departament calificat.

Se încarcă editorul...
Afișează indiciu

Condiția „cel puțin 2” devine COUNT(*) >= 2 în HAVING.

Soluție disponibilă după 3 încercări

Exercițiu de revizuire

Exercițiu#sql.m3.l4.e2
Încercări: 0Se încarcă…

Afișați departamentele (departamente.nume) al căror salariu mediu depășește 35000. Luați în considerare doar angajații angajați din 2018 încolo. Două coloane: nume și media. Sortați după medie descrescătoare.

Se încarcă editorul...
Afișează indiciu

WHERE filtrează rândurile (angajați angajați din 2018), HAVING filtrează grupurile (medie > 35000).

Soluție disponibilă după 3 încercări