Biblioteca
Tutora
BibliotecaInformatică și TIC › clasa a XI-a

Limbajul SQL – interogări avansate

Aprofundarea limbajului SQL pentru interogări complexe asupra bazelor de date relaționale.

Bacalaureat

Funcțiile de agregare: de la multe linii la o valoare

O funcție de agregare primește o mulțime de valori (o coloană, pe liniile selectate) și întoarce o singură valoare:

Subtilitățile care fac diferența la examen se învârt toate în jurul lui NULL și al lui COUNT:

Regula de amestec, sursa clasică de eroare: într-un SELECT fără GROUP BY, nu poți pune alături o coloană simplă și un agregat — `SELECT nume, MAX(medie) FROM elevi;` nu returnează elevul cu media maximă, ci este incorect logic (și respins de majoritatea SGBD-urilor): MAX produce o valoare pentru tot tabelul, iar nume are câte o valoare pe linie. Elevul cu media maximă se obține corect cu subinterogare: `WHERE medie = (SELECT MAX(medie) FROM elevi)`.

GROUP BY: agregate pe grupuri

GROUP BY împarte liniile în grupuri după valorile unei coloane (sau ale mai multor coloane), iar funcțiile de agregare se calculează pe fiecare grup în parte, nu pe tot tabelul:

Rezultatul are câte o linie per grup. De aici regula de aur a clauzei, punctată explicit la corectare: în SELECT pot apărea doar coloanele după care s-a grupat și funcții de agregare — orice altă coloană e ambiguă (care nume ai afișa pentru un grup de 30 de elevi?).

Gruparea se poate face după mai multe coloane: `GROUP BY clasa, sex` produce câte un grup pentru fiecare combinație existentă (11A-fete, 11A-băieți, …).

Ordinea de evaluare a unei interogări complete — schema care limpezește tot capitolul:

Din această ordine rezultă și de ce WHERE nu poate conține funcții de agregare: WHERE rulează înainte de formarea grupurilor, când agregatele nici nu există încă. Tot din ea rezultă că ORDER BY poate sorta după un agregat (`ORDER BY AVG(medie) DESC`), fiind evaluat ultimul.

HAVING: filtrul grupurilor, nu al liniilor

HAVING filtrează grupurile create de GROUP BY, pe baza unor condiții cu funcții de agregare — exact ceea ce WHERE nu are voie să facă:

Perechea WHERE / HAVING trebuie stăpânită contrastiv, pentru că orice subiect o testează:

Cele două clauze cooperează, nu se exclud: „media claselor, calculată doar din elevii promovați, afișată doar pentru clasele cu peste 20 de promovați” cere ambele — `WHERE medie >= 5 GROUP BY clasa HAVING COUNT(*) > 20`. WHERE elimină întâi elevii nepromovați (liniile), apoi HAVING elimină clasele mici (grupurile).

Greșelile care pică sistematic candidații:

JOIN: interogări pe mai multe tabele

JOIN combină linii din două (sau mai multe) tabele pe baza unei condiții de legătură, tipic egalitatea dintre cheia externă și cheia primară referită:

Aliasurile (e, c, i) scurtează scrierea și devin obligatorii când coloane cu același nume apar în ambele tabele (id) — altfel referirea e ambiguă.

Tipurile de JOIN, cu diferența care se cere:

De aici idiomul de examen „elevii care NU au împrumutat nimic”: `LEFT JOIN … WHERE i.id_elev IS NULL` — liniile rămase fără pereche sunt exact cele căutate.

Două capcane cotate maxim:

Subinterogări

O subinterogare (subcerere) este un SELECT inclus în altă comandă, ale cărei rezultate le folosește interogarea exterioară. După forma rezultatului:

Regulile de corectitudine care se verifică în subiecte:

Capcana specifică NOT IN: dacă subinterogarea întoarce și NULL, NOT IN nu mai returnează nicio linie (comparațiile cu NULL sunt necunoscute) — de aceea varianta cu LEFT JOIN … IS NULL sau filtrarea NULL-urilor în subcerere e mai sigură.

DDL: crearea și modificarea structurii tabelelor

Comenzile de până acum (SELECT, INSERT, UPDATE, DELETE) formează DML — limbajul de manipulare a datelor. Structura tabelelor se administrează cu DDL — limbajul de definire a datelor:

Restricțiile (constrângerile) care se atașează câmpurilor, fiecare cu rolul ei:

