1. Introducere în Limbajul SQL și Baza de Date Model (EMP & DEPT)
🔍 De la Algoritmi Imperativi (C++) la Interogări Declarative (SQL)
SQL (Structured Query Language) este limbajul standard utilizat pentru a comunica cu un Sistem de Gestiune a Bazelor de Date Relaționale (precum MySQL, Oracle, PostgreSQL sau MS SQL Server).
Spre deosebire de C++, care este un limbaj imperativ (unde trebuie să scrii pas cu pas cum se parcurge un vector cu o buclă for), SQL este un limbaj declarativ: tu doar specifici ce coloane și ce condiții trebuie să îndeplinească datele, iar SGBD-ul alege singur cel mai rapid algoritm de căutare.
💻 În C++ (Abordare Imperativă)
🗄️ În SQL (Abordare Declarativă)
Comenzile SQL se împart în 4 sub-limbaje principale, dintre care instrucțiunea SELECT este cea mai importantă și cea mai utilizată (atât în practică, cât și la examenul de Bacalaureat):
• DQL (Data Query Language): Interogarea și extragerea datelor — instrucțiunea SELECT.
• DDL (Data Definition Language): Definirea structurii tabelelor — CREATE TABLE, ALTER TABLE, DROP TABLE.
• DML (Data Manipulation Language): Modificarea datelor din tabele — INSERT, UPDATE, DELETE.
• DCL (Data Control Language): Controlul permisiunilor — GRANT, REVOKE.
Baza de Date de Exersare: Tabelele DEPT și EMP
Toate exemplele și exercițiile din acest material folosesc baza de date clasică a unei companii, formată din două tabele aflate în relație 1:M (Unu-la-Mulți):
1. DEPT (Departamente — Tabelul Părinte, partea 1): reține codul departamentului (DEPTNO — Cheie Primară), numele departamentului (DNAME) și orașul (LOC).
2. EMP (Angajați / Employees — Tabelul Copil, partea M): reține marca angajatului (EMPNO — Cheie Primară), numele (ENAME), funcția (JOB), codul șefului direct (MGR), data angajării (HIREDATE), salariul (SAL), comisionul (COMM — doar pentru agenții de vânzări) și codul departamentului în care lucrează (DEPTNO — Cheie Externă).
Tabelul 1: DEPT (4 înregistrări)
| DEPTNO (PK) | DNAME | LOC |
|---|---|---|
| 10 | ACCOUNTING | NEW YORK |
| 20 | RESEARCH | DALLAS |
| 30 | SALES | CHICAGO |
| 40 | OPERATIONS | BOSTON |
💡 Observație: Departamentul 40 (OPERATIONS) există în tabelul DEPT, dar nu are încă niciun angajat alocat în tabelul EMP.
Tabelul 2: EMP (9 înregistrări)
| EMPNO (PK) | ENAME | JOB | MGR | HIREDATE | SAL | COMM | DEPTNO (FK) |
|---|---|---|---|---|---|---|---|
| 7839 | KING | PRESIDENT | NULL | 1981-11-17 | 5000 | NULL | 10 |
| 7566 | JONES | MANAGER | 7839 | 1981-04-02 | 2975 | NULL | 20 |
| 7698 | BLAKE | MANAGER | 7839 | 1981-05-01 | 2850 | NULL | 30 |
| 7782 | CLARK | MANAGER | 7839 | 1981-06-09 | 2450 | NULL | 10 |
| 7788 | SCOTT | ANALYST | 7566 | 1987-04-19 | 3000 | NULL | 20 |
| 7499 | ALLEN | SALESMAN | 7698 | 1981-02-20 | 1600 | 300 | 30 |
| 7521 | WARD | SALESMAN | 7698 | 1981-02-22 | 1250 | 500 | 30 |
| 7654 | MARTIN | SALESMAN | 7698 | 1981-09-28 | 1250 | 1400 | 30 |
| 7369 | SMITH | CLERK | 7566 | 1980-12-17 | 800 | NULL | 20 |
2. Anatomia Instrucțiunii SELECT (Ordinea Scrierii vs. Ordinea Execuției)
O instrucțiune SELECT completă este alcătuită din până la 6 clauze principale. Primele două (SELECT și FROM) sunt obligatorii, iar următoarele patru sunt opționale, dar când sunt folosite, trebuie scrise întotdeauna în această ordine strictă.
SELECT, motorul bazei de date o execută intern în altă ordine logică:
1.
FROM (ia tabelul) → 2. WHERE (filtrează rândurile brute) → 3. GROUP BY (formează grupurile) → 4. HAVING (filtrează grupurile) → 5. SELECT (extrage coloanele/calculele) → 6. ORDER BY (sortează tabelul final).
1. SELECT (Proiecția)
Specifică ce coloane sau calcule (expresii, funcții agregat) vrem să apară în tabelul rezultat.
2. FROM (Sursa)
Specifică tabelul (sau tabelele) din care se citesc datele (ex: FROM EMP). Se execută prima!
3. WHERE (Selecția)
Filtrează rândurile individuale înainte de grupare. Rândurile care nu respectă condiția sunt eliminate.
4. GROUP BY (Gruparea)
Împarte rândurile rămase în submulțimi (grupuri) care au aceeași valoare pe coloana specificată (ex: pe departamente).
5. HAVING (Filtru Grup)
Filtrează grupurile formate de GROUP BY pe baza rezultatelor unor funcții agregat (COUNT, AVG, SUM).
6. ORDER BY (Sortarea)
Ordonează rândurile din rezultatul final crescător (ASC, implicit) sau descrescător (DESC). Se execută ultima!
👆 Apasă pe butoanele de mai sus pentru a vedea rolul fiecărei clauze în interogarea demonstrativă pe tabelul EMP.
3. Pas cu Pas: Proiecție, Filtrare (WHERE) și Sortare (ORDER BY)
Urmărește cum se construiesc interogările SQL de la cele mai simple la cele complexe, verificând de fiecare dată rezultatul pe tabelul EMP din Secțiunea 1.
Pasul 1 Alegerea Coloanelor (Proiecția), DISTINCT și Coloane Calculate
Putem extrage toate coloanele folosind simbolul *, doar anumite coloane separate prin virgulă, valori unice fără duplicate (DISTINCT) sau chiar expresii matematice redenumite cu AS (alias).
Exemplul 1.1: Extragerea funcțiilor unice din companie (DISTINCT)
Dacă am scrie SELECT JOB FROM EMP;, am primi 9 rânduri (funcția MANAGER și SALESMAN s-ar repeta). Cuvântul cheie DISTINCT elimină duplicatele din afișare:
| JOB |
|---|
| PRESIDENT |
| MANAGER |
| ANALYST |
| SALESMAN |
| CLERK |
Exemplul 1.2: Coloane calculate și redenumirea lor cu AS (Alias)
Afișăm numele, salariul lunar și salariul anual (SAL * 12) redenumit ca Venit_Anual pentru angajații din departamentul 10:
| Nume_Angajat | SAL | Venit_Anual |
|---|---|---|
| KING | 5000 | 60000 |
| CLARK | 2450 | 29400 |
Pasul 2 Filtrarea Rândurilor cu WHERE și Operatori Logici
Clauza WHERE testează fiecare rând din tabel. În SQL, egalitatea se scrie cu un singur egal (=, nu == ca în C++), iar diferit se scrie <> (sau !=). Șirurile de caractere și datele calendaristice se pun între apostrofuri simple ('MANAGER').
Exemplul 2.1: Condiții compuse cu AND și OR
Să se afișeze numele, funcția, salariul și departamentul pentru angajații din departamentul 30 care au salariul mai mare sau egal cu 1500:
| ENAME | JOB | SAL | DEPTNO |
|---|---|---|---|
| BLAKE | MANAGER | 2850 | 30 |
| ALLEN | SALESMAN | 1600 | 30 |
Pasul 3 Operatori Speciali în SQL: BETWEEN, IN, LIKE și IS NULL
SQL oferă patru operatori extrem de expresivi care simplifică scrierea condițiilor și apar frecvent în subiectele de examen:
BETWEEN a AND b: verifică apartenența la intervalul închis [a, b] (echivalent cu val >= a AND val <= b).•
IN (v1, v2, ...): verifică dacă valoarea se regăsește într-o mulțime de valori (echivalent cu val = v1 OR val = v2 ...).•
LIKE 'șablon': caută șiruri de caractere folosind două metacaractere (wildcards):—
% înlocuiește oricâte caractere (0, 1 sau mai multe);—
_ (underscore) înlocuiește exact un singur caracter.•
IS NULL / IS NOT NULL: testează dacă un câmp este necompletat. Atenție: Nu se scrie niciodată COMM = NULL!
Exemplul 3.1: Operatorii BETWEEN și IN
Afișăm angajații cu salariul cuprins între 2000 și 3000 (inclusiv capetele) care lucrează în departamentul 10 sau 20:
| ENAME | JOB | SAL | DEPTNO |
|---|---|---|---|
| JONES | MANAGER | 2975 | 20 |
| CLARK | MANAGER | 2450 | 10 |
| SCOTT | ANALYST | 3000 | 20 |
Exemplul 3.2: Căutarea după șablon cu LIKE
Afișăm angajații al căror nume începe cu litera 'S' (LIKE 'S%') sau are litera 'L' pe a doua poziție (LIKE '_L%'):
| EMPNO | ENAME | JOB |
|---|---|---|
| 7698 | BLAKE | MANAGER |
| 7782 | CLARK | MANAGER |
| 7788 | SCOTT | ANALYST |
| 7499 | ALLEN | SALESMAN |
| 7369 | SMITH | CLERK |
Exemplul 3.3: Testarea valorilor NULL (IS NOT NULL)
Afișăm doar angajații care primesc comision (adică au o valoare completată pe coloana COMM):
| ENAME | JOB | SAL | COMM |
|---|---|---|---|
| ALLEN | SALESMAN | 1600 | 300 |
| WARD | SALESMAN | 1250 | 500 |
| MARTIN | SALESMAN | 1250 | 1400 |
Pasul 4 Sortarea Rezultatelor cu ORDER BY
Clauza ORDER BY se scrie întotdeauna la finalul instrucțiunii SELECT. Implicit, ordonarea este crescătoare (ASC). Pentru ordonare descrescătoare folosim DESC. Putem sorta și după mai multe criterii: dacă doi angajați au același salariu, îi departajăm alfabetic după nume.
| ENAME | JOB | SAL |
|---|---|---|
| BLAKE | MANAGER | 2850 |
| ALLEN | SALESMAN | 1600 |
| MARTIN | SALESMAN | 1250 |
| WARD | SALESMAN | 1250 |
Observați cum MARTIN și WARD au același salariu (1250), dar MARTIN apare primul datorită celui de-al doilea criteriu: ENAME ASC.
4. Funcții Agregat, Grupare (GROUP BY / HAVING) și Joncțiuni (JOIN)
Pasul 5 Funcțiile de Agregare (Statistici pe Tabel)
Funcțiile agregat prelucrează o mulțime de rânduri și returnează o singură valoare rezumat:
• COUNT(*) — numără toate rândurile;
• COUNT(coloana) — numără doar rândurile unde acea coloană nu este NULL;
• SUM(coloana) — calculează suma valorilor numerice;
• AVG(coloana) — calculează media aritmetică;
• MIN(coloana) și MAX(coloana) — determină valoarea minimă, respectiv maximă.
Exemplul 5.1: Diferența dintre COUNT(*) și COUNT(COMM) pe tabelul EMP
| Total_Angajati | Cu_Comision | Sal_Min | Sal_Max |
|---|---|---|---|
| 9 | 3 | 800 | 5000 |
Pasul 6 Gruparea Datelor cu GROUP BY și Filtrarea cu HAVING
Ce facem dacă nu vrem salariul maxim pe toată firma, ci vrem numărul de angajați și salariul maxim pentru fiecare departament în parte? Folosim GROUP BY DEPTNO.
WHERE vs. HAVING:
• În
WHERE nu ai voie să pui funcții agregat (precum COUNT, AVG, SUM), deoarece WHERE filtrează rândurile individuale înainte de formarea grupurilor.
• În
HAVING pui condiții pe funcțiile agregat (ex: HAVING COUNT(*) >= 3), deoarece filtrează grupurile după ce au fost calculate.
Exemplul 6.1: Statistici pe fiecare departament cu cel puțin 3 angajați
| DEPTNO | Nr_Ang | Fond_Salarii |
|---|---|---|
| 20 | 3 | 6775 |
| 30 | 4 | 6950 |
Observați că departamentul 10 (care are doar 2 angajați: KING și CLARK) a fost eliminat de clauza HAVING COUNT(*) >= 3.
Pasul 7 Interogarea pe Două Tabele: Joncțiunea (INNER JOIN)
În tabelul EMP avem doar codul departamentului (DEPTNO), nu și numele departamentului (DNAME) sau orașul (LOC), care se află în tabelul DEPT. Pentru a afișa date din ambele tabele simultan, le unim prin condiția de egalitate dintre Cheia Externă (EMP.DEPTNO) și Cheia Primară (DEPT.DEPTNO).
Exemplul 7.1: Afișarea numelui angajatului, a funcției, a denumirii departamentului și a orașului
În SQL există două moduri echivalente de a scrie această joncțiune (ambele sunt acceptate la Bacalaureat):
Varianta 1 (Standard SQL cu INNER JOIN ... ON):
Varianta 2 (Sintaxa clasică în WHERE):
Tabelul rezultat (pentru oricare dintre cele două variante de mai sus):
| ENAME | JOB | DNAME | LOC |
|---|---|---|---|
| JONES | MANAGER | RESEARCH | DALLAS |
| SCOTT | ANALYST | RESEARCH | DALLAS |
| SMITH | CLERK | RESEARCH | DALLAS |
5. Laborator de Exersare și Quiz SQL (pe baza EMP & DEPT)
Testează-ți cunoștințele! Consultă tabelele EMP și DEPT din Secțiunea 1 ori de câte ori vrei să verifici rezultatul unei interogări.
Partea I: Alege Clauza sau Condiția SQL Corectă
Pentru fiecare cerință de mai jos, apasă pe varianta de cod SQL care rezolvă corect problema:
WHERE angajații care NU primesc comision (au NULL pe coloana COMM)?LIKE selectează toți angajații al căror nume (ENAME) se termină cu litera 'N' (ex: ALLEN, MARTIN)?JOB) în care salariul mediu depășește 2500. Ce clauză folosim după GROUP BY JOB?WHERE SAL >= 1250 AND SAL <= 2850?DEPTNO), iar în cadrul aceluiași departament, descrescător după salariu (SAL)?Partea a II-a: Test Grilă de Evaluare SQL (pe datele din EMP & DEPT)
Calculează rezultatul interogărilor de mai jos pe baza celor 9 angajați din tabelul EMP și a celor 4 departamente din DEPT: