You are on page 1of 30

Subinterogri (Subcereri)

O caracteristic foarte puternic a limbajului SQL sunt subinterogrile (numite i selecii), care, aa cum sugereaz i numele, se refer la o instruciune SELECT care conine o instruciune SELECT subordonat. De cele mai multe ori, pentru a implementa anumite interogri, nu este suficient o singur cerere SELECT ci sunt necesare subcereri. Subcererile sunt comenzi SELECT ncapsulate n oricare din clauzele , SELECT, WHERE, HAVING, FROM, numit instruciune printe. Dac subcererea urmeaz clauzei WHERE sau HAVING, ea poate conine unul dintre operatorii ALL, ANY, IN (=ANY), EXIST, NOT IN (!=ALL) care sunt specifici cererilor care ntorc mai multe linii (multiple-row subquery) sau unul dintre operatorii de comparare (=, <, >, >=, <=, <>) care sunt specifici cererilor care ntorc o singur linie (single-row subquery). Utiliznd subcereri, se pot construi interogri complexe pe baza unor instruciuni simple. Subcererile mai sunt numite instruciuni SELECT imbricate sau interioare.

Subcererea returneaz o valoare care este utilizat de ctre instruciunea printe. Utilizarea unei subcereri este echivalent cu efectuarea a dou cereri secveniale i utilizarea rezultatului cererii interne ca valoare de cutare n cererea extern (principal). Subcererile pot fi utilizate n urmtoarele situaii: pentru a furniza valori care intervin n condiiile din clauzele WHERE, HAVING i START WITH ale instruciunilor SELECT; pentru a defini o mulime de linii care urmeaz s fie inserat n tabelul destinaie al unei instruciuni INSERT sau CREATE TABLE; pentru a defini o mulime de linii care urmeaz s fie inserate ntr-o vizualizare sau vizualizare materializat, prin intermediul unei instruciuni CREATE VIEW sau CREATE MATERIALIZED VIEW; pentru a defini una sau mai multe valori care urmeaz s fie atribuite unor linii existente ntr-o instruciune UPDATE; pentru a defini un tabel asupra cruia va opera cererea extern (plasarea subcererii n clauza FROM sau n instruciunile INSERT, UPDATE, DELETE).

Subcererile trebuie incluse ntre paranteze i trebuie plasate n partea dreapt a operatorului de comparare. Subcererea nu poate conine clauza ORDER BY. De obicei, subinterogrile sunt folosite n clauza WHERE, ca modalitate de limitare a rndurilor returnate n setul de rezultate al interogrii externe. Aceasta poate fi o modalitate foarte flexibil de selectare a datelor. O regul esenial de sintax este ca subinterogarea s fie ncadrat de paranteze. Orice operaie efectuat cu o subinterogare poate fi fcut i printr-o uniune. Exemplu: S se obin numele i salariul angajailor, avnd salariul minim. SELECT FROM WHERE name, sal angajati sal=(SELECT FROM

MIN(sal) angajati);

Exemplu: S se obin job-ul pentru care salariul mediu este minim. Sa se afiseze si salariul mediu. SELECT job, AVG(sal) FROM angajati GROUP BY job HAVING AVG(sal)=(SELECT MIN(AVG(sal)) FROM angajati GROUP BY job); Operatorul ANY presupune c este adevrat condiia dac comparaia este adevrat pentru cel puin una din valorile returnate. Sunt evidente relaiile: < ANY mai mic ca maximul; > ANY mai mare ca minimul; = ANY IN. Pentru operatorul ALL se presupune c este adevrat condiia, dac comparaia este adevrat pentru toate elementele listei returnate. Pentru operatorul ALL sunt evidente relaiile: < ALL mai mic ca minimul; > ALL mai mare ca maximul; ! = ALL NOT IN.

Exemplu: WHERE codec > ALL (C1, C2) este superior tuturor elementelor din list; WHERE codec > ANY (C1, C2) este superior cel puin unui element din list. Exemplu: S se obin salariaii al cror salariu este mai mare ca salariile medii din toate departamentele. SELECT FROM WHERE nume, job angajati sal > ALL(SELECT FROM GROUP BY

AVG(sal) angajati cod_dep);

Exist subcereri care au ca rezultat mai multe coloane (multiple-column subquery). Aceste interogri au urmtoarea sintax general: SELECT FROM WHERE col,col, tabel (col,col,) IN (SELECT col,col, FROM tabel WHERE condiie);

Dac una din valorile returnate de subcerere este valoarea null atunci cererea nu ntoarce nici o linie. Prin urmare, dac valoarea null poate s fac parte din rezultatul subcererii nu trebuie utilizat operatorul NOT IN. Problema nu mai apare dac se utilizeaz operatorul IN.

Exemplu: S se obin salariaii care nu au subordonai. SELECT FROM WHERE a.nume angajati a a.cod_ang NOT IN (SELECT m.mgr FROM angajati m);

n acest caz, instruciunea SQL nu ntoarce nici o linie deoarece una din valorile furnizate de subcerere este valoarea null.

Subinterogri necorelate (nesincronizate) O subinterogare necorelat (noncorrelated subselect) este o subinterogare n care interogarea intern nu face nici o referire la interogarea extern care o conine. Subcererile necorelate returneaz o valoare care este utilizat de cererea extern (cererea principal). Cererile care conin subcereri necorelate sunt evaluate n modul urmtor: cererea intern este executat prima i determin o valoare (sau o mulime de valori); cererea extern se execut o singur dat, utiliznd valorile returnate de cererea intern. n general, o cerere imbricat, necorelat are urmtoarea form: SELECT FROM WHERE lista_select nume_tabel expresie operator (SELECT lista_select FROM nume_tabel);