Tripleta de ștergeri, nelipsită din grile pentru că numele se aseamănă și efectele diferă radical: DELETE șterge înregistrări (DML, tabelul rămâne), TRUNCATE golește rapid tot tabelul (structura rămâne), DROP șterge tabelul însuși. Cine le tratează ca sinonime pierde punctul la fiecare apariție.

De reținut

funcție de agregare
funcție care primește mulțimea valorilor unei coloane și întoarce o singură valoare: COUNT, SUM, AVG, MIN, MAX; valorile NULL sunt ignorate din calcul
COUNT(*) vs COUNT(camp)
COUNT(*) numără toate liniile selectate; COUNT(camp) numără doar liniile cu valoare nenulă în câmp; COUNT(DISTINCT camp) numără valorile distincte nenule
GROUP BY
clauza care împarte liniile în grupuri după valorile coloanelor specificate, agregatele calculându-se pe fiecare grup; în SELECT pot apărea doar coloanele de grupare și funcții de agregare
HAVING
clauza care filtrează grupurile după formarea lor, cu condiții ce pot conține funcții de agregare — spre deosebire de WHERE, care filtrează linii individuale înainte de grupare
INNER JOIN
combinarea a două tabele păstrând doar perechile de linii care satisfac condiția de legătură ON, tipic egalitatea cheie externă = cheie primară
LEFT JOIN
combinare care păstrează toate liniile tabelului din stânga, completate cu NULL unde nu există pereche în dreapta; cu filtrul IS NULL găsește liniile fără corespondent
produs cartezian
rezultatul combinării a două tabele fără condiție de legătură: fiecare linie a primului tabel asociată cu fiecare linie a celui de-al doilea — semn aproape sigur de interogare greșită
subinterogare
comandă SELECT scrisă între paranteze în interiorul altei comenzi; poate întoarce o valoare scalară (folosită cu operatori de comparație) sau o mulțime (folosită cu IN, ANY, ALL, EXISTS)
DDL vs DML
DDL definește structura bazei (CREATE, ALTER, DROP); DML manipulează datele din structura existentă (SELECT, INSERT, UPDATE, DELETE)
ordinea de evaluare a interogării
FROM și JOIN, apoi WHERE, GROUP BY, HAVING, SELECT și la final ORDER BY — ordinea explică de ce WHERE nu poate conține agregate, iar ORDER BY poate

Greșeli frecvente

Greșit: Elevul cu media maximă s-ar obține cu SELECT nume, MAX(medie) FROM elevi
Corect: Amestecul coloană simplă + agregat fără GROUP BY este incorect; forma corectă folosește subinterogare: WHERE medie = (SELECT MAX(medie) FROM elevi)
Greșit: Condițiile cu funcții de agregare s-ar putea scrie în WHERE
Corect: WHERE se evaluează înainte de formarea grupurilor, când agregatele nu există; condițiile pe agregate merg exclusiv în HAVING, după GROUP BY
Greșit: COUNT(camp) și COUNT(*) ar întoarce mereu același rezultat
Corect: COUNT(camp) exclude liniile cu NULL în câmpul respectiv; pe un tabel cu valori lipsă, cele două numere diferă exact cu numărul de NULL-uri
Greșit: JOIN fără condiția ON ar returna doar liniile care se potrivesc natural
Corect: Fără condiție de legătură se obține produsul cartezian — fiecare linie cu fiecare; potrivirea pe chei trebuie scrisă explicit în ON
Greșit: DELETE, TRUNCATE și DROP ar fi trei sinonime pentru ștergere
Corect: DELETE șterge înregistrări selectabile cu WHERE (tabelul rămâne), TRUNCATE golește tot tabelul păstrând structura, DROP șterge tabelul cu structură cu tot

Test — 6 întrebări ca la examen

1. Tabelul elevi are 30 de linii, dintre care 4 au NULL în câmpul medie. Ce returnează SELECT COUNT(*), COUNT(medie) FROM elevi;?
  1. 30 și 30
  2. 26 și 26
  3. 30 și 26
  4. 26 și 30
