Ce face GROUP BY, HAVING și clauza FILTER
GROUP BY grupează rândurile cu aceleași valori în rânduri sumarizate, iar HAVING filtrează grupurile rezultate după aplicarea funcțiilor agregate (COUNT, SUM, AVG, STRING_AGG).
O funcționalitate extrem de elegantă în PostgreSQL este clauza FILTER (WHERE conditie) atașată direct unei funcții de agregare. Aceasta înlocuiește expresiile SUM(CASE WHEN ... THEN 1 ELSE 0 END) greu de citit și permite calcularea mai multor metrici condiționale într-o singură parcurgere a tabelului.
Clauze, operatori și argumente
| Clauză / Operator | Descriere |
|---|---|
GROUP BY col1, col2 |
Grupează rândurile care au aceleași valori pe coloanele sau expresiile specificate. |
GROUP BY ROLLUP / CUBE |
Generează automat subtotaluri ierarhice (ROLLUP) sau toate combinațiile multidimensionale (CUBE). |
HAVING conditie_agregat |
Filtrează grupurile după agregare (spre deosebire de WHERE, care filtrează rândurile individuale înainte de GROUP BY). |
AGG(...) FILTER (WHERE ...) |
Evaluează funcția agregată doar pentru rândurile din grup care îndeplinesc condiția din FILTER. |
STRING_AGG(col, sep) |
Concatenează valorile text dintr-un grup folosind separatorul indicat. |
Exemple
Exemplul 1: Raport pivot de comenzi pe statusuri folosind FILTER (WHERE …)
Calculăm într-o singură interogare numărul total de comenzi, numărul celor livrate, numărul celor anulate și încasările doar din comenzile livrate pe fiecare lună.
SELECT to_char(plasata_la, 'YYYY-MM') AS luna,
COUNT(*) AS total_comenzi,
COUNT(*) FILTER (WHERE status = 'livrata') AS livrate,
COUNT(*) FILTER (WHERE status = 'anulata') AS anulate,
COALESCE(SUM(total_lei) FILTER (WHERE status = 'livrata'), 0) AS incasari_lei
FROM comenzi
GROUP BY luna
HAVING COUNT(*) >= 10
ORDER BY luna DESC;
Rezultat interogare
luna | total_comenzi | livrate | anulate | incasari_lei
---------+---------------+---------+---------+--------------
2025-03 | 48 | 41 | 3 | 19450.00
2025-02 | 62 | 58 | 4 | 27810.50
2025-01 | 55 | 50 | 5 | 23100.00
(3 rows)
Exemplul 2: Concatenarea valorilor dintr-un grup cu STRING_AGG și ordonare internă
Afișăm lista angajaților din fiecare departament, ordonați alfabetic și separați prin virgulă.
SELECT departament,
COUNT(*) AS nr_angajati,
STRING_AGG(nume, ', ' ORDER BY nume ASC) AS echipa
FROM angajati
GROUP BY departament
ORDER BY nr_angajati DESC;
Rezultat interogare
departament | nr_angajati | echipa
-------------+-------------+-----------------------------------------
Backend | 3 | Andrei Popa, Maria Stan, Victor Toma
DevOps | 2 | Dan Munteanu, Vlad Dumitru
(2 rows)
Greșeli frecvente
- Includerea în lista
SELECTa unei coloane care nu apare nici înGROUP BY, nici într-o funcție de agregare (și nu depinde funcțional de cheia primară dinGROUP BY). - Folosirea funcțiilor de agregare în clauza
WHERE(ex:WHERE COUNT(*) > 5) în loc deHAVING COUNT(*) > 5.
Comenzi și funcții înrudite
SUM() / AVG() OVER (PARTITION BY): Calculează totaluri cumulate (running totals), medii mobile și procente din totalul grupului folosind ferestre.COALESCE, NULLIF și CASE WHEN: Gestionează valorile NULL, previne împărțirea la zero și evaluează logica condițională direct în expresiile SQL.jsonb_build_object, jsonb_agg și jsonb_set: Construiește obiecte și vectori JSONB din rânduri relaționale și modifică parțial documente JSONB existente.
Întrebări & Exemple de Cod:
GROUP BY, HAVING și clauza FILTERAi o nelămurire despre utilizarea comenzii
GROUP BY, HAVING și clauza FILTERsau ai descoperit un truc / fragment de cod util? Distribuie-l cu ceilalți programatori!Fii primul care pune o întrebare sau distribuie un fragment de cod / prompt!
Nu au fost adăugate încă întrebări sau exemple de cod pentru această pagină. Dacă ai întâlnit o problemă sau ai un snippet util, adaugă-l mai jos pentru a-i ajuta pe ceilalți.