n aceast sintax, identificatorul operator poate fi de tip: single-row operator (>, =, >=, <, <>, <=), care poate fi utilizat dac subcererea returneaz o singur linie; multiple-row operator (IN, ANY, ALL), care poate fi folosit dac subcererea returneaz mai mult de o linie. Operatorul ANY, care este sinonim cu operatorul SOME, determin compararea unei valori cu fiecare valoare returnat de o subcerere. Astfel, <ANY are semnificaia mai mic dect maximul; >ANY nseamn mai mare dect minimul; =ANY este echivalent cu operatorul IN. Operatorul ALL compar o valoare cu toate valorile returnate de o subcerere. Astfel, <ALL are semnificaia mai mic dect minimul, iar >ALL este echivalent cu mai mare dect maximul. Operatorul NOT poate fi utilizat n combinaie cu IN, ANY i ALL. n utilizarea unei subcereri se impun anumite reguli. Subcererea trebuie inclus ntre paranteze. Pentru claritate, subcererea se plaseaz n partea dreapt a operatorului de comparaie. nainte de versiunea Oracle8i, subcererile nu puteau s conin clauza ORDER BY. ncepnd cu Oracle8i, clauza ORDER BY poate fi utilizat i este chiar obligatorie n subcerere pentru a efectua analiza top-n (cererea care efectueaz analiza top-n returneaz cele mai mari sau cele mai mici n valori ale unei coloane). Operatorul folosit trebuie s fie conform cu tipul cererii. Cererea va

genera o eroare dac este utilizat un operator single-row n faa unei subcereri care returneaz mai mult de o linie. De asemenea, dac subcererea nu returneaz nici o linie, apare o eroare. Server-ul Oracle nu impune nici o limit asupra numrului de subcereri. Limita acestora depinde de dimensiunea buffer-ului pe care l utilizeaz cererea. Exemple: Afiai toate limbile n care nu exist nici un film n inventarul magazinului de produse video. SELECT LIMBA_COD, LIMBA_NUME FROM LIMBA WHERE LIMBA_COD NOT IN (SELECT DISTINCT LIMBA_COD FROM FILM_LIMBA) ORDER BY LIMBA_COD LIMBA_COD Ja Ko ni ru zh LIMBA_NUME Japoneza Coreana Olandeza Rusa Chineza

Interogarea intern returneaz o list cu codurile de limb asociate filmelor n tabelul FILM_LIMBA. Cuvntul cheie DISTINCT elimin rndurile duplicate din setul de rezultate . Interogarea intern rulat independent, pentru a v ajuta s nelegei cum funcioneaz: SELECT DISTINCT LIMBA_COD FROM FILM_LIMBA; LIMBA_COD ------------------------------------------de (Germana) en (Engleza) es (Spaniola) fr (Franceza)

Proprietarul magazinului vrea s vad efectul recentei creteri de preuri i are nevoie de o list a tranzaciilor (TRANZACTIE_ID) n care clientul a pltit mai mult dect taxa medie (INCHIRIAT_TAXA) pentru un film. Iat cum arat interogarea: SELECT DISTINCT TRANZACTIE_ID FROM FILM_INCHIRIAT WHERE INCHIRIAT_TAXA> (SELECT AVG(INCHIRIAT_TAXA) FROM FILM_INCHIRIAT) Interogarea intern calculeaz media taxelor de nchiriere, iar interogarea extern gsete apoi toate rndurile din tabelul FILM_INCHIRIAT pentru care valoarea INCHIRIAT_TAXA depete media. Cuvntul cheie DISTINCT elimin tranzaciile duplicate. Rezultatele interogrii anterioare ar fi mai utile pentru proprietarul magazinului dac ar include i data tranzaciei. O modalitate de a realiza acest lucru este i adugm o uniune cu tabelul CLIENT_TRANZACTIE n interogarea extern. Totui, deoarece tocmai ai nvat despre subinterogari, s facem acelai lucru folosind nc o subinterogare. Iat cum arat interogarea: SELECT TRANZACTIE_ID, TRANZACTIE_DATA AS TRANZ_DATA FROM CLIENT_TRANZACTIE WHERE TRANZACTIE_ID IN (SELECT DISTINCT TRANZACTIE_ID FROM FILM_INCH, WHERE INCH_TAXA > (SELECT AVG ( INCHIRIAT_TAXA) FROM FILM_INCHIRIAT) TRANZACTIE_ID TRANZ_DATA 9 03/01/2005 10 03/01/2005 Exemplu(din galeria de arta): a) S se afieze titlul, codul artistului i valoarea operelor create de artistul cruia i aparine opera avnd codul 180 i care se afl expuse n aceeai galerie cu operele al cror cod este 100 sau 110. Se presupune c o oper are un singur autor. SELECT titlu, cod_artist, valoare FROM opera WHERE cod_artist = (SELECT cod_artist

AND

FROM opera WHERE cod_opera = 180) cod_galerie IN (SELECT cod_galerie FROM opera WHERE cod_opera IN (100, 110));

b) S se determine artistul pentru care valoare medie a operelor sale de art este minim. SELECT cod_artist, AVG(valoare) FROM opera GROUP BY cod_artist HAVING AVG(valoare) = (SELECT MIN(AVG(valoare)) FROM opera GROUP BY cod_artist); c) Pentru fiecare artist, s se afieze titlul i valoarea celei mai ieftine opere de art expuse n muzeu. SELECT titlu, cod_artist, valoare FROM opera WHERE valoare IN (SELECT MIN(valoare) FROM opera GROUP BY cod_artist); d) S se afieze operele de art care nu sunt expuse n galeria avnd codul 30 i a cror valoare este mai mic dect a unei opere din galeria 30. SELECT cod_opera, titlu, valoare FROM opera WHERE valoare < ANY (SELECT valoare FROM opera WHERE cod_galerie = 30) AND cod_galerie <> 30; Dac operatorul ANY se nlocuiete cu operatorul ALL, cererea precedent returneaz operele care nu sunt expuse n galeria 30 i a cror valoare este mai mic dect a oricrei opere din galeria respectiv. e) S se afieze cele mai scumpe 3 opere de art din muzeu. SELECT ROWNUM "Nr.Crt", titlu, valoare FROM (SELECT titlu, valoare FROM opera ORDER BY valoare DESC)