Vezi răspunsul
30 și 26. COUNT(*) numără liniile — toate cele 30; COUNT(medie) numără doar valorile nenule — 26. Varianta 30 și 30 e capcana pentru cine crede că cele două forme sunt echivalente; diferența dintre ele este exact numărul de NULL-uri.
2. Care interogare afișează corect clasele cu media generală peste 9?
  1. SELECT clasa, AVG(medie) FROM elevi WHERE AVG(medie) > 9 GROUP BY clasa;
  2. SELECT clasa, AVG(medie) FROM elevi GROUP BY clasa HAVING AVG(medie) > 9;
  3. SELECT clasa, AVG(medie) FROM elevi HAVING AVG(medie) > 9;
  4. SELECT clasa, medie FROM elevi WHERE medie > 9 ORDER BY clasa;
Vezi răspunsul
SELECT clasa, AVG(medie) FROM elevi GROUP BY clasa HAVING AVG(medie) > 9;. Condiția pe un agregat se pune în HAVING, după GROUP BY. Prima variantă — distractorul principal — pică pentru că WHERE rulează înaintea grupării, când AVG nu există; a treia pierde gruparea pe clase, iar a patra filtrează elevi individuali cu media peste 9, cu totul altă întrebare.
3. În interogarea SELECT clasa, COUNT(*) FROM elevi GROUP BY clasa; rezultatul conține:
  1. câte o linie pentru fiecare elev din tabel
  2. câte o linie pentru fiecare clasă distinctă, cu numărul elevilor ei
  3. o singură linie, cu numărul total de elevi
  4. câte o linie pentru fiecare clasă, cu numele tuturor elevilor
Vezi răspunsul
câte o linie pentru fiecare clasă distinctă, cu numărul elevilor ei. GROUP BY produce o linie per grup, iar COUNT(*) se calculează în interiorul fiecărui grup — deci fiecare clasă cu efectivul ei. O singură linie totală ar rezulta fără GROUP BY; afișarea numelor lângă agregat ar încălca regula coloanelor permise în SELECT la grupare.
4. Pentru a afișa TOȚI elevii, inclusiv pe cei care nu au niciun împrumut (cu NULL la titlu), se folosește:
  1. INNER JOIN între elevi și imprumuturi
  2. LEFT JOIN cu tabelul elevi în stânga
  3. produsul cartezian al celor două tabele
  4. două comenzi SELECT executate succesiv
Vezi răspunsul
LEFT JOIN cu tabelul elevi în stânga. LEFT JOIN păstrează toate liniile tabelului din stânga (elevi) și completează cu NULL acolo unde nu există împrumut. INNER JOIN — alegerea reflexă a multora — elimină exact elevii fără împrumuturi, adică pe cei ceruți explicit de enunț; produsul cartezian combină totul cu totul, fără sens.
5. Interogarea SELECT nume FROM elevi WHERE medie = (SELECT MAX(medie) FROM elevi); returnează:
  1. media maximă din tabel
  2. numele elevilor cu media egală cu maximul din tabel
  3. eroare, pentru că două comenzi SELECT nu pot apărea împreună
  4. numele tuturor elevilor, sortați descrescător după medie
Vezi răspunsul
numele elevilor cu media egală cu maximul din tabel. Subinterogarea scalară calculează întâi maximul, apoi interogarea exterioară selectează elevii cu exact acea medie — pot fi mai mulți la egalitate. Acesta este șablonul corect pentru linia cu valoare extremă; SELECT în interiorul altui SELECT este perfect legal dacă subcererea stă între paranteze.
6. Diferența corectă dintre DROP TABLE elevi și DELETE FROM elevi este:
  1. nu există diferență, ambele golesc tabelul
  2. DROP șterge tabelul cu structură cu tot; DELETE șterge doar înregistrările, tabelul rămânând
  3. DELETE șterge tabelul, DROP doar datele
  4. DROP funcționează numai împreună cu clauza WHERE
Vezi răspunsul
DROP șterge tabelul cu structură cu tot; DELETE șterge doar înregistrările, tabelul rămânând. DROP este comandă DDL: după ea tabelul nu mai există deloc. DELETE este DML: golește (sau filtrează cu WHERE) datele, dar structura rămâne și se pot insera din nou înregistrări. Varianta a treia inversează termenii — exact confuzia pe care mizează grila; WHERE nu are ce căuta lângă DROP.
Deschide varianta interactivă — cu AI care îți explică
← Baze de date – noțiuni fundamentaleRețele de calculatoare →
BiologieChimieEconomieFilosofieFizicăGeografieInformatică și TICIstorieLogică și argumentareMatematicăPsihologieLimba și literatura română