Pe scurt
O interogare extrage datele cerute din unul sau mai multe tabele. Un raport le prezintă într-o formă utilă, de exemplu numărul elevilor din fiecare clasă. Pentru elevii Ana și Dan în 9A și Mara în 9B, raportul arată 9A: 2 și 9B: 1.
În detaliu
O interogare extrage din una sau mai multe tabele datele cerute; un raport le prezintă într-o formă utilă, de exemplu numărul elevilor din fiecare clasă sau media fiecărei clase. Interogarea de bază alege câmpuri (proiecție) și înregistrări (selecție): SELECT nume FROM elevi WHERE clasa_id = 9 ORDER BY nume. Pentru rapoarte se folosesc funcții de agregare (COUNT, SUM, AVG, MIN, MAX), gruparea GROUP BY și filtrarea grupurilor cu HAVING. COUNT(*) numără rândurile unui grup, nu adună valorile unei coloane. GROUP BY nu garantează singur ordinea grupurilor; ordinea afișării se cere cu ORDER BY. WHERE filtrează rândurile înainte de grupare, iar HAVING filtrează grupurile după calculul agregatelor.
Exemplul 1 — număr de elevi pe clasă. Datele sunt: clasele 9 (9A) și 10 (9B); elevii Ana (clasa 9, media 9,50), Dan (clasa 9, media 7) și Mara (clasa 10, media 8):
CREATE TABLE clase (id integer PRIMARY KEY, denumire text NOT NULL);
CREATE TABLE elevi (id integer PRIMARY KEY, nume text NOT NULL,
clasa_id integer REFERENCES clase(id), medie numeric(4,2));
INSERT INTO clase VALUES (9, '9A'), (10, '9B');
INSERT INTO elevi VALUES (1, 'Ana', 9, 9.5), (2, 'Dan', 9, 7), (3, 'Mara', 10, 8);
SELECT clasa_id, COUNT(*) AS numar FROM elevi GROUP BY clasa_id ORDER BY clasa_id;
SELECT clasa_id, COUNT(*) AS numar FROM elevi GROUP BY clasa_id HAVING COUNT(*) >= 2;
Prima interogare formează două grupuri și întoarce și . A doua păstrează doar grupurile cu cel puțin doi elevi, deci întoarce numai . Filtrul pe un rezultat agregat se pune în HAVING, nu în WHERE: o condiție WHERE COUNT(*) >= 2 este respinsă, pentru că agregatul nu există încă în momentul filtrării rândurilor.
Exemplul 2 — raport cu JOIN și medie. Pentru numele clasei, tabelele se combină pe cheia externă. Raportul arată, pentru fiecare clasă, numărul elevilor și media lor:
SELECT clase.denumire, COUNT(*) AS numar, ROUND(AVG(medie), 2) AS medie_clasa
FROM elevi JOIN clase ON elevi.clasa_id = clase.id
GROUP BY clase.denumire ORDER BY clase.denumire;
SELECT clasa_id, COUNT(*) AS numar FROM elevi
WHERE medie >= 8 GROUP BY clasa_id ORDER BY clasa_id;
Primul raport are rândurile (9A, 2, 8,25) și (9B, 1, 8,00): media clasei 9A este . A doua interogare filtrează cu WHERE rândurile cu media cel puțin 8 înainte de grupare, deci Dan dispare din calcul, iar rezultatul este și . Acest rezultat diferă de cel cu HAVING din primul exemplu: WHERE schimbă rândurile care intră în grupuri, HAVING schimbă grupurile care rămân. Ordinea clauzelor în interogare este SELECT, FROM, WHERE, GROUP BY, HAVING, ORDER BY, iar ORDER BY este ultima aplicată rezultatului.
Exemplul 3 — clasa fără elevi și valorile lipsă. Se adaugă clasa 9C (id 11), fără niciun elev. Raportul cu JOIN o omite, pentru că nu are rânduri în elevi. Cu LEFT JOIN, clasa rămâne în raport, iar numărul se calculează cu COUNT(elevi.id):
INSERT INTO clase VALUES (11, '9C');
SELECT clase.denumire, COUNT(elevi.id) AS numar
FROM clase LEFT JOIN elevi ON elevi.clasa_id = clase.id
GROUP BY clase.denumire ORDER BY clase.denumire;
Rezultatul este (9A, 2), (9B, 1), (9C, 0). Dacă s-ar scrie COUNT(*), clasa 9C ar primi 1, pentru că rândul rezultat din unire, cu valori lipsă în coloanele elevilor, este totuși un rând; COUNT(elevi.id) numără numai valorile existente. Aceeași regulă se aplică mediilor: dacă elevul Radu din clasa 10 are media necompletată (NULL), în clasa 10 COUNT(*) dă 2, COUNT(medie) dă 1, iar AVG(medie) rămâne 8, fiindcă ignoră valorile lipsă. Elevii cu media peste media generală se obțin cu o subinterogare: WHERE medie > (SELECT AVG(medie) FROM elevi). Media generală a primelor trei medii este , deci rămâne numai Ana. Clasamentul elevilor după medie, de la cea mai mare, se obține cu ORDER BY medie DESC: Ana (9,5), Mara (8), Dan (7). Fără DESC, ordonarea este crescătoare. Pentru mai multe criterii, ele se despart prin virgulă: ORDER BY clasa_id, nume.
Greșeli frecvente
- Greșit:
COUNT(*)adună valorile unei coloane.Corect: numără rândurile din grup. - Greșit:
GROUP BYgarantează singur ordinea grupurilor.Corect: foloseșteORDER BY. - Greșit:
WHERE COUNT(*) >= 2filtrează grupurile.Corect: foloseșteHAVING.
Testează-te pe această lecție
Lecția o citești aici, fără cont. Testele pe lecții și capitole sunt în cont, cu grile originale Didaxis și explicația fiecăreia: gratuit 10 grile pe zi, fără limită cu Premium, 49 de lei pe lună pentru fiecare copil.
Înainte și după
Surse și referințe
Redactare proprie, conform programei:
- OMECI 5099/2009, anexa 5, Informatică, p. 3–4, 7, clasa XII; rocnee.eu
- OMECI 5099/2009, anexa 5, Informatică, p. 3, 7, clasa XII; plan de încadrare: OMEC 7723/2024, anexa 2, tabelele 1–25, legislatie.just.ro; filiera tehnologică: OMEC 7724/2024, anexa 4, tabelul calificării, legislatie.just.ro
Documente consultate
- Programa școlară de informatică, clasa a XII-a (OMECI 5099/2009, anexa 5), CNCE, modulul Baze de date, p. 3 și 7; rocnee.eu
- PostgreSQL, Documentation 18, „Querying a Table” și „Aggregate Functions”, postgresql.org/docs/18/tutorial-sql.html
Desene: Redactare proprie (desen original)