WHERE ROWNUM <= 3; Exemplu: Din punct de vedere logic, urmtoarea cerere ar trebui s returneze titlurile operelor care nu sunt expuse n galeriile unde se afl lucrrile artistului avnd codul 60. SELECT titlu FROM opera WHERE cod_galerie NOT IN (SELECT cod_galerie FROM opera WHERE cod_artist = 60); Dac pentru una dintre opere valoarea coloanei cod_galerie este null, ntreaga cerere nu va returna nici o linie, chiar dac exist nregistrri cu proprietatea cerut. Justificarea este c toate condiiile n care unul dintre operanzi este null au, de asemenea, valoarea null. Prin urmare, ori de cte ori este posibil ca n rezultatul subcererii s apar valori null, nu trebuie folosit operatorul NOT IN. Operatorul NOT IN este echivalent cu <>ALL. Dac se utilizeaz operatorul IN, nu mai este nici o problem dac n rezultatul subcererii apar valori null. Operatorul IN este echivalent cu =ANY. Exemplu: S se afieze titlurile operelor care sunt expuse n galeriile unde se afl lucrrile artistului avnd codul 60. SELECT titlu FROM opera WHERE cod_galerie IN (SELECT cod_galerie FROM opera WHERE cod_artist = 60); Pentru a evita obinerea de valori null n rezultatul unei cereri care utilizeaz operatorul NOT IN, se poate specifica o condiie n subcerere: SELECT titlu FROM opera WHERE cod_galerie NOT IN (SELECT cod_galerie FROM opera WHERE cod_artist = 60 AND cod_galerie IS NOT NULL);

Subcereri (Subinterogri) corelate (incuibarite sau sincronizate) O subinterogare corelat (correlated subselect) este o subinterogare n care interogarea intern refer valorile furnizate de interogarea extern. Subcererile corelate sunt utilizate pentru procesarea linie cu linie a interogrilor. O subcerere este corelat dac face referin la o coloan dintr-un tabel specificat n instruciunea printe. O astfel de subcerere este evaluat o dat pentru fiecare linie procesat de instruciunea printe, care poate fi SELECT, UPDATE sau DELETE. Subcererile corelate permit compararea valorilor unei linii cu date determinate pe baza acestor valori. Cererile corelate se execut astfel: cererea extern determin o linie candidat; cererea intern este executat utiliznd valoarea liniei candidat; valorile rezultate din cererea intern sunt utilizate pentru calificarea sau descalificarea liniei candidat; paii precedeni se repet pn cnd nu mai exist linii candidat. Forma general a unei subcereri corelate este urmtoarea: SELECT nume_coloan_1[, nume_coloan_2 ] FROM nume_tabel_1 extern WHERE expresie operator (SELECT nume_coloan_1 [, nume_coloan_2 ] FROM nume_tabel_2 WHERE expresie_1 = extern.expresie_2);

Exemplu: Proprietarul magazinului vrea s transmit prin pot un cupon valoric tuturor clienilor care au pltit mai mult de 15$ pentru o singur tranzacie de nchiriere. SELECT DISTINCT CLIENT_CONT_ID FROM CLIENT_TRANZACTIE A WHERE 15 < (SELECT SUM (INCHIRIAT_TAXA) FROM FILM_INCHIRIATB WHERE A.TRANZACTIE _ID = B.TRANZACTIE_ID) CLIENT_CONT_ID

2 7 9 Observai pseudonimele asociate numelor de tabele din interogrile intern i extern, precurn i folosirea acestora n clauza WHERE a interogrii interne. Acesta este elementul de identificare al unei subinterogri corelate. Interogarea extern selecteaz o lista de valori CLIENT_CONT_ID distincte din tabelul CLIENT_TRANZACTIE. Fiecare valoare gsit este transmis interogrii interne, care este rulat pentru a calcula suma taxelor de nchiriere din tranzacia respectiv. Dac suma taxelor de nchiriere este mai mare sau egal cu 15, atunci clauza WHERE din interogarea extern ia valoarea logic adevrat", iar rndul CLIENT_ID este adugat n setul de rezultate. Vizualizri n linie Foarte puine implementri, printre care Oracle, permit folosirea unei subinterogri n clauza FROM a unei interogri, ntr-o construcie numit vizualizare n linie (inline view). Aceast construcie permite care setul de rezultate al unei interogri s fie tratat ca i cum ar fi un tabel sau o vizualizare predefinit. Iat un exemplu: Aceast interogare afl numrul maxim de nchirieri ale unui singur film; SELECT MAX(INCHIRIAT_NUMAR) AS MAX_INCHIRIAT_NUMAR FROM (SELECT FILM_ID, NUMAR(*) AS INCHIRIAT_NUMAR FROM FILM_INCHIRIAT GROUP BY FILM_ID) MAX_INCH_NUMAR 5 Interogarea intern calculeaz numrul de nchirieri pentru fiecare valoare FILM_ID. Interogarea extern selecteaz valoarea maxim INCHIRIAT_NUMAR din interogarea intern, tratat ca i cum ar fi o vizualizare predefinit. Nu exist nici o limit n privina modurilor de utilizare a vizualizrilor n linie - putei chiar s le unii cu alte tabele sau vizualizri. Exemplu de subcereri corelate pentru galeria de arta): a) S se afieze informaii despre operele de art a cror valoare depete valoarea medie a celor expuse n aceeai galerie.

SELECT titlu, valoare, cod_galerie FROM opera o WHERE valoare > (SELECT AVG(valoare) FROM opera WHERE cod_galerie = o.cod_galerie); b) S se afieze codul, numele i prenumele artitilor care au cel puin dou opere de art expuse n muzeu. SELECT cod_artist, nume, prenume FROM artist a WHERE 2 <= (SELECT COUNT(*) FROM opera WHERE cod_artist = a.cod_artist); Server-ul Oracle evalueaz subcererea corelat precedent urmnd succesiunea de pai prezentat n continuare. 1) Selecteaz o linie din tabelul specificat n cererea extern (aceasta va fi linia candidat curent). 2) Reine valoarea coloanei referite n subcerere din aceast linie candidat (n cazul subcererii de mai sus, coloana referit n subcerere este a.cod_artist). 3) Efectueaz subcererea, considernd condiia acesteia ca facnd referin la valoarea liniei candidat din cererea extern (n exemplul precedent, funcia COUNT(*) este evaluat pe baza valorii lui a.cod_artist determinat la pasul 2). 4) Evalueaz clauza WHERE a cererii externe pe baza rezultatelor returnate de cererea intern la pasul 3. Adic, se determin dac linia candidat este selectat n rezultatul cererii (n exemplul precedent, numrul de opere ale unui artist, evaluat de subcerere, este comparat cu 2 n clauza WHERE a cererii externe, iar dac aceast condiie este satisfcut, linia corespunztoare artistului respectiv va face parte din rezultat). 5) Procedura se repet pentru urmtoarele linii candidat din tabel, pn cnd sunt procesate toate liniile tabelului. Operatorul EXISTS n instruciunile SELECT imbricate, este permis utilizarea oricrui operator logic. Pentru a testa dac valoarea recuperat de cererea extern exist n mulimea valorilor regsite de cererea intern corelat, se poate utiliza operatorul EXISTS. Dac subcererea returneaz cel puin o linie, operatorul returneaz valoarea TRUE. n caz contrar, va fi returnat valoarea FALSE.

