Documente Academic
Documente Profesional
Documente Cultură
2 - SQL
6. Utilizarea funciilor agregat
Deseori este necesar s sintetizm datele fr a le regsi propriu-zis n totalitate, iar SQL
pune la dispoziie funcii speciale n acest scop. Utiliznd aceste funcii, interogrile SQL sunt
frecvent folosite la regsirea datelor pentru analiz i includerea n rapoarte. Printre exemplele
din aceast categorie de operaii de regsire se numr:
Determinarea numrului de rnduri dintr-un tabel (sau a numrului de rnduri care satisfac o
anumit condiie, respectiv care conin o anumit valoare);
Obinerea sumei unui set de rnduri dintr-un tabel;
Determinarea valorii maxime, minime i medii din coloana unui tabel (fie pentru toate
rndurile, fie numai pentru anumite rnduri).
SQL pune la dispoziie un set de cinci funcii agregat, care sunt enumerate n tabelul 6.1.
Aceste funcii v permit s efectuai toate tipurile de operaii de regsire prezentate anterior.
Funcii agregat Funcii care lucreaz cu un set de rnduri pentru a calcula i returna o
singur valoare.
Tabelul 6.1 Funciile agregat ale limbajului SQL
Funcie
Descriere
AVG()
COUNT()
MAX()
MIN()
SUM()
Funcia AVG()
Funcia AVG() este utilizat pentru calculul mediei valorilor dintr-o anumit coloan, prin
numrarea rndurilor din tabel i nsumarea valorilor acestora. Funcia AVG() se poate utiliza
pentru calculul mediei tuturor coloanelor, respectiv a anumitor coloane sau rnduri.
Primul exemplu folosete funcia AVG() pentru a calcula preul mediu al tuturor produselor
din tabelul Produse:
SELECT AVG(pret_produs) AS pret_mediu
FROM Produse;
Aceast instruciune SELECT difer de cea precedent numai prin faptul c instruciunea
curent conine o clauz WHERE. Clauza filtreaz numai produsele al cror identificator de
productor (id_producator) are valoarea 'DLL01'.
Funcia COUNT()
Folosind funcia COUNT(), putei determina numrul de rnduri dintr-un tabel sau numrul
de rnduri care satisfac un anumit criteriu.
Funcia COUNT() se poate folosi n dou moduri:
Formatul COUNT(*) se utilizeaz la numrarea rndurilor dintr-un tabel, indiferent dac
coloanele conin valori sau nu (valori NULL);
Formatul COUNT(coloana) se utilizeaz la numrarea rndurilor care conin valori dintr-o
anumit coloan, ignornd valorile NULL.
Acest prim exemplu determin numrul total de clieni din tabelul Clienti:
SELECT COUNT(*) AS num_clienti
FROM Clienti;
Funcia MAX()
Funcia MAX() returneaz cea mai mare valoare dintr-o coloan specificat. Funcia MAX()
impune specificarea numelui coloanei, aa cum se poate vedea n continuare:
SELECT MAX(pret_produs) AS pret_maxim
FROM Produse;
Aici, funcia MAX() determin preul celui mai costisitor element din tabelul Produse.
Funcia MIN()
Funcia MIN() este exact opusul funciei MAX(): returneaz valoarea cea mai mic dintr-o
coloan specificat. Ca i MAX(), funcia MIN() impune specificarea numelui coloanei, aa
cum se poate vedea n continuare:
2
Aici, funcia MIN() determin preul celui mai puin costisitor articol din tabelul Produse.
Funcia SUM()
Funcia SUM() este utilizat la calculul sumei (totalului) valorilor dintr-o anumit coloan.
Iat un exemplu n care vom ilustra aceasta. Tabelul ArticoleComenzi conine articolele
aezate ntr-o anumit ordine, iar la fiecare articol este asociat o cantitate. Numrul total de
articole (suma tuturor valorilor din coloana cantitate) poate fi regsit astfel:
SELECT SUM(cantitate) AS articole_comandate
FROM ArticoleComandate
WHERE numar_comanda = 20005;
n acest caz, o singur instruciune SELECT execut patru calcule de sintez ntr-o singur
etap i returneaz patru valori (numrul articolelor din tabelul Produse, precum i preul
maxim, minim i mediu al acestora).
7. Gruparea datelor
Noiunea de grupare a datelor
Grupurile v permit s mprii datele n seturi logice, pentru a putea s efectuai calcule de
sintez cu fiecare grup.
Crearea grupurilor
Grupurile se creeaz cu ajutorul clauzei GROUP BY n cadrul instruciunii SELECT.
SELECT id_producator, COUNT(*) AS numar_produse
FROM Produse
GROUP BY id_producator;
Filtrarea grupurilor
n afar de posibilitatea de a grupa datele folosind GROUP BY, SQL mai permite i filtrarea
grupurilor care vor fi incluse, respectiv a celor care vor fi excluse. De exemplu,
exemplu putei dori o list
a tuturor clienilor care au emis cel puin dou comenzi. Pentru a obine aceste date, trebuie s
filtrai folosind ca baz ntregul grup, nu rnduri individuale.
SQL pune la dispoziie n acest scop clauza HAVING. n timp ce WHERE filtreaz rnduri,
HAVING filtreaz grupuri.
SELECT id_client, COUNT(*) AS comenzi
FROM Comenzi
GROUP BY id_client
HAVING COUNT(*) >= 2;
Diferena dintre HAVING i WHERE WHERE filtreaz anterior gruprii datelor, n timp ce
HAVING filtreaz dup aceast operaie, ceea ce reprezint o diferen important; rndurile
4
eliminate de o clauz WHERE nu vor mai fi incluse n grup. Aceasta poate modifica valorile
calculate care, la rndul lor, pot influena grupurile filtrate, pe baza utilizrii valorilor respective
n clauza HAVING.
Pentru a ilustra mai bine acest concept, s examinm exemplul urmtor, care afieaz toi
productorii ce ofer articole la un pre de cel puin 4 lei:
SELECT id_producator, COUNT(*) AS numar_produse
FROM Produse
WHERE pret_produs >= 4
GROUP BY id_producator
HAVING COUNT(*) >= 2;
Prima linie reprezint o instruciune SELECT elementar, care folosete o funcie agregat.
Clauza WHERE filtreaz toate rndurile cu un pre al produsului (pret_unitar) egal cu
minimum 4. Datele sunt apoi grupate n funcie de identificatorul productorului
(id_producator), dup care o clauz HAVING filtreaz numai acele grupuri care conin dou
sau mai multe rnduri. n absena clauzei WHERE, ar mai fi aprut un rnd (productorul DLL01,
care vinde patru produse cu un pre mai mic dect 4), aa cum se poate vedea n continuare:
SELECT id_producator, COUNT(*) AS numar_produse
FROM Produse
GROUP BY id_producator
HAVING COUNT(*) >= 2;
Grupare i sortare
Deseori, vei descoperi c datele grupate folosind GROUP BY vor fi ntr-adevr afiate ntr-o
ordine de grup. Dar aceasta nu se ntmpl ntotdeauna i nu este o cerin obligatorie n
specificaiile SQL. Mai mult, chiar dac programul SGBD sorteaz ntotdeauna datele n funcie
de clauza GROUP BY specificat, s-ar putea ca s dorii s fie sortate ntr-un alt mod. Faptul c
grupai datele ntr-un anumit mod (pentru a obine valori de sintez specifice unui grup) nu
nseamn c dorii ca datele de ieire s fie sortate n acelai mod. Trebuie s specificai i o
clauz explicit ORDER BY, chiar dac este una i aceeai cu clauza GROUP BY.
Pentru a demonstra utilizarea ambelor clauze, s examinm un exemplu.
exemplu Instruciunea
SELECT urmtoare este asemntoare celor prezentate anterior; regsete numrul comenzii i
numrul articolelor comandate pentru toate comenzile care conin trei sau mai multe articole:
SELECT numar_comanda, COUNT(*) AS articole
FROM ArticoleComandate
GROUP BY numar_comanda
HAVING COUNT(*) >= 3;
Pentru a sorta datele de ieire n funcie de numrul articolelor comandate, tot ce avei de
fcut este s adugai o clauz ORDER BY, aa cum se poate vedea n continuare:
SELECT numar_comanda, COUNT(*) AS articole
FROM ArticoleComandate
GROUP BY numar_comanda
HAVING COUNT(*) >= 3
ORDER BY COUNT(*), numar_comanda;
n acest exemplu, clauza GROUP BY este utilizat la gruparea datelor n funcie de numrul
comenzii (coloana numar_comanda), astfel nct funcia COUNT(*) s poat determina
numrul articolelor din fiecare comand. Clauza HAVING filtreaz datele astfel nct s fie
returnate numai comenzile care conin trei sau mai multe articole. n final, datele de ieire sunt
sortate folosind clauza ORDER BY.
Descriere
SELECT
FROM
Tabelul din care urmeaz a fi regsite Numai dac se selecteaz date dintr-un
datele
tabel
WHERE
Nu
GROUP BY
Specificaie de grup
HAVING
Nu
ORDER BY
Nu
valori
8. Lucrul cu sub-interogri
Noiunea de sub-interogare
Interogare Orice instruciune SQL. Totui, termenul este utilizat, de regul, pentru a face
referire la instruciunile SELECT.
6
Etapa urmtoare const din regsirea identificatorilor de client asociai comenzilor 20007 i
20008. Folosind clauza IN putei crea o instruciune SELECT aa cum se poate vedea n
continuare:
SELECT id_client
FROM Comenzi
WHERE numar_comanda IN (20007, 20008);
Acum, combinai cele dou interogri, transformnd-o pe prima (cea care a returnat numerele
comenzilor) ntr-o sub-interogare. S examinm urmtoarea instruciune SELECT:
SELECT id_client
FROM Comenzi
WHERE numar_comanda IN (SELECT numar_comanda
FROM ArticoleComandate
WHERE id_produs = 'RGAN01');
Pentru a executa instruciunea SELECT anterioar, programul SGBD a trebuit s execute trei
instruciuni SELECT. Sub-interogarea interioar a returnat o list cu numerele comenzilor, care
au fost apoi utilizate n clauza WHERE a sub-interogrii imediat superioare. Acea sub-interogare a
returnat o list cu identificatori de client, care au fost utilizai n clauza WHERE a interogrii
principale. Aceasta din urm a returnat efectiv datele dorite.
Aceast instruciune SELECT returneaz trei coloane pentru fiecare client din tabelul
Clienti: nume_client, stat_client i comenzi. comenzi este un cmp cu valoare
calculat, care este determinat prin intermediul unei sub-interogri delimitat ntre paranteze.
Acea sub-interogare este executat cte o dat pentru fiecare client regsit. n exemplul de mai
sus, sub-interogarea este executat de cinci ori, deoarece au fost regsii cinci clieni.
Clauza WHERE din sub-interogare este puin diferit de clauzele WHERE folosite anterior,
deoarece folosete nume de coloane complet determinate. Clauza urmtoare indic programului
SQL s compare identificatorul de client din tabelul Comenzi cu acela regsit din tabelul
Clienti:
WHERE Comenzi.id_client = Clienti.id_client
Aceast sintax numele tabelului i numele coloanei, separate printr-un punct trebuie
utilizat ori de cte ori exist posibilitatea unei neclariti n ceea ce privete numele coloanelor.
n acest exemplu, exist dou coloane numite id_client: una n tabelul Clienti i alta n
tabelul Comenzi.
9. Unirea tabelelor
Noiunea de uniune
Una dintre cele mai puternice funcionaliti ale limbajului SQL o reprezint capacitatea de
unire instantanee a tabelelor n cadrul interogrilor de regsire a datelor. Uniunile se numr
printre cele mai importante operaii pe care le putei efectua folosind instruciunea SQL
SELECT, iar o bun cunoatere a uniunilor i a sintaxei acestei operaii reprezint o component
extrem de important a nvrii limbajului SQL.
9
De ce s folosim uniuni?
O uniune este un mecanism folosit pentru asocierea tabelelor din cadrul unei instruciuni
SELECT (de unde i numele de uniune). Folosind o sintax special, pot fi unite mai multe
tabele astfel nct s se returneze un singur set de date de ieire, iar uniunea asociaz instantaneu
rndurile corecte din fiecare tabel.
Instruciunea SELECT ncepe n acelai mod ca i toate instruciunile pe care le-ai examinat
pn acum, prin specificarea coloanelor care urmeaz a fi regsite. Marea diferen, n acest caz,
const din aceea c dou dintre coloanele specificate (nume_produs i pret_produs) se
gsesc ntr-un tabel, n timp ce o alta (nume_producator) se gsete ntr-un alt tabel.
10
Tabelele sunt unite n mod corespunztor cu ajutorul unei clauze WHERE, care indic
programului SGBD s caute identitatea dintre elementele coloanei id_producator din
tabelul Producatori i elementele coloanei omonime din tabelul Produse.
Vei observa c specificaia coloanelor este de forma Producatori.id_producator,
respectiv Produse.id_producator. Acest nume de coloan complet determinat este
obligatoriu n cazul de fa deoarece, dac specificai numai id_producator, programul
SGBD nu poate stabili la care coloan cu acest nume v referii.
Identificarea complet a numelor de coloane Trebuie s folosii numele de coloan
complet determinat (numele tabelului i numele coloanei, separate printr-un punct) ori de cte ori
exist o potenial ambiguitate privind coloana la care v referii.
Uniuni interioare
Uniunea pe care ai folosit-o pn acum se numete echi-uniune adic o uniune bazat pe
verificarea egalitii valorilor cuprinse n dou tabele. Aceast categorie de uniune se mai
numete i uniune interioar. De fapt, pentru aceste uniuni se poate folosi o sintax uor diferit,
n care se specific n mod explicit tipul uniunii. Urmtoarea instruciune SELECT regsete
exact aceleai date ca i n exemplul precedent:
SELECT nume_producator, nume_produs, pret_produs
FROM Producatori INNER JOIN Produse
ON Producatori.id_producator = Produse.id_producator;
Relaia dintre cele dou tabele face parte din clauza FROM specificat sub forma INNER
JOIN. Cnd folosii aceast sintax, condiia de unire este specificat folosindu-se clauza
special ON, n locul unei clauze WHERE.
Acest exemplu afieaz articolele cuprinse n comanda cu numrul 20007. Articolele din
comand sunt stocate n tabelul ArticoleComandate. Fiecare produs este sortat n funcie de
identificatorul su, care face referire la un produs din tabelul Produse. Produsele sunt legate de
productorul corespunztor, situat n tabelul Producatori, prin identificatorul productorului,
care este stocat n nregistrarea fiecrui produs. Aici, clauza FROM menioneaz cele trei tabele,
iar clauza WHERE definete ambele condiii de unire.
Sub-interogrile nu reprezint ntodeauna cea mai eficient modalitate de a afectua operaii
SELECT complexe.
n urmtorul exemplu,
exemplu returnarea datelor necesit utilizarea a trei tabele. Dar, n loc de a le
folosi n cadrul unor sub-interogri imbricate, n acest caz se folosesc dou uniuni pentru a stabili
legtura dintre tabele. Aici exist trei condiii n clauza WHERE. Primele dou creaz o legtur
ntre tabelele din uniune, iar a treia filtreaz datele pentru a se obine numai informaiile legate
de produsul RGAN01:
SELECT nume_client, contact_client
FROM Clienti, Comenzi, ArticoleComandate
WHERE Clienti.id_client = Comenzi.id_client
AND ArticoleComandate.numar_comanda = Comenzi.numar_comanda
AND
id_produs = 'RGAN01';
Auto-uniunile
S presupunem c dorii s trimitei un mesaj tuturor persoanelor de contact clieni care
lucreaz la aceeai companie ca i Jim Jones. Aceast interogare impune ca, mai nti, s se
identifice firma pentru care lucreaz Jim Jones, iar dup aceea s se determine persoanele de
contact care lucreaz n cadrul companiei respective. n continuare este prezentat o modalitate
de rezolvare a problemei:
SELECT id_client, nume_client, contact_client
FROM Clienti
WHERE nume_client = (SELECT nume_client
FROM Clienti
WHERE contact_client = 'Jim Jones');
13
Cele dou tabele necesare n aceast interogare sunt, de fapt unul i acelai tabel, motiv
pentru care tabelul Clienti apare de dou ori n clauza FROM. Dei aceast operaie este
perfect posibil, referirile la tabelul Clienti vor fi ambigue, deoarece programul SGBD nu
tie la care tabel Clienti se face referirea.
Pentru a rezolva aceast problem, se utilizeaz alias-urile. Prima apariie a tabelului
Clienti are alias-ul c1, n timp ce a doua are alias-ul c2. Acum, aceste alias-uri se pot utiliza
ca nume de tabele. Instruciunea SELECT, de exemplu, folosete prefixul c1 pentru a specifica
n mod explicit numele complet al coloanelor dorite. Dac nu s-ar fi procedat astfel, programul
SGBD ar fi returnat o eroare, deoarece exist cte dou coloane cu numele id_client,
nume_client i contact_client. Programul nu are de unde ti care este coloana dorit
(chiar dac, n realitate, este vorba de una i aceeai coloan). Clauza WHERE ncepe prin a uni
tabelele, dup care filtreaz datele n funcie de coloana contact_client din al doilea tabel,
pentru a returna numai datele dorite.
Uniuni naturale
La fiecare uniune de tabele, cel puin o coloan va aprea n mai mult de un tabel (coloanele
ce se unesc). Uniunile standard (uniunile interioare) returneaz toate datele, chiar i mai multe
apariii ale aceleiai coloane. O uniune natural elimin pur i simplu aceste apariii multiple,
astfel nct s fie returnat cte o coloan din fiecare.
O uniune natural este acea uniune n care se selecteaz numai coloanele care sunt unice.
Aceasta se realizeaz, n mod obinuit, folosind un caracter de nlocuire (SELECT *) pentru un
tabel i sub-seturi explicite ale coloanelor pentru toate celelalte tabele. n continuare, prezentm
un exemplu:
exemplu
SELECT C.*, O.numar_comanda, O.data_comanda,
AC.id_produs,AC.cantitate, AC.pret_unitar
FROM Clienti as C, Comenzi as O, ArticoleComandate AS AC
WHERE C.id_client = O.id_client
AND AC.numar_comanda = O.numar_comanda
AND id_produs = 'RGAN01';
n acest exemplu, caracterul de nlocuire se folosete numai la primul tabel. Toate celelalte
coloane sunt menionate n mod explicit, astfel nct s nu fie regsite coloane duplicate.
Uniuni exterioare
Majoritatea uniunilor stabilesc legturi ntre rndurile dintr-un tabel i rndurile dintr-un alt
tabel. Dar, uneori, se dorete includerea rndurilor care nu sunt corelate cu alte rnduri. De
exemplu,
exemplu putei folosi uniuni exterioare pentru executarea urmtoarelor operaii:
Stabilirea numrului comenzilor emise de fiecare client, inclusiv de clienii care nu au emis
nici o comand;
Enumerarea tuturor produselor, alturi de cantitile n care au fost comandate, inclusiv
produsele pe care nu le-a comandat nimeni;
Calcularea cifrei medii de vnzri, lundu-se n calcul i pe clienii care nu au emis nc nici
o comand.
14
n fiecare dintre aceste exemple, uniunea include rnduri din tabel care nu dispun de rnduri
asociate n tabelul conex. Acest tip de uniune se numete uniune exterioar.
exterioar
Urmtoarea instruciune SELECT este o uniune interioar simpl, care regsete o list a
tuturor clienilor i a comenzilor acestora:
SELECT Clienti.id_client, Comenzi.numar_comanda
FROM Clienti INNER JOIN Comenzi
ON Clienti.id_client = Comenzi.id_client;
Sintaxa unei uniuni exterioare este asemntoare. Pentru a regsi o list a tuturor clienilor,
inclusiv a acelora care nu au emis nici o comand, putei proceda astfel:
SELECT Clienti.id_client, Comenzi.numar_comanda
FROM Clienti LEFT OUTER JOIN Comenzi
ON Clienti.id_client = Comenzi.id_client;
Spre deosebire de uniunile interioare, care stabilesc legturi ntre rnduri din ambele tabele,
uniunile exterioare cuprind i rnduri care nu sunt corelate cu alte rnduri. Cnd se folosete
sintaxa OUTER JOIN trebuie s se utilizeze cuvntul-cheie RIGHT sau LEFT pentru a specifica
tabelul din care urmeaz a se include toate rndurile (RIGHT pentru tabelul din partea dreapt a
uniunii exterioare, respectiv LEFT pentru cel din stnga). n exemplul precedent se folosete
LEFT OUTER JOIN pentru a selecta toate rndurile din tabelul situat n partea stng a clauzei
FROM (tabelul Clienti). Pentru a selecta toate rndurile din tabelul situat n dreapta, vei
folosi RIGHT OUTER JOIN, aa cum se poate vedea n exemplul prezentat n continuare:
SELECT Clienti.id_client, Comenzi.numar_comanda
FROM Clienti RIGHT OUTER JOIN Comenzi
ON Clienti.id_client = Comenzi.id_client;
15
Acest exemplu folosete o uniune exterioar la stnga pentru a include pe toi clienii, chiar i
pe cei care nu au emis nici o comand. Rezultatele l includ i pe clientul cu numrul
1000000002, de data aceasta cu 0 comenzi.
16
Prima instruciune SELECT regsete toate rndurile cu informaii despre clieni cu sediile n
statele Illimois, Indiana i Michigan, prin includerea abrevierilor numelor acestor state n clauza
IN. Cea de-a doua instruciune SELECT folosete un test simplu de egalitate pentru a gsi toate
filialele firmei Fun4All.
Pentru a combina cele dou instruciuni, procedai astfel:
SELECT nume_client, contact_client, email_client
FROM Clienti
WHERE stat_client IN ('IL', 'IN', 'MI')
UNION
SELECT nume_client, contact_client, email_client
FROM Clienti
WHERE nume_client = 'Fun4All';
17
18
Acest operator UNION preia o singur clauz ORDER BY dup instruciunea SELECT final.
Dei clauza ORDER BY pare a face parte din ultima instruciune SELECT, programul SGBD o
va folosi pentru sortarea tuturor rezultatelor returnate de toate instruciunile SELECT.
cod_postal_client,
tara_client,
contact_client,
email_client)
VALUES('1000000006',
'Toy Land',
'123 Any Street',
'New York',
'NY',
'11111',
'USA',
NULL,
NULL);
Acest exemplu execut exact aceeai operaie ca i instruciunea INSERT precedent, dar de
data aceasta numele coloanelor sunt precizate n mod explicit ntre paranteze, dup numele
tabelului. La inserarea rndului, programul SGBD va stabili corespondena ntre fiecare element
din lista coloanelor i fiecare element din lista VALUES.
Urmtoarea instruciune INSERT populeaz toate coloanele de rnduri, dar ntr-o alt ordine.
Deoarece numele coloanelor sunt specificate, inserarea va avea efectul dorit:
INSERT INTO Clienti(id_client,
contact_client,
email_client,
nume_client,
adresa_client,
oras_client,
stat_client,
cod_postal_client,
tara_client)
VALUES('1000000006',
NULL,
NULL,
'Toy Land',
'123 Any Street',
'New York',
'NY',
'11111',
'SUA');
20
adresa_client,
oras_client,
stat_client,
cod_postal_client,
tara_client)
SELECT id_client,
contact_client,
email_client,
nume_client,
adresa_client,
oras_client,
stat_client,
cod_postal_client,
tara_client
FROM ClientiNoi;
Dac tabelul ClientiNoi este vid, nu va fi inserat nici un rnd (i nu va fi generat nici un
mesaj de eroare, deoarece operaia rmne valabil). Dac tabelul conine date, toate datele
respective vor fi inserate n tabelul Clienti.
Instruciunea SELECT folosit ntr-o instruciune INSERT SELECT poate include o clauz
WHERE, pentru a filtra datele care urmeaz a fi inserate.
22
tergerea datelor
Pentru a terge (elimina) date dintr-un tabel, se folosete instruciunea DELETE. Aceast
instruciune se poate folosi n dou moduri:
Pentru a terge anumite rnduri dintr-un tabel;
Pentru a terge toate rndurile dintr-un tabel.
Instruciunea urmtoare terge un singur rnd din tabelul Clienti:
DELETE FROM Clienti
WHERE id_client = '1000000006';
n acest exemplu, se va terge numai clientul cu numrul 1000000006. Dac s-ar fi omis
clauza WHERE, aceast instruciune ar fi ters toi clienii din tabel.
Instruciunea DELETE nu preia nume de coloane i nici caractere de nlocuire. DELETE
terge rnduri, nu coloane. Pentru a terge anumite coloane, folosii instruciunea UPDATE.
24