Operatorul EXISTS asigur c nu mai este continuat cutarea n cererea intern dup ce aceasta regsete o linie. Exemplu: a) S se determine codul, numele i prenumele artitilor care au cel puin o oper de art expus n muzeu. SELECT cod_artist, nume, prenume FROM artist a WHERE EXISTS (SELECT 'x' FROM opera WHERE cod_artist = a.cod_artist); ntruct nu este necesar ca instruciunea SELECT interioar s returneze o anumit valoare, se poate selecta o constant. De altfel, din punct de vedere al performanei, selectarea unei constante asigur mai mult rapiditate dect selectarea unei coloane. Ca alternativ a lui EXISTS, poate fi utilizat operatorul IN. Exemplul precedent poate fi rezolvat prin instruciunea urmtoare: SELECT cod_artist, nume, prenume FROM artist WHERE cod_artist IN (SELECT cod_artist FROM opera); b) S se determine operele care nu sunt menionate n nici o surs bibliografic. SELECT cod_opera, titlu FROM opera o WHERE NOT EXISTS (SELECT 'x' FROM mentionata_in WHERE cod_opera = o.cod_opera); Acest exemplu poate fi rezolvat i printr-o subcerere necorelat, utiliznd operatorul NOT IN: SELECT cod_opera, titlu FROM opera WHERE cod_opera NOT IN (SELECT cod_opera FROM ment_in WHERE cod_opera IS NOT NULL);

Clauza WITH Cu ajutorul clauzei WITH se poate defini un bloc de cerere nainte ca acesta s fie utilizat ntr-o interogare. Clauza permite reutilizarea aceluiai bloc de cerere ntr-o instruciune SELECT complex. Acest lucru este util atunci cnd o cerere face referin de mai multe ori la acelai bloc de cerere, care conine operaii join i funcii agregat. Folosind clauza WITH, server-ul Oracle regsete rezultatele unui bloc de cerere i le stocheaz n spaiul tabel temporar al utilizatorului, ceea ce poate determina mbuntirea performanelor. Exemplu: Utiliznd clauza WITH, s se scrie o cerere care afieaz numele artitilor i valoarea total a operelor acestora. Se vor considera artitii a cror valoare total a operelor este mai mare dect media valorilor totale ale operelor tuturor artitilor. WITH val_artist AS (SELECT nume, SUM(valoare) AS total FROM opera o, artist a WHERE o.cod_artist = a.cod_artist GROUP BY nume), val_medie AS (SELECT SUM(total)/COUNT(*) AS medie FROM val_artist) SELECT * FROM val_artist WHERE total > (SELECT medie FROM val_medie) ORDER BY nume; Intern, clauza WITH este tratat ca o vizualizare inline (subcerere n clauza FROM) sau ca un tabel temporar. Optimizorul alege decizia adecvat pe baza costului sau beneficiului stocrii temporare a rezultatelor clauzei WITH. Observaii: Clauza WITH poate fi folosit numai pentru instruciuni SELECT. Un nume de cerere este vizibil tuturor blocurilor din clauza WITH definite ulterior (inclusiv subcererilor acestora). De asemenea, un nume de cerere este vizibil cererii principale i subcererilor acesteia. Cnd un nume de cerere coincide cu numele unui tabel, numele blocului de cerere are preceden asupra numelui tabelului. Clauza WITH poate conine mai mult dect o singur cerere. n acest caz, cererile sunt separate prin virgule.

2.4.4. Funcii grup i clauza GROUP BY Clauza GROUP BY este utilizat pentru a diviza liniile unui tabel n grupuri. Pentru a returna informaia corespunztoare fiecrui astfel de grup, pot fi utilizate funciile agregat. Ele pot aprea n clauzele SELECT, ORDER BY i HAVING. Server-ul Oracle aplic aceste funcii fiecrui grup de linii i returneaz un singur rezultat pentru fiecare mulime. Dintre funciile grup definite n sistemul Oracle, se pot enumera: AVG, SUM, MAX, MIN, COUNT, STDDEV, VARIANCE, DENSE_RANK, RANK, FIRST, LAST, GROUP_ID, GROUPING, GROUPING_ID etc. Tipurile de date ale argumentelor funciilor grup pot fi CHAR, VARCHAR2, NUMBER sau DATE. Funciile AVG, SUM, STDDEV i VARIANCE opereaz numai asupra valorilor numerice. Funciile MAX i MIN pot opera asupra valorilor numerice, caracter sau de tip dat calendaristic. Toate funciile grup, cu excepia lui COUNT(*), ignor valorile null. COUNT(expresie) returneaz numrul de linii pentru care expresia dat nu are valoarea null. Funcia COUNT returneaz un numr mai mare sau egal cu zero i nu ntoarce niciodat valoarea null. Cnd este utilizat clauza GROUP BY, server-ul sorteaz implicit mulimea rezultat n ordinea cresctoare a valorilor coloanelor dup care se realizeaz gruparea. n clauza GROUP BY a unei cereri se pot utiliza operatorii ROLLUP i CUBE. Acetia sunt disponibili ncepnd cu versiunea Oracle8i. Operatorul ROLLUP Operatorul ROLLUP produce o mulime care conine liniile obinute n urma gruprii obinuite i linii pentru subtotaluri. Acest operator furnizeaz valori agregat i superagregat corespunztoare expresiilor din clauza GROUP BY. Operatorul ROLLUP poate fi folosit pentru extragerea de statistici i informaii totalizatoare din mulimile rezultate. Acest operator poate fi util la generarea de rapoarte, diagrame i grafice. Operatorul ROLLUP creeaz grupri prin deplasarea ntr-o singur direcie, de la dreapta la stnga, de-a lungul listei de coloane specificate n clauza GROUP BY. Apoi, se aplic funcia agregat acestor grupri. Dac sunt specificate n expresii n operatorul ROLLUP, numrul de grupri generate va fi n + 1. Liniile care se bazeaz pe valoarea primelor n expresii se numesc linii obinuite, iar celelalte se numesc linii superagregat. Dac n clauza GROUP BY sunt specificate n coloane, pentru a produce subtotaluri fr operatorul ROLLUP ar fi necesare n + 1 instruciuni SELECT

conectate prin UNION ALL. Aceasta ar face execuia cererii ineficient deoarece fiecare instruciune SELECT determin accesarea tabelului. Operatorul ROLLUP determin rezultatele efectund un singur acces la tabel i este util atunci cnd sunt implicate multe coloane n producerea subtotalurilor. Exemplu: S se afieze codurile de galerii mai mici dect 50, iar pentru fiecare dintre acestea i pentru fiecare autor care are opere expuse n galerie, s se listeze valoarea total a lucrrilor sale. De asemenea, se cere valoarea total a operelor expuse n fiecare galerie. Rezultatul va conine i valoarea total a operelor din galeriile avnd codul mai mic dect 50, indiferent de codul autorului. SELECT cod_galerie, cod_artist, SUM(valoare) FROM opera WHERE cod_galerie < 50 GROUP BY ROLLUP(cod_galerie, cod_artist); Instruciunea precedent va avea un rezultat de forma: COD_GALERIE 10 10 10 40 40 COD_ARTIST 50 60 50 SUM(VALOARE) 14000 10000 24000 8080 8080 32080

n rezultatul prezentat anterior se pot distinge 3 tipuri de linii. 1) Prima linie reprezint suma operelor artistului care are codul 50, expuse n galeria avnd codul 10. n mod similar se interpreteaz a doua i a patra linie din rezultat. 2) Linia a treia i a cincea din rezultat conin valoarea total a operelor din galeria al crei cod este 10, respectiv 40. Aceste linii se disting prin faptul c valoarea coloanei cod_artist este null. 3) Ultima linie conine suma valorilor tuturor operelor din galeriile al cror cod este 10 sau 40. Valoarea afiat este obinut prin nsumarea valorilor de pe a treia, respectiv a cincea linie. ntruct aceast linie corespunde totalului general, ea conine valoarea null pe toate coloanele, cu excepia

cmpului SUM(valoare). Operatorul CUBE Operatorul CUBE grupeaz liniile selectate pe baza valorilor tuturor combinaiilor posibile ale expresiilor specificate i returneaz cte o linie totalizatoare pentru fiecare grup. Acest operator este folosit pentru a produce mulimi de rezultate care sunt utilizate n rapoarte. n vreme ce ROLLUP produce subtotalurile doar pentru o parte dintre combinaiile posibile, operatorul CUBE produce subtotaluri pentru toate combinaiile posibile de grupri specificate n clauza GROUP BY, precum i un total general. Dac exist n coloane sau expresii n clauza GROUP BY, vor exista 2n combinaii posibile superagregat. Din punct de vedere matematic, aceste combinaii formeaz un cub n-dimensional, de aici provenind numele operatorului. Pentru producerea de subtotaluri fr ajutorul operatorului CUBE ar fi necesare 2n instruciuni SELECT conectate prin UNION ALL. Exemplu: S se afieze valoarea total a operelor de art ale unui autor, expuse n cadrul fiecrei galerii avnd codul mai mic dect 50. De asemenea, s se afieze valoarea total a operelor din fiecare galerie avnd codul mai mic dect 50, valoarea total a operelor fiecrui autor indiferent de galerie i valoarea total a operelor din galeriile avnd codul mai mic dect 50. SELECT cod_galerie, cod_artist, SUM(valoare) FROM opera WHERE cod_galerie < 50 GROUP BY CUBE(cod_galerie, cod_artist); Instruciunea precedent va genera un rezultat de forma urmtoare: COD_GALERIE 10 10 10 40 40 COD_ARTIST 50 60 50 50 60 SUM(VALOARE) 14000 10000 24000 8080 8080 22080 10000

32080 n plus fa de rezultatul corespunztor operaiei ROLLUP, operatorul CUBE a produs linii care reprezint suma valorilor operelor pentru fiecare artist care a expus n galerii avnd codul mai mic dect 50. Aceste linii se disting prin faptul c valoarea coloanei cod_galerie este null. Funcia GROUPING Funcia GROUPING poate fi utilizat alturi de operatorii CUBE i ROLLUP pentru a arta modul cum a fost obinut o valoare totalizatoare. Aceast funcie accept un singur argument, care trebuie s fie una dintre expresiile specificate n clauza GROUP BY. O valoare null a expresiei din argumentul funciei GROUPING poate proveni din tabelul de baz (valoare null stocat) sau poate fi o valoare null creat de operaia ROLLUP sau CUBE ca rezultat al unei funcii grup asupra expresiei respective. Funcia GROUPING returneaz valoarea 0 sau 1. Valoarea 0 returnat de funcia GROUPING pe baza unei expresii poate indica fie c expresia a fost utilizat pentru calculul valorii agregat, fie c valoarea null a expresiei este o valoare null stocat. Valoarea 1 returnat de funcia GROUPING pe baza unei expresii poate indica fie c expresia nu a fost utilizat pentru calculul valorii agregat, fie c valoarea null a expresiei este creat de ROLLUP sau CUBE ca rezultat al gruprii. Valorile returnate de funcia GROUPING sunt utile pentru: determinarea nivelului de agregare al unui subtotal dat, adic a grupului sau grupurilor pe care se bazeaz subtotalul respectiv; identificarea provenienei unei valori null a unei expresii calculate, dintruna din liniile mulimii rezultat. Exemplu: SELECT cod_galerie, cod_artist, SUM(valoare), GROUPING(cod_galerie), GROUPING(cod_artist) FROM opera WHERE cod_galerie < 50 GROUP BY ROLLUP(cod_galerie, cod_artist); COD_GALERIE COD_ARTIST 10 SUM GROUPING GROUPING (VALOARE) (COD_GALERIE) (COD_ARTIST) 50 14000 0 0

10 10 40 40

60 50

10000 24000 8080 8080 32080

0 0 0 0 1

0 1 0 1 1

Pe prima linie din acest rezultat, valoarea totalizatoare reprezint suma valorilor operelor artistului avnd codul 50, n cadrul galeriei 10. Pentru a calcula aceast valoare au fost luate n considerare coloanele cod_galerie i cod_artist. Prin urmare, expresiile GROUPING(cod_galerie) i GROUPING(cod_artist) au valoarea 0 pentru prima linie din rezultat. Pe linia a treia se afl valoarea total a operelor din galeria avnd codul 10. Aceast valoare a fost calculat lund n considerare doar coloana cod_galerie, astfel nct GROUPING (cod_galerie) i GROUPING(cod_artist) au valorile 0, respectiv 1. Pe ultima linie din rezultat se afl valoarea total a operelor din galeriile avnd codul mai mic dect 50. Nici una dintre coloanele cod_galerie i cod_artist nu au intervenit n calculul acestui total, prin urmare valorile corespunztoare expresiilor GROUPING(cod_galerie) i GROUPING(cod_artist) sunt 0. Clauza GROUPING SETS GROUPING SETS reprezint o extensie a clauzei GROUP BY care permite specificarea unor grupri multiple de date. Utilizarea acestei opiuni faciliteaz analiza datelor n mai multe dimensiuni. Aceast extensie, aprut n sistemul Oracle9i, permite scrierea unei singure instruciuni SELECT pentru a specifica grupri diferite (care pot conine operatorii ROLLUP i CUBE), n loc de mai multe instruciuni SELECT combinate prin operatorul UNION ALL. De altfel, reuniunea rezultatelor mai multor cereri este ineficient ntruct necesit mai multe parcurgeri ale acelorai date. Operatorii ROLLUP i CUBE pot fi considerai cazuri particulare de mulimi de grupri. Au loc urmtoarele echivalene: CUBE(a, b, c) GROUPING SETS ((a, b, c), (a, b), (a, c), (b, c), (a), (b), (c), ()) ROLLUP(a, b, GROUPING SETS c) ((a, b, c), (a, b), (a), ()) Exemplu: Considernd galeriile al cror cod este mai mic dect 50, s se calculeze media valorilor operelor:

pentru fiecare galerie i, n cadrul acesteia, pentru fiecare artist; pentru fiecare artist i, n cadrul acestuia, pentru anii de achiziie corespunztori. SELECT cod_galerie, cod_artist, TO_CHAR(data_achizitiei, 'yyyy') "an achizitie", AVG(valoare) "Valoare medie" FROM opera WHERE cod_galerie < 50 GROUP BY GROUPING SETS ((cod_galerie, cod_artist), (cod_artist, TO_CHAR(data_achizitiei, 'yyyy'))); Mulimea rezultat este constituit din valorile medii pentru fiecare dintre cele dou grupuri i are forma urmtoare: COD_GALERIE COD_ARTIST 10 50 10 60 40 50 50 50 60 60 an a Valoare medie 3500 2500 2020 2380 2300 2000 3000

2000 2002 2001 2003

Exemplul precedent poate fi rezolvat i prin urmtoarea instruciune compus: SELECT cod_galerie, cod_artist, NULL "an achizitie", AVG(valoare) "Valoare medie" FROM opera GROUP BY cod_galerie, cod_artist UNION ALL SELECT NULL, cod_artist, TO_CHAR(data_achizitiei, 'yyyy'), AVG(valoare) FROM opera GROUP BY cod_artist, TO_CHAR(data_achizitiei, 'yyyy'); n absena unui optimizor care analizeaz blocurile de cerere i genereaz planul de execuie, cererea precedent va parcurge de dou ori tabelul de baz (opera), ceea ce poate fi ineficient. Din acest motiv, este recomandat utilizarea

extensiei GROUPING SETS. Concatenarea gruprilor Concatenarea gruprilor reprezint o modalitate concis de a genera combinaii de grupri. Acestea se specific prin enumerarea mulimilor de grupri (grouping sets) i a operaiilor ROLLUP, CUBE separate prin virgul. De exemplu, expresia GROUP BY GROUPING SETS(a, b), GROUPING SETS(c, d) definete gruprile (a, c), (a, d), (b, c), (b, d). Concatenarea mulimilor de grupri este util att pentru uurina dezvoltrii cererilor, ct i pentru aplicaii. Codul SQL generat de aplicaiile OLAP implic deseori concatenarea mulimilor de grupri, n care fiecare astfel de mulime definete gruprile necesare pentru o dimensiune. Exemplu: S se determine media valorilor operelor lund n considerare urmtoarele grupri: (cod_galerie, cod_artist, an_achizitie), (cod_galerie, cod_artist), (cod_galerie, an_achizitie), (cod_galerie). SELECT cod_galerie, cod_artist, TO_CHAR(data_achizitiei, 'yyyy') an_achizitie, AVG(valoare) FROM opera GROUP BY cod_galerie, ROLLUP(cod_artist), CUBE(TO_CHAR(data_achizitiei, 'yyyy'));

PROBLEME-SUBCERERI De cele mai multe ori, pentru a implementa anumite interogri, nu este suficient o singur cerere SELECT ci sunt necesare subcereri. Subcererile sunt comenzi SELECT ncapsulate n oricare din clauzele SELECT, WHERE, HAVING, FROM. Dac subcererea urmeaz clauzei WHERE sau HAVING, ea poate conine unul dintre operatorii ALL, ANY, IN (=ANY), EXIST, NOT IN (!=ALL) care sunt specifici cererilor care ntorc mai multe linii (multiple-row subquery) sau unul dintre operatorii de comparare (=, <, >, >=, <=, <>) care sunt specifici cererilor care ntorc o singur linie (single-row subquery). Subcererile trebuie incluse ntre paranteze i trebuie plasate n partea dreapt a operatorului de comparare. Subcererea nu poate conine clauza ORDER BY. Exemplu: S se obin numele salariailor, salariile, codul departamentului n care lucreaz i salariul mediu pe departament pentru toi angajaii care au salariul mai mare ca media salariilor din departamentul n care lucreaz (folosirea subcererii n clauza FROM). SELECT a.nume, a.sal, a.cod_dep, b.salavg FROM angajati a, (SELECT dept ,avg(sal) salavg FROM angajati GROUP BY cod_dep) b WHERE a. cod_dep =b. cod_dep AND a.sal>b.salavg Exemplu: S se obin lista celor mai scumpe cri. SELECT titlu FROM carte WHERE pret = (SELECT FROM carte);

MAX(pret)

Exemplu: S se obin lista scriitorilor care au n bibliotec un numr de exemplare mai mare dect numrul mediu al crilor din bibliotec. SELECT FROM DISTINCT autor carte

WHERE

nrex > (SELECT AVG(nrex) FROM carte);

Exemplu: S se obin informaii despre crile al cror pre depete media preurilor crilor ce aparin aceluiai domeniu SELECT FROM WHERE * carte c pret > (SELECT AVG(pret) FROM carte WHERE coded = c.coded);

Exemplu: S se obin lista cititorilor care au mprumutat cel puin o carte. SELECT FROM WHERE nume cititor codec IN (SELECT DISTINCT codec FROM imprumuta);

Exemplu: S se obin codurile cititorilor care nu au mprumutat niciodat cri. SELECT FROM WHERE codec cititor codec NOT IN (SELECT DISTINCT codec FROM imprumuta);

Exemplu: S se obin lista cititorilor care sunt n ntrziere cu predarea crilor. SELECT FROM WHERE nume cititor codec IN (SELECT FROM WHERE AND DISTINCT codec imprumuta dataef IS NULL dares<SYSDATE);

Exemplu: S se obin numele cititorilor care au mprumutat cel puin o carte scris de ZOLA. SELECT FROM WHERE nume cititor codec IN (SELECT DISTINCT codec

FROM imprumuta WHERE codel IN (SELECT codel FROM carte WHERE autor=ZOLA)); Exemplu: S se obin numele cititorilor care nu au mprumutat nici o carte scris de ZOLA. SELECT FROM WHERE nume cititor codec NOT IN (SELECT DISTINCT codec FROM imprumuta WHERE codel IN (SELECT codel FROM carte WHERE autor=ZOLA));

Operatorul IN poate fi nlocuit cu = ANY (un element este n list dac i numai dac este egal cu un element al listei), iar operatorul NOT IN poate fi nlocuit prin !=ALL. Exemplu: S se obin codurile cititorilor care au mprumutat o carte de algebr. SELECT DISTINCT codec FROM imprumuta WHERE codel IN (SELECT codel FROM carte WHERE coded= (SELECT coded FROM domeniu WHERE intdom=ALGEBRA)); Exemplu: S se obin cititorii care au mprumutat numai cri scrise de ZOLA. SELECT FROM WHERE nume cititor codec NOT IN (SELECT DISTINCT codec FROM imprumuta WHERE codel NOT IN

(SELECT codel FROM carte WHERE autor=ZOLA)); Exemplu: S se obin numele cititorilor care au mprumutat cel puin o carte de informatic (procedural). SELECT nume FROM cititor WHERE codec IN (SELECT DISTINCT codec FROM imprumuta WHERE codel IN (SELECT codel FROM carte WHERE coded= (SELECT coded FROM domeniu WHERE intdom= INFORMATICA))); Exemplu: S se obin numele cititorilor i titlurile crilor de informatic mprumutate de aceti cititori (relational). SELECT FROM WHERE AND AND AND nume, titlu cititor, carte, imprumuta, domeniu imprumuta.codel = carte.codel carte.coded = domeniu.coded imprumuta.codec = cititor.codec intdom = INFORMATICA;

Subcererile pot fi executate corelat (cu sincronizare) sau ncuibrit (fr sincronizare). Subcererile fr sincronizare sunt caracterizate de faptul c se execut cererea cea mai interioar care ntoarce un rezultat ce este transmis cererii de nivel superior, care ntoarce un rezultat s.a.m.d. Subcererile cu sincronizare sunt caracterizate de faptul c evaluarea subcererii face referin la o coloan a cererii principale, iar evaluarea cererii interioare se face pentru fiecare linie a cererii (principale) care o conine.

Exemplu: S se obin, utiliznd sincronizarea subcererii cu cererea principal, titlurile crilor care au toate exemplarele mprumutate (se selecteaz un titlu din carte i pentru acest titlu se numr cte exemplare sunt mprumutate). SELECT FROM WHERE titlu carte nrex=(SELECT FROM WHERE AND COUNT(*) imprumuta codel = carte.codel dataef IS NULL);

Exemplu: S se obin codurile cititorilor i codul ultimei cri mprumutate. SELECT FROM WHERE codec, codel imprumuta i dataim>=ALL (SELECT dataim FROM imprumuta WHERE codec=i.codec); dataim=(SELECT MAX(dataim) FROM imprumuta WHERE codec=i.codec);

Pentru aceast interogare, clauza WHERE putea fi scris i sub forma: WHERE

Exemplu: S se obin lista codurilor crilor mprumutate i codul primului cititor care a mprumutat aceste crti. SELECT FROM WHERE codel,codec imprumuta i dataim<=ALL (SELECT dataim FROM imprumuta WHERE i.codel=codel);

Exemplu: S se obin codurile crilor din care cel puin un exemplar este mprumutat. SELECT FROM WHERE codel carte EXISTS (SELECT codel FROM imprumuta

WHERE AND

codel = carte.codel dataef IS NULL);

Operatorul WHERE EXISTS (subcerere) presupune c predicatul este adevrat dac subcererea ntoarce cel puin un tuplu, iar WHERE NOT EXISTS (subcerere) presupune c predicatul este adevrat dac subcererea nu ntoarce nici un tuplu. EXISTS i NOT EXISTS cer sincronizarea subcererii. Exemplu: S se obin titlurile crilor care sunt momentan mprumutate. Soluia 1 (cu sincronizare): SELECT titlu FROM carte WHERE EXISTS (SELECT * FROM WHERE AND

imprumuta codel = carte.codel dataef IS NULL);

Soluia 2 (fr sincronizare): SELECT titlu FROM carte WHERE codel IN (SELECT DISTINCT codel FROM imprumuta WHERE dataef IS NULL); Exemplu: S se obin codurile crilor care nu au fost mprumutate niciodat. Soluia 1 (cu sincronizare) SELECT codel FROM carte WHERE NOT EXISTS (SELECT FROM WHERE Soluia 2 (fr sincronizare) SELECT FROM WHERE codel carte codel NOT IN (SELECT DISTINCT codel

codel imprumuta codel = carte.codel);

FROM

imprumuta);

Exemplu: S se obin lista salariailor avnd salariul minim n departamentul n care lucreaz. SELECT FROM WHERE ename,sal emp e sal=(SELECT FROM WHERE

MIN(sal) emp deptno=e.deptno);

Exemplu: S se obin numele primilor trei salariai avnd retribuia maxim (ideea rezolvrii este de a verifica dac numrul salariailor care au leafa mai mare dect leafa salariatului considerat, este mai mic dect 3). SELECT FROM WHERE ename emp a 3>(SELECT COUNT(*) FROM emp WHERE sal > a.sal);

Exemplu: S se obin numele cititorilor care au mprumutat cel puin aceleai cri ca i cititorul avnd codul C19 (ideea problemei este de a selecta cititorii pentru care este vid lista crilor mprumutatede C19 mai puin lista crilor mprumutate de acei cititori). SELECT nume FROM cititor WHERE NOT EXISTS (SELECT codel FROM imprumuta WHERE codec=C19 MINUS SELECT codel FROM imprumuta WHERE codec= cititor.codec); Dac problema era modificat n sensul c cel puineste nlocuit prin cel mult atunci trebuiau inversate interogrile legate prin MINUS.

Exemplu: S se obin codurile cititorilor care au mprumutat aceleai cri ca i cititorul avnd un cod specificat. Rezolvarea problemei se bazeaz pe ideea: A = B A B i B A (AB) = i (B-A) = A-B i B-A nu furnizeaz nici un tuplu rezultat. SELECT codec FROM imprumuta i WHERE NOT EXISTS (SELECT codel FROM imprumuta WHERE codec=i.codec MINUS SELECT codel FROM imprumuta WHERE codec=&ccc) AND NOT EXISTS (SELECT codel FROM imprumuta WHERE codec=&ccc MINUS SELECT codel FROM imprumuta WHERE codec=i.codec) AND codec!=&ccc); Ultimul operator (AND), asigur s nu apar n rezultat cititorul specificat. n cazul formei relaionale de rezolvare a cererii, drumul de acces la informaie este n sarcina SGBD-lui i prin urmare nu mai apar cereri imbricate. Exemplu: S se obin numele cititorilor care au mprumutat cel puin o carte. Soluia 1 (forma relaional): SELECT DISTINCT nume FROM cititor,imprumuta WHERE cititor.codec=imprumuta.codec; Soluia 2 (forma procedural): SELECT nume FROM cititor WHERE codec IN (SELECT DISTINCT codec FROM imprumuta);

Exemplu: S se obin numele cititorilor care au mprumutat cel puin dou cri. Soluia 1 (forma relaional): SELECT nume FROM cititor, imprumuta WHERE cititor.codec=imprumuta.codec GROUP BY nume HAVING COUNT(*)>1; Soluia 2 (forma procedural): SELECT nume FROM cititor WHERE codec IN (SELECT codec FROM imprumuta GROUP BY codec HAVING COUNT(*)>1); Exemplu: S se afieze numele, prenumele, salariul lucrtorilor, codurile publicaiilor la care lucreaz i salariul mediu pe publicaie pentru toi angajaii care au salariul mai mare dect media salariului pe publicaia respectiv. SELECT s.nume, s.prenume, s.salariu, p.nr_publicatie, a.salariu_mediu FROM salariat s, publicatie p, (SELECT p1.nr_publicatie,AVG(salariu) salariu_mediu FROM publicatie p1, salariat s1 WHERE p1.cod_salariat = s1.cod_salariat GROUP BY p1.nr_publicatie) a WHERE p.nr_publicatie = a.nr_publicatie AND s.cod_salariat = p.cod_salariat AND s.salariu > a.salariu_mediu; Exemplu: S se obin numele salariailor care nu cunosc nici o limb strin. SELECT nume, prenume FROM salariat WHERE NOT EXISTS (SELECT * FROM limba WHERE limba.cod_salariat = salariat.cod_salariat AND limba_cun IS NOT NULL); Exemplu:

S se afieze graficienii care au ntrziat s predea frame-urile. a) cu sincronizare: SELECT nume, prenume FROM salariat WHERE EXISTS (SELECT * FROM realizeaza r WHERE salariat.cod_salariat=r.cod_salariat AND data_lim < SYSDATE); b) fr sincronizare: SELECT nume, prenume FROM salariat WHERE cod_salariat IN (SELECT DISTINCT cod_salariat FROM realizeaza WHERE data_lim < SYSDATE); Exemplu: S se determine revistele coordonate de redactori efi care nu cunosc limba n care sunt scrise. Se tie c n urma inspectrii vizuale a rezultatului interogrii se poate decide schimbarea redactorilor efi ai revistelor respective, de aceea se dorete blocarea nregistrrilor gsite. SELECT p.nr_publicatie FROM salariat s, publicatie p WHERE s.cod_salariat = p.cod_salariat AND p.limba NOT IN (SELECT limba_cun FROM limba WHERE limba.cod_salariat = s.cod_salariat) FOR UPDATE OF p.cod_salariat;

You might also like