Sunteți pe pagina 1din 155

SISTEME DE GESTIUNE A BAZELOR DE DATE (MySQL, ORACLE)

IOLU Mihai-Stefan 14 ianuarie 2011

ii

Cuprins
I MySQL
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

3
5 5 6 6 7 8 11 11 11 12 13 13 13 15 15 16 16 17 18 22 30 31 32 33 34 35 37 37 38 38

1 Prezentare general a 1.1 De ce MySQL? . . . . . . . . . . . . . . 1.2 Versiunea folosit . . . . . . . . . . . . . a 1.3 Arhitectura MySQL . . . . . . . . . . . 1.3.1 Instalare program i rulare server s 1.3.2 Invocarea programelor client . . .

2 Interogarea i actualizarea datelor s 2.1 Generaliti . . . . . . . . . . . . . . . . . . . . at 2.1.1 Literali MySQL . . . . . . . . . . . . n 2.1.2 Expresii . . . . . . . . . . . . . . . . . . 2.1.3 Asignarea de nume la coloane . . . . . . 2.1.4 Variabile utilizator i instructiunea SET s 2.1.5 Variabilele sistem . . . . . . . . . . . . . 2.1.6 Expresia CASE . . . . . . . . . . . . . . 2.1.7 Functii scalare . . . . . . . . . . . . . . . 2.1.8 Castingul expresiilor . . . . . . . . . . . 2.1.9 Expresii scalare compuse . . . . . . . . . 2.2 Interogarea SELECT . . . . . . . . . . . . . . . 2.2.1 Baza de date exemplu . . . . . . . . . . 2.2.2 Exemple de interogri . . . . . . . . . . a 2.3 Actualizarea datelor . . . . . . . . . . . . . . . 2.3.1 Interogarea INSERT . . . . . . . . . . . 2.3.2 Interogarea REPLACE . . . . . . . . . . 2.3.3 Interogarea UPDATE . . . . . . . . . . . 2.3.4 Interogarea DELETE . . . . . . . . . . . 2.3.5 Interogarea TRUNCATE . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

3 Crearea obiectelor bazei de date 3.1 Crearea unei baze de date . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.2 Tipuri de date . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.2.1 Tipuri numerice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . iii

3.3

3.4 3.5 3.6

3.7

3.8 3.9

3.2.2 Tipuri pentru iruri de caractere . . . . . . . . . s 3.2.3 Tipuri pentru lucrul cu date . . . . . . . . . . . 3.2.4 Alegerea ecient a tipurilor de date . . . . . . a Crearea tabelelor . . . . . . . . . . . . . . . . . . . . . 3.3.1 Crearea unor tabele simple . . . . . . . . . . . . 3.3.2 Copierea tabelelor . . . . . . . . . . . . . . . . . 3.3.3 Crearea tabelelor temporare . . . . . . . . . . . 3.3.4 Optiuni ale tabelelor . . . . . . . . . . . . . . . 3.3.5 Tabelele i catalogul MySQL . . . . . . . . . . . s 3.3.6 Specicarea constrngerilor de integritate . . . . a Stergerea tabelelor - DROP TABLE . . . . . . . . . . . Redenumirea tabelelor - RENAME TABLE . . . . . . Schimbarea structurii tabelului - ALTER TABLE . . . 3.6.1 Schimbarea coloanelor . . . . . . . . . . . . . . 3.6.2 Schimbarea constrngerilor de integritate . . . . a Lucrul cu indeci . . . . . . . . . . . . . . . . . . . . . s 3.7.1 Cum se retin datele? . . . . . . . . . . . . . . . 3.7.2 Ce este un index i cum functioneaz? . . . . . s a 3.7.3 Procesarea instructiunii SELECT . . . . . . . . 3.7.4 Crearea indecilor . . . . . . . . . . . . . . . . . s 3.7.5 Denirea indecilor s mpreun cu tabela . . . . . a 3.7.6 Stergerea indecilor . . . . . . . . . . . . . . . . s 3.7.7 Alegerea coloanelor pentru indeci . . . . . . . . s Optimizarea performantei interogrilor . . . . . . . . . a 3.8.1 Lucruri de baz relativ la executia interogrilor a a Utilizarea view-urilor . . . . . . . . . . . . . . . . . . . 3.9.1 Crearea de view-uri . . . . . . . . . . . . . . . . 3.9.2 Optiuni ale view-urilor . . . . . . . . . . . . . . 3.9.3 Stergerea view-urilor . . . . . . . . . . . . . . . 3.9.4 Restrictii referitoare la actualizarea view-urilor . 3.9.5 De ce sa folosim view-urile? . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

39 40 40 42 42 45 46 47 50 50 52 53 53 54 55 56 56 57 62 63 64 65 65 65 67 69 69 70 71 71 72 73 73 74 74 74 76 78 79 80 82 84

4 Crearea obiectelor procedurale 4.1 Proceduri stocate . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.1.1 Transmiterea parametrilor . . . . . . . . . . . . . . . . . . 4.1.2 Corpul procedurilor stocate . . . . . . . . . . . . . . . . . 4.1.3 Variabile locale i variabile utilizator . . . . . . . . . . . . s 4.1.4 Structuri de control . . . . . . . . . . . . . . . . . . . . . . 4.1.5 Apelarea procedurilor stocate . . . . . . . . . . . . . . . . 4.1.6 Interogarea datelor cu SELECT INTO . . . . . . . . . . . 4.1.7 Mesaje de eroare, handlere i conditii . . . . . . . . . . . . s 4.1.8 Folosirea cursoarelor . . . . . . . . . . . . . . . . . . . . . 4.1.9 Specicarea anumitor caracteristici ale procedurilor stocate iv

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

4.2 4.3

4.4

4.5

4.6

4.1.10 Stergerea procedurilor stocate . . . . . . . . . . . . . . 4.1.11 Securitatea procedurilor stocate . . . . . . . . . . . . . 4.1.12 Avantaje ale procedurilor stocate . . . . . . . . . . . . Functii stocate . . . . . . . . . . . . . . . . . . . . . . . . . . Triggere . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.3.1 Sintaxa instructiunii CREATE TRIGGER . . . . . . . 4.3.2 Stergerea triggerelor . . . . . . . . . . . . . . . . . . . Event-uri . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.4.1 Crearea unui eveniment . . . . . . . . . . . . . . . . . 4.4.2 Proprieti ale evenimentelor . . . . . . . . . . . . . . . at Utilizatori i securitate . . . . . . . . . . . . . . . . . . . . . . s 4.5.1 Adugarea i tergerea utilizatorilor . . . . . . . . . . . a s s 4.5.2 Schimbarea numelor utilizatorilor i a parolelor . . . . s 4.5.3 Acordarea de privilegii la nivel de coloane i tabele . . s 4.5.4 Acordarea de privilegii la nivelul bazei de date . . . . . 4.5.5 Acordarea de privilegii la nivel de utilizator . . . . . . 4.5.6 Dreptul de a da drepturi: optiunea WITH GRANT . . 4.5.7 Restrictionarea privilegiilor . . . . . . . . . . . . . . . 4.5.8 Revocarea privilegiilor . . . . . . . . . . . . . . . . . . Tranzactii i lucrul intr-un mediu multiuser . . . . . . . . . . . s 4.6.1 Conceptul de tranzactie . . . . . . . . . . . . . . . . . 4.6.2 Pornirea unei tranzactii . . . . . . . . . . . . . . . . . 4.6.3 Lucrul cu savepoints . . . . . . . . . . . . . . . . . . . 4.6.4 Probleme care pot aprea datorit accesului concurent a a 4.6.5 Mecanismul de locking . . . . . . . . . . . . . . . . . . 4.6.6 Nivelul de izolare . . . . . . . . . . . . . . . . . . . . . 4.6.7 Momentul procesrii interogrilor . . . . . . . . . . . . a a

. . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . .

85 85 85 86 88 89 91 91 91 95 96 96 97 98 99 100 100 101 101 102 102 103 103 104 105 106 107

II

Oracle

109

5 Prezentare general a 111 5.1 Generaliti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111 at 5.2 Arhitectura Oracle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112 5.3 Instalare Oracle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113 6 Interogarea i actualizarea datelor s 6.1 Generaliti . . . . . . . . . . . . . . . . . . at 6.1.1 Tipuri de date Oracle . . . . . . . n 6.1.2 Functii predenite Oracle . . . . . n 6.1.3 Functii numerice . . . . . . . . . . . 6.1.4 Functii pentru lucrul cu date i timp s 6.2 Interogarea SELECT . . . . . . . . . . . . . v 115 115 115 117 118 118 119

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

6.2.1 6.2.2

Crearea bazei de date exemplu . . . . . . . . . . . . . . . . . . . . . . 119 Exemple de interogri . . . . . . . . . . . . . . . . . . . . . . . . . . 124 a 131 131 133 134 135 136 139 139 140 141 142 143 144 146 148

7 Crearea obiectelor bazei de date 7.1 Lucrul cu tabele . . . . . . . . . 7.2 Lucrul cu secvente . . . . . . . 7.3 Lucrul cu indeci . . . . . . . . s 7.4 Lucrul cu view-uri . . . . . . . 7.5 Utilizatori i securitate . . . . . s

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

8 Crearea obiectelor procedurale 8.1 Programarea PL/SQL . . . . . . . . . . . . 8.1.1 Structuri conditionale i repetitive . . s 8.1.2 Cursoare . . . . . . . . . . . . . . . . 8.2 Proceduri stocate . . . . . . . . . . . . . . . 8.3 Lucrul cu functii . . . . . . . . . . . . . . . 8.4 Lucrul cu pachete . . . . . . . . . . . . . . . 8.5 Lucrul cu triggere . . . . . . . . . . . . . . . 8.6 Tranzactii i lucrul s ntr-un mediu multiuser .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

vi

Prefat a
Sistemele de gestiune a bazelor de date relationale joac un rol foarte important in ziua a de astzi numeroase domenii precum: afaceri, cercetare, sisteme educationale, cutri pe a n a a Internet etc. Initial, alegerea unui sistem de gestiune a bazelor de date era foarte complicat deoarece a ea presupunea un pret foarte mare pentru aplicatia propriu-zis ct i necesitatea existentei a a s unei infrastructuri foarte complexe. Mai nou, se poate spune c sistemele de gestiune a a bazelor de date au ajuns s poat folosite pe orice calculator. Bineinteles, exist i exceptii a a as cum ar cazul unor sisteme de gestiune a bazelor de date foarte complexe, precum Oracle. n Dup cum se tie, lumea sistemelor de gestiune a bazelor de date este o lume foarte a s dinamic, care exist numeroi juctori pe piata. Cei mai mari sunt Oracle, IBM (DB2), a n a s a Microsoft (Sql Server), MySQL, Postgresql, SQLite, etc... cele ce urmeaz vom prezenta dou solutii, una care provine din lumea open-source, In a a cum este cazul MySQL, precum i una care vine din lumea enterprise, cazul Oracle. s Voi prezenta, pe ct posibil, att lucruri care sunt utile cu precdere pentru dezvoltatori a a a (limbajul SQL cu extensiile sale corespunztoare ecrui SGBD) ct i lucruri care in de a a a s t administrarea serverului de baze de date.

Partea I MySQL

Capitolul 1 Prezentare general a


Unul din cele mai raspndite sisteme de gestiune a bazelor de date este MySQL. Deza voltarea lui a nceput in 1979 cnd compania TcX (prin Michael Monty Widenius) a a nceput dezvoltarea unui instrument de lucru cu baze de date numit UNIREG. 1994, In compania a nceput munca pentru un SGBD care s foloseasc SQL pentru a realiza comua a nicarea cu aplicatii Web. Ei au avut nevoie de un nou SGBD deoarece cele existente deja (cum ar mSQL) prezentau prea putine faciliti. at 1996 a fost lansat MySQL prin versiunea 3.11.11, versiune disponibil numai pentru In a Linux i Solaris. s Intre timp, a aprut compania MySQL AB care s-a ocupat de dezvoltarea a acestui produs. 2008, aceasta a fost In nghitit de Sun Microsystems, care a ntre timp a fost cumprat de Oracle. a a Initial, MySQL era un SGBD cruia lipseau numeroase faciliti precum suportul pentru a i at tranzactii sau procedurile stocate, dar ultima vreme, toate acestea i multe altele au fost n s incluse distributiile MySQL, astfel at acesta a devenit un SGBD foarte complex, and n nc ntr categoria enterprise. n Un alt mare avantaj pe care-l prezint acest SGBD este faptul c el ruleaz sub numeroase a a a platforme precum Window, Linux, Solaris i multe altele. s

1.1

De ce MySQL?

momentul care dorim s alegem un SGBD care s ne coste ct mai putin i s nu In n a a a s a necesite foarte multe resurse, avem mai multe posibile optiuni: MySQL, PostreSQL, SQLite i multe altele. s MySQL prezint mai multe avantaje: a 1. MySQL este unul din cele mai rapide SGBD-uri de pe piat. a 2. Prezint performante foarte bune dar este mult mai uor de administrat i folosit dect a s s a alte SGBD-uri. 5

3. MySQL folosete SQL (Structured Query Language), care este cel mai folosit standard s piat. n a 4. Are numeroase capabiliti: este multi-threading (ceea ce at nseamn c mai multi clienti a a se pot conecta simultan), poate folosit mai multe moduri (prin aplicatii client n consol, aplicatii client grace, aplicatii client web, prin diverse interfete de programare a de ctre limbaje precum C, C++, Java, PHP etc.). a 5. Poate folosit retea i chiar accesat de pe Internet. Prezint posibilitatea de a lucra n s a cu el folosind SSL (Secure Sockets Layer). 6. Este foarte portabil. 7. Are o dimensiune foarte mic. a 8. Este un program open-source, care cele mai multe cazuri poate folosit free. n 9. Este folosit pe scar larg, ceea ce face ca documentatia s e foarte uor de obtinut. a a a s

1.2

Versiunea folosit a

De-a lungul timpului MySQL a cunoscut o dezvoltare continu. Au existat numeroase a versiuni, ecare aducnd a mbuntiri mai mult sau mai putin consistente. a at cele ce urmeaz vom prezenta functionaliti prezente versiunile de la 5.0. VersiIn a at n unea 5.0 a introdus proceduri i functii stocate, view-uri, trigger-e, strict input handling, s VARCHAR adevrat i INFORMATION SCHEMA. a s Versiunea 5.1 a introdus event scheduler-ul precum i suport pentru XML. s

1.3

Arhitectura MySQL

MySQL ruleaz a ntr-un mediu bazat pe retea i are o arhitectur de tip client/ server. Cu s a alte cuvinte, exist un program principal care ruleaz (serverul) i mai multe alte programe a a s care se conecteaz la el, fac cereri i primesc rspunsuri numite programe client. a s a Atunci cnd instalm MySQL, de fapt instalm urmtoarele componente: a a a a Serverul MySQL sau mysqld este aplicatia care rspunde la cereri i care face manage a s mentul accesului la disk sau la memorie. Serverul este multi-threaded, ceea ce nseamn a c suport mai multi clienti simultan. Pentru managementul bazelor de date, el poate a a folosi mai multe mecanisme (putem avea baze de date care s suporte tranzactii i baze a s de date care nu suport tranzactiile). a mysqld prezint mai multe variante, care ecare dintre ele aduc ceva nou fat de a a varianta simpl. mysqld-nt, de exemplu, ofer suport pentru lucrul cu named pipes, a a n timp ce mysqld-max ofer mai multe posibiliti pentru stocarea bazelor de date. a at 6

Aplicatiile client sunt nite aplicatii pe care cei care au creat MySQL le-au gndit s a pentru ca noi s putem accesa i prelucra datele din bazele de date. Practic, noi a s folosim aceste programe care la rndul lor se conecteaz la server pentru ecare din a a operatiile pe care noi le facem. Avem mai multe tipuri de astfel de aplicatii: MySQL Query Browseri MySQL Admistrator sunt nite aplicatii grace care ne s s permit s manipulm serverul. a a mysql este o aplicatie linie de comand care ne permite s transmitem interogri n a a a serverului i s vedem rezultatele acestora. s a Exist de asemenea i alte programe client precum: mysqlimport pentru ima s portarea datelor, mysqldump pentru backup-uri, mysqladmin pentru managementul serverului i mysqlcheck pentru vericarea integritii bazelor de date. s at De asemenea, exist i programe care sunt independente de server i care fac ecare as s anumite lucruri: myisamchk veric tabele i face corectii dac e cazul, myisampack a s a care creeaz arhive read-only ale unor tabele MyISAM. Toate aceste utilitare nu se a conecteaz niciodat la server, ele lucrnd independent de acesta. a a a Dup cum se poate uor bnui nu este necesar ca aplicatia client i aplicatia server s se a s a s a ae pe acelai calculator pentru a putea comunica. Mai mult, se poate ca ele s se ae pe s a sisteme de operare diferite i acest lucru este continuare posibil. s n

1.3.1

Instalare program i rulare server s

cele ce urmeaz voi prezenta paii necesari pentru instalarea MySQL pe un calculator In a s care are sistemul de operare Windows. ai se downloadeaz MySQL (versiunea 5.1) de la adresa de internet: Int a http://dev.mysql.com/downloads/mysql/5.1.html#downloads. Avem mai multe modaliti de a instala programul. Pentru at nceput vom alege Without installer care presupune doar dezarhivarea programului direct pe c:. Dup ce se termin a a download-ul, dezarhivm ierul direct pe c:. a s directorul corespunztor vom vedea existenta mai multor alte directoare, printre care In a acest director se gsesc aplicatiile corespunztoare serverului, clientilor i directorul bin. In s a a dar i altor utilitare. s Primul pas pe care dorim s-l facem este pornirea serverului. Acest lucru se poate face a prin rularea programului mysqld. Pentru a putea siguri ca totul este regul i serverul n as ruleaz, trebuie s dm Ctrl+Alt+Del i s cutm aplicatia mysqld.exe. Dac aceasta a a a s a a a a ruleaz, atunci serverul este pornit. a Initial avem creat un user root care nu are parol. Putem folosi acest lucru pentru a ne a conecta la serverul de baze de date. Putem folosi aplicatia client mysql.exe felul urmtor: n a mysql -u root Vom putea observa faptul c a ncepnd din acest moment avem un prompt care ne permite a introducerea comenzilor. Prezentm continuare cteva comenzi: a n a 7

show databases; use mysql show tables; select host, user, password from user; quit Prima comand permite aarea tuturor bazelor de date. A doua selecteaz o baz de a s a a date (mysql) ca baz activ, pentru ca din acest moment, comenzile s se refere la aceast a a a a baz de date. A treia comand permite aarea tabelelor din baza de date curent. Ultima a a s a comand aeaz informatiile despre utilizatorii a s a nregistrati. Se poate observa c pentru a utilizatorul root nu avem nici o parol. Ultima comand are ca efect ieirea din promptul a a s mysql. Un lucru important care trebuie fcut atunci cnd se instaleaz MySQL este schimbarea a a a parolei utilizatorului root. Acest lucru se poate face prin comanda, introdus promptul a n MySQL: set password for root@localhost=password(parola); Urmtorul pas ar putea downloadul aplicatiilor client care au interfete grace. Acest a lucru se poate face de la adresa http://dev.mysql.com/downloads/gui-tools/5.0.html, dup care se poate dezarhiva ierul obtinut. Acesta contine aplicatiile MySQL Query a s Browser i MySQL Administrator. s Aceste aplicatii pot pornite, dar pentru ca ele s poat rula, trebuie introduse anumite a a informatii precum calculatorul gazd (host - unde putem introduce localhost dac serverul a a se a pe acelai calculator), precum i numele utilizatorului numele cruia ne conectm. a s s n a a Dei nu are legtur mod direct cu subiectul prezentat, trebuie mentionat c exist o s a a n a a documentatie foarte cuprinztoare referitoare la modul de utilizare a MySQL-ului pe situl a dedicat de la urmtoarea adres: a a http://dev.mysql.com/doc/

1.3.2

Invocarea programelor client

Programele client, dup cum am mai spus pot de dou feluri: a a Programe client invocate din linie de comand (mysql ) a Programe client de tip GUI (MySQL Query Browser i MySQLAdministrator ) s Cnd se invoc un program client, general trebuie specicate optiuni care controleaz a a n a comportamentul lui. Acestea pot date e live e iere de optiuni. Unele optiuni n s specic cum se face conectarea, timp ce altele care este operatia propriu-zis care se a n a dorete a executat. s a Pentru clientii GUI aceste optiuni pot specicate i cadrul interfetei grace. s n Voi prezenta continuare cu precdere modul de lucru cu aplicatia client mysql. n a Pentru a putea vedea optiunile disponibile, putem introduce: 8

mysql --help Pentru a putea vedea versiunea serverului pe care lucrm: a mysql --version Pentru a ne putea conecta la un calculator aat la o anumit adres putem scrie instructiuni a a de forma urmtoare. Toate cele 3 instructiuni sunt echivalente: a mysql --host=myhost.example.com mysql -h myhost.example.com mysql -hmyhost.example.com Cel mai des ne conectm la un server MySQL folosind o instructiune de forma: a mysql -h host name -P port number -u user name -p Aceast comand are ca efect conectarea la serverul aat pe calculatorul host name, a a n s a server care ruleaz pe portul port number, numele utilizatorului user name i dorim s a m ntrebati referitor la parol. Oricare dintre aceste optiuni poate lipsi. a De exemplu, dac nu specicm -P se consider c lucrm pe portul implicit 3306. a a a a a Pentru a nu introduce optiunile de conectare de ecare dat, cazul care se lucreaz a n n a mereu cu acelai server, se pot crea iere de optiuni care s e refolosite cazul mai multor s s a n conectri succesive. a Optiunile din ierele de optiuni sunt organizate pe grupuri precum [mysql], [mysqldump] s sau [client]. grupul [mysql] avem optiuni referitoare la aplicatia client mysql, timp In n ce grupul [client] avem optiuni comune tuturor aplicatiilor client. n Un astfel de ier ar putea arta astfel: s a [client] host = myhost.example.com compress [mysql] safe-updates Pe Windows, sunt cutate ordine ierele my.ini i my.cnf ai directorul Windows a n s s nt n i apoi pe c:. s Uneori, momentul care dorim s rulm o aplicatie client, este bine s specicm n n a a a i a i baza de date pe care dorim s lucreze ca exemplul urmtor: s a n a mysqldump -u mihai -p database name > file.sql Aceast comand are ca efect crearea unui ier le.sql care va cuprinde toate interogrile a a s a SQL necesare recreerii acestei baze de date, dac acest lucru s-ar dori. a Un astfel de ier ar putea rerulat pe un alt calculator, pentru recreerea bazei de date, s e folosind aplicatia client mysql : 9

mysqldump database name < file.sql e direct din promptul mysql: source file.sql; Nu vom prezenta cele ce urmeaz lucrul cu aplicatii client grace deoarece optiunile n a care trebuie specicate cazul lor sunt aceleai, doar c ele se specic ferestre de dialog n s a a n dedicate.

10

Capitolul 2 Interogarea i actualizarea datelor s


2.1
2.1.1

Generaliti at
Literali MySQL n

multe din interogrile pe care le vom scrie de-a lungul timpului vom folosi literali. In a Acetia sunt de mai multe tipuri: numeric, alfanumeric, temporal, boolean i hexazecimal. s s Fiecare literal are un tip de date, dar nu neaprat pentru ecare tip de date exist literali. a a Prezentm nite exemple de interogri care am scris a s a n ngroat literalii care apar: s insert into products values( 1, televizor LCD); select from products where productId = 1; Nu vom prezenta toate tipurile de literali posibili ci doar pe cele care prezint atribute a mai deosebite. Literalii alfanumerici poti precizati folosind ghilimele duble () sau simple () la nceputul i sfritul literalului. Exist i caractere speciale care sunt prezentate tabelul s as as n urmtor: a Caracterul special Ce produce \0 Caracterul ASCII 0 \ Caracterul ghilimea simpl a \ Caracterul ghilimea dubl a \b Caracterul backspace \n Caracterul linie nou a \r Caracterul carriage return \t Caracterul tab \z Caracterul cu cod ASCII 26 (Ctrl+Z) Literalii de tip dat sunt cuprini a s ntre ghilimele i au trei componente: an, luna i zi. s s Ca separatori se pot folosi caracterele -, /, @ i %. s Date corecte sunt: 1980-12-13 (13 dec 1980), 1980/12/13, 1980@12@13. Se poate i s introducem date prin folosirea de numere s a ntregi ca exemplele urmtoare: n a 19801208 (8 dec 1980), 991111(11 nov 1999). 11

Literalii pentru date trebuie s e cuprini a s ntre 1 ianuarie 1000 i 31 decembrie 9999. s Pentru ca s putem siguri c operatiile cu date vor functiona corect, trebuie ca datele a a introduse s e corecte. a Literalul de timp specic un moment de timp din cadrul unei zile. Se specic tot a a ntre ghilimele, ca exemplele urmtoare: 23:38:45, 14:00, 14 (reprezint ora 0:00:14), n a a 10:00:34.000023. Se poate ca s se foloseasc acest literal i pentru a retine durate de timp. O expresie a a s precum 8 10:00:00 reprezint 8 zile i 10 ore. a s Literalii datetime i timestamp sunt combinatii intre literalii pentru dat i literalii pentru s as timp. Un literal de acest tip arat felul urmtor: 1998-10-23 10:34:21.002345. a n a Dei cei doi literali sunt aproape identici, exist i diferente care in de intervalele pe care s as t le pot retine. O variabil de tip timestamp poate retine date cu anii a ntre 1970 i 2037, pe s cnd o variabil de tip datetime poate retine date cuprinse a a ntre anii 1000 i 9999. s O alt diferenta ar faptul c literalii de tip timestamp retin datele format UTC a a n (Universal Coordinated Time). Literalul boolean este cel mai simplu literal deoarece poate avea doar dou valori: true a i false. s Literalul hexazecimal este folosit pentru a retine numere baza 16. El poate avea o n variant alfanumeric (x41, X41) sau o variant numeric (0x23, 0xAF). a a a a Literalul de tip bit este un literal alfanumeric care are fata caracterul b sau B, n urmat numai de valori de 0 i 1, ca exemplele urmtoare: b1001 (valoarea 9) sau B101 s n a (valoarea 5).

2.1.2

Expresii

Expresiile sunt combinatii de literali, nume de coloane, calcule complexe, operatori i s functii care sunt evaluate ntr-o anumit ordine i duc la un anumit rezultat. a s urmtoarea interogare avem 2 expresii: In a select nume, venit* 120/100 from salarii where salariu < @salariu_mediu Fiecare expresie are urma evalurii un anumit tip de date. n a Expresiile pot de mai multe tipuri: expresii scalare care au ca rezultat un numr sau o dat. a a expresii care au ca rezultat o nregistrare (row expressions). O astfel de expresie arat a astfel: (1, "John", "Romania") expresii care au ca rezultat o tabel (table expressions). Un exemplu de astfel de a expresie este: 12

((1, "Adi", "Romania"), (2, "Maria", "France"))

2.1.3

Asignarea de nume la coloane

MySQL, la fel ca i majoritatea SGBD-urilor putem da un nume nou unei coloane In s n felul urmtor: n a select nume, prenume, venituri - datorii as profit from persoane Dac n-am specicat un nume pentru coloana a 3-a, automat MySQL i-ar dat numele a venituri-datorii. Se poate specica un nou nume de coloan i pentru coloanele care n-au as expresii compuse.

2.1.4

Variabile utilizator i instructiunea SET s

Variabilele denite de utilizator pot initializate folosind expresii scalare. Inainte de a folosi o variabil aceasta treubuie denit i initializat. Dac ea nu este a as a a initializat, automat are valoarea NULL. a Pentru a deni i initializa o variabil putem folosi instructiunea SET: s a SET @player = 2; Nu trebuie specicat tipul variabilei deoarece acesta este dat de expresia cu care este initializat. Aceste variabile utilizator pot folosite ulterior interogri: n a select user, userid from users where user_id < @player; Pentru a putea vizualiza valoarea unei astfel de variabile utilizator putem folosi instructiunea SELECT: SELECT @player;

2.1.5

Variabilele sistem

Variabilele sistem, la fel ca i cele utilizator au un tip de date i o valoare. Diferenta s s const faptul c MySQL introduce i initializeaz aceste variabile. a n a s a Ele se mpart dou mari categorii: n a variabile sistem globale - Sunt initializate de ecare dat cnd este pornit MySQL i a a s sunt vazute toate sesiunile. Unele pot modicate prin folosirea instructiunii SET, n timp ce altele precum VERSION sunt read-only. n Prezentm un exemplu: a 13

select @@global.version; variabile sistem de sesiune - Sunt variabile care au, general un corespondent variabil n a global, dar pe care dac le modicm noile valori se potrivesc numai sesiunii curente. a a a Iat i nite exemple: as s select @@session.sql warnings; set @@session.sql warnings=true; set @@session.sql select limit=20; select @@session.sql select limit; Putem vedea faptul c valoarea variabilei globale nu s-a schimbat i c este o valoare a s a foarte mare prin instructiunea: select @@global.sql select limit; Dac nu se specic nici un modicator, se sub elege utilizarea lui SESSION (poate a a nt nlocuit cu LOCAL). Variabilele globale de sistem pot initializate ierele de congurare precum "my.ini". n s De asemenea, se pot seta momentul care se pornete serverul MySQL, ca exemplul n n s n urmtor: a mysqld --SQL SELECT LIMIT=1000 Putem vedea o list a tuturor variabilelor sistem (toate, globale i de sesiune) folosind a s una din urmtoarele comenzi: a show variables; show global variables; show session variables; Din dorinta ca MySQL s respecte standarde la care mai multe produse au aderat, a exist anumite variabile de sistem, pentru care nu mai trebuie folosite caracterele @@ a (astfel de exemple sunt: CURRENT USER, CURRENT DATE, CURRENT TIME, CURRENT TIMESTAMP). select current user; select * from persoane where last used date = current date; 14

2.1.6

Expresia CASE

Expresia CASE se folosete cu un sens asemntor celui pe care-l cunoatem cazul s a a s n instructiunii SWITCH din Java sau C++. Iat un exemplu: a select nume, case sex when f then Femeie else Barbat end as sex, oras from persoane; Aceast interogare ar putea scris i astfel: a as select nume, case sex when f then Femeie when m then Barbat end as sex, oras from persoane; Dac nu se potrivete nici o expresie, atunci se va returna valoarea NULL. a s Putem construi i interogri mult mai complicate, prin folosirea de CASE-uri imbricate: s a select idpersoana, nume, case sex when m then case when year(data nasterii)>2000 then Baietel else Barbat end when f then case when year(data nasterii)>2000 then Fetita else Femeie end end as Gen from persoane; Evident, clauzele when putem pune i conditii, nu numai stringuri sau valori xe. Cnd n s a o expresie este evaluat ca ind corect, celelalte nu mai sunt evaluate. a a Aceste expresii CASE pot folosite oriunde sunt permise expresii scalare, adic i a s n clauzele HAVING sau WHERE.

2.1.7

Functii scalare

Functiile scalare sunt folosite pentru a efectua calcule i transformri. s a O astfel de functie primete mai multi parametri scalari i are o valoare scalar. Avem s s a numeroase functii scalare pentru lucrul cu numere, iruri de caractere, date, etc. s Pentru a consulta o lista complet a acestora este recomandat utilizarea documentatiei a a MySQL care se gsete la adresa: a s 15

http://dev.mysql.com/doc/refman/5.1/en/tutorial.html Iat i cteva exemple de utilizare a functiilor scalare: as a select pow(3,5); select nume, year(data_nasterii) from persoane; select ucase(test); select replace(maria,a,e);

2.1.8

Castingul expresiilor

De multe ori, momentul care folosim un literal tipul de dat al acestuia este evident. n n a Sunt totui situatii cnd MySQL trebuie s fac casturi sau cnd dorim s facem propriile s a a a a a noastre cast-uri. Putem preciza un cast prin expresii de genul urmtor: a cast(123 as signed integer) cast(122035 as time) cast(123 as char) Tipurile de date acceptate ntr-o operat de cast sunt: binary(lungime), char(lungime), e date, datetime, decimal(precizie, scal), [signed] integer, time, unsigned [integer]. a

2.1.9

Expresii scalare compuse

Evident, i MySQL se pot forma expresii compuse. s n principiu, MySQL sunt valabili operatorii pentru numere pe care-i cunoatem din In n s Java sau C++, la care se adaug operatorul DIV. a De asemenea, MySQL suport exact aceeai operatori pe biti. a s Lucruri mai interesante i foarte folositoare alnim atunci cnd vorbim despre lucrul cu s nt a date. Se poate s scriem interogri de genul: a a SELECT * FROM persoane WHERE data nasterii > CURRENT DATE - INTERVAL 20 YEAR; Aceast interogare are ca efect returnarea tuturor datelor referitoare la persoane care a s-au nscut ultimii 20 ani. a n Exist astfel de notatii pentru: DAY, WEEK, MONTH, QUARTER, YEAR, YEAR MONTH. a Intervalul poate sczut sau adunat. a Un lucru asemntor se poate face atunci cnd este vorba de timp: a a a select nume, ora_incepere, ADDTIME(ora_incepere,3:30:00) from evenimente 16

2.2

Interogarea SELECT

Una din cele mai complicate interogri MySQL este interogarea SELECT. Ea este a n n acelai timp, probabil, i cea mai folosit interogare. s s a Complexitatea ei poate uor observat din forma general care poate regasit s a a a n documentatia MySQL i care este prezentat continuare. s a n SELECT [ALL | DISTINCT | DISTINCTROW ] [HIGH PRIORITY] [STRAIGHT JOIN] [SQL SMALL RESULT] [SQL BIG RESULT] [SQL BUFFER RESULT] [SQL CACHE | SQL NO CACHE] [SQL CALC FOUND ROWS] select expr [, select expr ...] [FROM table references [WHERE where condition] [GROUP BY col name | expr | position [ASC | DESC], ... [WITH ROLLUP]] [HAVING where condition] [ORDER BY col name | expr | position [ASC | DESC], ...] [LIMIT [offset,] row count | row count OFFSET offset] [PROCEDURE procedure name(argument list)] [INTO OUTFILE file name [CHARACTER SET charset name] export options | INTO DUMPFILE file name | INTO var name [, var name]] [FOR UPDATE | LOCK IN SHARE MODE]] cele ce urmeaz nu vom intra chiar cele mai mici amnunte privitor la aceast In a n a a sintax, dar vom a ncerca s elegem modul de functionare al acestei interogri. a nt a Trebuie fcute cteva precizri: a a a O interogare SELECT trebuie s contin mcar clauza SELECT. a a a Dac se folosesc WHERE, GROUP BY sau HAVING atunci este obligatorie i clauza a s FROM. Ordinea clauzelor este x, ceea ce a nseamn ca mereu dup SELECT, vom avea a a FROM, WHERE, GROUP BY, HAVING i ORDER BY. s S presupunem c avem urmtoarea interogare: a a a 17

SELECT PLAYERNO FROM PENALTIES WHERE AMOUNT > 25 GROUP BY PLAYERNO HAVING COUNT(*) > 1 ORDER BY PLAYERNO Pentru o astfel de interogare, procesarea ecrei clauze const a a ntr-o tabel intermediar a a care const din 0 sau mai multe a nregistrri, ecare avnd cel putin una sau mai multe a a coloane. Se parcurg urmtorii pai: a s Clauza FROM are ca date de intrare informatii din unul sau mai multe tabele, cre nduse un tabel temporar cu aceste informatii. Clauza WHERE terge din acest tabel temporar acele s nregistrri care nu a ndeplinesc conditiile. Clauza GROUP BY are ca efect gruparea nregistrrilor tabela temporar functie a n a n de cmpul specicat. a Clauza HAVING se aplic asupra tabelei intermediare create dup grupare. Astfel, a a n acest exemplu se pstreaz acele numere de juctori pentru care exist mai mult de o a a a a nregistrare. Clauza ORDER BY nu are efect asupra datelor care vor obtinute, ci doar le sorteaz a dup cum este specicat. a

2.2.1

Baza de date exemplu

Problema pentru care trebuie s crem o baz de date sun felul urmtor: a a a a n a Dorim s creem o baz de date care s permit retinerea notelor studentilor unei faculti. a a a a at Pentru un student se cunosc nrmatricol, numele, prenumele, sexul, data naterii, codul s numeric personal, oraul, judetul i ara din care provine. s s t De asemenea, avem mai multe tipuri de cursuri.Ele pot obligatorii, optionale sau fac ultative. Pentru ecare curs se cunosc: codul cursului, denumirea cursului, tipul cursului, numrul a de credite aferent cursului precum i codul profesorului care ine acel curs. s t Studentii, pe baza preferintelor lor se pot nscrie la mai multe cursuri. Pentru ecare astfel de nscriere trebuie s putem retine data la care studentul s-a a nscris. Studentii primesc note la materiile la care s-au nscris. Notele sunt cuprinse ntre 1 i 10, s nota de promovare ind 5. Studentii pot da un examen din nou dac doresc s-i mreasc a as a a nota obtinut. Nota care se ia considerare pentru ecare student este ultima not pe care a n a a obtinut-o. cele ce urmeaz vom lucra pe urmtoarea baz de date, care permite retinerea notelor In a a a studentilor: 18

studenti (nrmatricol, nume, prenume, sex, CNP, datan, oras, judet, tara) profesori (cod prof, nume, prenume, grad, sex, datan) tipuri_curs (tip_curs, den_tip) cursuri (cod_curs, den_curs, tip_curs , credite, cod_profesor ) inrolari (cod_inrolare, nrmatricol , cod_curs , data_inrolare) note (cod_nota, cod_inrolare , nota, data) Codul care poate crea i popula aceast baz de date este urmtorul: s a a a drop database if exists mydatabase; create database mydatabase; use mydatabase; create table tipuri_curs( tip_curs bigint primary key auto_increment, den_tip varchar(30) not null ); insert into tipuri_curs(den_tip) values ("obligatoriu"), ("optional"), ("facultativ");

create table profesori( cod_prof bigint primary key auto_increment, nume varchar(30) not null, prenume varchar(30) not null, grad varchar(30) not null, sex char(1) not null, datan date ); insert (null, (null, (null, (null, (null, (null, into profesori values "Iolu","Mihai","lector","m",1979-05-03), "Bocu","Dorin","profesor","m",1955-08-03), "Ciurea","Eleonor","profesor","m",1943-07-13), "Sasu","Lucian","lector","m",1977-08-02), "Deaconu","Adrian","conferentiar","m",1974-03-13), "Ciupala", "Laura", "conferentiar", "f", 1976-02-20);

create table studenti( nrmatricol bigint primary key not null, nume varchar(30) not null, 19

prenume varchar(30) not null, CNP varchar(13) not null, sex char(1)not null, datan date not null, oras varchar(30) not null, judet varchar(30) not null, tara varchar(30) not null ); insert into studenti values (101, "Florescu","Radu","1870409030182","m",1987-04-09, "Bucuresti","Bucuresti","Romania"), (102, "Ceausescu","Ionut","1880323020382","m",1988-03-23, "Brasov","Brasov","Romania"), (103, "Ciumarnean","Oana","2880520435434","f",1988-05-20, "Brasov","Brasov","Romania"), (104, "Neagu","Andrei","1871115456537","m",1987-11-15, "Sinaia","Prahova","Romania"), (105, "Saracu","Ana-Maria","1880308345322","f",1988-03-08, "Fagaras","Brasov","Romania"), (106, "Ionita","Emanuel-Ionut","1881023345433","m",1988-10-23, "Victoria","Brasov","Romania"), (107, "Dumitrescu","Teodora","2881220030325","f",1988-12-20, "Cluj-Napoca","Cluj","Romania"), (108, "Radoi","Ovidiu","1871005325323","m",1987-10-05, "Munchen","Bavaria","Germania"), (109, "Tanase","Alexandra","2880301345436","f",1988-03-01, "Brasov","Brasov","Romania"), (110, "Mocanu","Laura","2880402342344","f",1987-04-02, "Brasov","Brasov","Romania"); create table cursuri( cod_curs bigint primary key auto_increment, den_curs varchar(30) not null, tip_curs bigint not null, credite int(2), cod_profesor bigint not null); insert (null, (null, (null, into cursuri values "Design patterns",2, 6, 1), "SGBD (MySQL, Oracle)",1, 5, 1), "Inginerie software",1, 6, 2),

20

(null, (null, (null, (null, (null, (null, (null,

"POO 2",1, 6, 2), "Algoritmica",1, 6, 3), "Algoritmica grafurilor",1, 4, 3), "Programare C#",1, 5, 4), "Inteligenta artificiala",1, 4, 4), "Programare procedurala",1, 6, 5), "Optimizare combinatorie",1, 3, 6);

create table inrolari( cod_inrolare bigint primary key auto_increment, nrmatricol bigint not null, cod_curs bigint not null, data_inrolare date not null); insert (null, (null, (null, (null, (null, (null, (null, (null, (null, (null, (null, (null, (null, (null, (null, into 101, 101, 102, 102, 102, 103, 104, 105, 107, 107, 108, 108, 109, 110, 110, inrolari values 7, 2007-09-03), 1, 2007-09-09), 8, 2007-09-14), 2, 2007-09-03), 9, 2007-09-08), 3, 2007-09-14), 8, 2007-09-07), 2, 2007-09-09), 1, 2007-09-03), 3, 2007-09-12), 2, 2007-09-08), 9, 2007-09-08), 8, 2007-09-13), 7, 2007-09-14), 4, 2007-09-14);

create table note( cod_nota bigint primary key auto_increment, cod_inrolare bigint not null, nota int(2) not null, data date not null); insert (null, (null, (null, (null, into note values 1, 8, 2008-01-10), 1, 10, 2008-01-20), 2, 3, 2008-01-12), 3, 6, 2008-01-14),

21

(null, (null, (null, (null, (null, (null, (null, (null, (null, (null, (null,

4, 9, 2008-01-16), 6, 7, 2008-01-12), 7, 4, 2008-01-14), 7, 8, 2008-01-12), 8, 9, 2008-01-10), 10, 3, 2008-01-14), 10, 5, 2008-01-16), 12, 7, 2008-01-13), 13, 4, 2008-01-8), 14, 3, 2008-01-10), 14, 4, 2008-01-20);

2.2.2

Exemple de interogri a

S se rezolve urmtoarele interogri: a a a 1. S se aeze toate informatiile despre toti studentii: a s SELECT * FROM studenti; 2. S se aeze pentru toti studentii numele, prenumele i locul din care provin: a s s SELECT nume, prenume, CONCAT(oras,", ",judet,", ",tara) AS "Locul de provenienta" FROM studenti; 3. S se aeze numele, prenumele si orasul din care provin pentru studentii care sunt din a s oraul Brasov: s SELECT nume, prenume, oras FROM studenti WHERE oras="brasov"; 4. S se aeze numele, prenumele i data naterii pentru studentii care s-au nscut a s s s a nainte de 1988. SELECT nume, prenume, datan FROM studenti WHERE YEAR(datan) < 1988; SELECT nume, prenume, datan FROM studenti WHERE datan < 1988-01-01; 22

5. S se aeze numele i prenumele persoanelor care s-au nscut oraele Brasov sau a s s a n s s Bucureti: s SELECT nume, prenume, oras FROM studenti WHERE oras=brasov or oras=bucuresti; SELECT nume, prenume, oras FROM studenti WHERE oras IN (brasov,bucuresti); 6. S se aeze numele, prenumele, oraul i data naterii pentru acei studenti care s-au a s s s s nscut Braov anul 1988. a n s n SELECT nume, prenume, oras, datan FROM studenti WHERE oras=Brasov and year(datan)=1988; SELECT nume, prenume, oras, datan FROM studenti WHERE (oras,YEAR(datan)) = ("brasov", 1988); 7. S se aeze numele, prenumele i data naterii tuturor profesorilor pentru care data a s s s naterii este nul: s a SELECT nume, prenume, datan FROM profesori WHERE datan IS NULL; Pentru a se verica dac un cmp este sau nu NULL, nu se folosete operatorul = ci a a s IS NULL sau IS NOT NULL. 8. S se aeze numele i prenumele tuturor studentilor ordonati alfabetic dup nume i a s s a s prenume: SELECT nume, prenume FROM studenti ORDER BY nume, prenume; 9. S se aeze numele, prenumele i oraul pentru studenti, ordonate functie de ora a s s s n s cresctor i apoi functie de nume i prenume descresctor. a s n s a 23

SELECT nume, prenume, oras FROM studenti ORDER BY oras, nume DESC, prenume DESC; 10. S se sorteze cresctor profesorii dup data naterii: a a a s SELECT * FROM profesori ORDER BY datan; 11. S se sorteze cresctor profesorii dup data naterii, cei care nu au data cunoscut a a a s a ind aezati la sfrit: s as SELECT * FROM profesori ORDER BY IF(datan IS NULL, 1, 0), datan; 12. S aeze numele i prenumele primilor cinci studenti: a s s SELECT nume, prenume FROM studenti LIMIT 5; 13. S se aeze numele i prenumele a 2 studenti, de dup primii 3: a s s a SELECT nume, prenume FROM studenti LIMIT 3, 2; 14. Sa se aeze aleator numele a 3 studenti: s SELECT nume, prenume FROM studenti ORDER BY RAND() LIMIT 3; 15. S se aeze pentru ecare student, numele i prenumele concatenat precum i oraul a s s s s i tara concatenate, ordonate dup nume i prenume: s a s SELECT CONCAT(nume, ,prenume) AS Numele, CONCAT(oras,,tara) AS Origine FROM studenti ORDER BY nume, prenume; 24

16. S se aeze numele i prenumele studentilor care-i vor mai srbatori ziua de natere a s s s a s luna aceasta: SELECT nume, prenume, datan FROM studenti WHERE MONTH(datan)=MONTH(CURDATE()) AND (DAY(datan)= DAY(CURDATE()); 17. S se aeze pentru ecare student numele, prenumele, data naterii precum i varsta a s s s lui, ordonate descresctor functie de vrsta: a n a SELECT nume, prenume, datan, TIMESTAMPDIFF(YEAR, datan, CURDATE()) AS Varsta FROM studenti ORDER BY Varsta DESC; 18. S se aeze numele i prenumele studentilor al cror nume a s s a ncepe cu litera C. SELECT nume, prenume FROM studenti WHERE nume LIKE C%; Dac vrem s considerm orice secvent de caractere atunci se folosete caracterul %, a a a a s altfel, pentru o singur liter se folosete caracterul . a a s 19. S se aeze toate oraele distincte din care avem studenti: a s s SELECT DISTINCT oras FROM studenti; 20. S se aeze numrul de a s a nregistrri din tabela studenti: a SELECT COUNT(*) FROM studenti; 21. Cti studenti din Braov avem? a s SELECT COUNT(*) FROM studenti WHERE oras=Brasov; 22. Pentru ci profesori se cunoate data naterii? at s s 25

SELECT COUNT(datan) FROM profesori; SELECT COUNT(*) FROM profesori WHERE datan IS NOT NULL: 23. S se aeze toate oraele distincte din care avem studenti: a s s SELECT (DISTINCT oras) FROM studenti ORDER BY oras; 24. S se aeze ci brbati i cte femei avem studenti? a s at a s a SELECT sex, COUNT(*) FROM studenti GROUP BY sex; SELECT CASE sex WHEN f THEN feminin WHEN m THEN masculin END AS Sex, COUNT(*) AS Numar FROM studenti GROUP BY Sex; 25. S se aeze pentru ecare lun ci studenti sunt nscuti acea lun: a s a at a n a SELECT MONTH(datan) AS Month, MONTHNAME(datan) AS Name, COUNT(*) AS Aparitii FROM studenti GROUP BY Month ORDER BY Month; 26. S se prezinte toate oraele care dau mai mult de un student, precum i numrul de a s s a studenti din oraele respective, oraele ind ordonate descresctor functie de numrul s s a n a de studenti: SELECT oras, COUNT(*) as "numar studenti" FROM studenti GROUP BY oras HAVING COUNT(*)>1 ORDER BY "numar studenti" DESC; 26

27. S se grupeze datele din tabela studenti functie de ora i luna care s-au nscut a n ss n a studentii: SELECT oras, MONTH(datan), COUNT(*) FROM studenti GROUP BY oras, MONTH(datan); 28. S se aeze ci bieti i cte fete avem, precum i numarul total de studenti: a s at a s a s SELECT sex, COUNT(*) AS Numar FROM studenti GROUP BY sex WITH ROLLUP; 29. S se aeze oraele ordinea descresctoare a mediilor vrstelor persoanelor care a s s n a a provin din acele orae: s SELECT oras, AVG(TIMESTAMPDIFF(YEAR,datan,CURDATE())) AS "Varsta medie" FROM studenti GROUP BY oras ORDER BY "Varsta medie" DESC; 30. S se aeze pentru ecare student numele, prenumele i a s s nrolrile pe care le-a fcut: a a SELECT studenti.nrmatricol, nume, prenume, cod_inrolare FROM studenti INNER JOIN inrolari ON studenti.nrmatricol=inrolari.nrmatricol ORDER BY student.nrmatricol; SELECT s.nrmatricol, nume, prenume, cod_inrolare FROM studenti s,inrolari i WHERE s.nrmatricol=i.nrmatricol ORDER BY student.nrmatricol; 31. S se aeze toti studentii i ce a s s nrolri s-au fcut pentru ei, inclusiv studentii care nu a a au fcut nici o a nrolare: SELECT student.nrmatricol, nume, prenume, cod_inrolare FROM studenti LEFT JOIN inrolari ON studenti.nrmatricol=inrolari.nrmatricol ORDER BY student.nrmatricol; 27

SELECT student.nrmatricol, nume, prenume, cod_inrolare FROM studenti LEFT JOIN inrolari USING(nrmatricol) ORDER BY student.nrmatricol; 32. S se aeze pentru ecare student, la cte cursuri s-a inscris. a s a SELECT nume, prenume, COUNT(*) FROM studenti s LEFT JOIN inrolari i USING (nrmatricol) GROUP BY s.nrmatricol; 33. S se aeze studentii care s-au a s nrolat la vreun curs: SELECT nrmatricol, nume, prenume FROM studenti WHERE nrmatricol IN (SELECT DISTINCT nrmatricol FROM inrolari) SELECT studenti.nrmatricol, nume, prenume FROM studenti INNER JOIN ( SELECT DISTINCT nrmatricol FROM inrolari) t ON studenti.nrmatricol=t.nrmatricol; 34. S se aeze cea mai vrst persoan (persoane) din toti studentii: a s n a a a SELECT nume, prenume FROM studenti WHERE datan= (SELECT MIN(datan) FROM studenti) SELECT nume, prenume, datan FROM studenti WHERE datan<= ALL( SELECT datan FROM studenti); 35. S se aeze toti studentii care sunt din acelai ora cu Oana Ciumrnean. a s s s a 28

SELECT nume, prenume, oras FROM studenti WHERE oras = (SELECT oras FROM studenti WHERE (nume, prenume)=(Ciumarnean,Oana)); 36. S se aeze studentii care au optat pentru anumite cursuri. a s SELECT nrmatricol, nume, prenume FROM studenti WHERE EXISTS (SELECT * FROM inrolari WHERE inrolari.nrmatricol=studenti.nrmatricol); 37. S se aeze pentru toate lunile care s-au nscut profesori sau studenti, ci profea s n a at sori/studenti s-au nscut. a SELECT luna, COUNT(*) FROM (SELECT DISTINCT month(datan) AS luna FROM studenti UNION ALL SELECT DISTINCT month(datan) AS luna FROM profesori) AS t GROUP BY luna ORDER BY luna; 38. S se aeze pentru ecare judet, oraele pe care le avem pentru el, separate prin a s s virgul: a SELECT judet, GROUP_CONCAT(DISTINCT oras) AS Orase FROM studenti GROUP BY judet; 39. S se aeze toate numele distincte de profesori i studenti: a s s SELECT prenume FROM profesori UNION SELECT prenume FROM studenti; Diferenta ntre UNION i UNION ALL este c, n cazul primei se elimin duplicatele s a a timp ce pentru a doua nu n 29

40. S se aeze pentru ecare numr matricol, ultimul curs la care s-a a s a nscris. SELECT i.nrmatricol, max_data, i.cod_curs FROM inrolari i JOIN (SELECT nrmatricol, MAX(data_inrolare) AS max_data FROM inrolari GROUP BY nrmatricol) AS t ON i.nrmatricol=t.nrmatricol AND i.data_inrolare=t.max_data 41. S se aeze pentru ecare student, ultimul curs la care s-a inscris. a s

SELECT nume, prenume, den_curs FROM (studenti s join inrolari i using (nrmatricol)) join cursuri c using (cod_curs) WHERE data_inrolare = (SELECT MAX(data_inrolare) FROM inrolari WHERE inrolari.nrmatricol=s.nrmatricol); sau SELECT s.nume, s.prenume, max_data, c.den_curs FROM studenti s JOIN ( SELECT ii.nrmatricol, max_data, ii.cod_curs FROM inrolari ii JOIN (SELECT nrmatricol, MAX(data_inrolare) AS max_data FROM inrolari GROUP BY nrmatricol) AS t ON ii.nrmatricol=t.nrmatricol and ii.data_inrolare=max_data ) tt USING(nrmatricol) JOIN cursuri c USING(cod_curs) 42. S se aeze pentru ecare curs, media notelor nale pe ecare an. a s

43. S se aeze mediile notelor acordate de profesorii brbati i profesorii femei. a s a s

2.3

Actualizarea datelor

Pentru actualizarea datelor vom folosi, principiu, una din urmtoarele interogri: INn a a SERT, REPLACE, UPDATE, DELETE i TRUNCATE. s 30

2.3.1

Interogarea INSERT

Pentru a introduce date ntr-o tabel se folosete instructiunea INSERT. Ea are mai a s multe forme: INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE] [INTO] tbl_name [(col_name,...)] VALUES (expr | DEFAULT,...),(...),... [ ON DUPLICATE KEY UPDATE col_name=expr, ... ] sau INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE] [INTO] tbl_name SET col_name=expr | DEFAULT, ... [ ON DUPLICATE KEY UPDATE col_name=expr, ... ] sau INSERT [LOW_PRIORITY | HIGH_PRIORITY] [IGNORE] [INTO] tbl_name [(col_name,...)] SELECT ... [ ON DUPLICATE KEY UPDATE col_name=expr, ... ] Cele 3 forme realizeaz urmtoarele lucruri: a a 1. Inserarea uneia sau mai multor nregistrri a ntr-o tabel, forma scurt. a n a 2. Inserarea uneia sau mai multor nregistrri a ntr-o tabel forma lung. a n a 3. Inserarea de nregistrri pe baza datelor din alte tabele. a De exemplu pentru a insera un nou curs tabela cursuri putem proceda conform n variantei 1 mai multe feluri: n INSERT INTO cursuri VALUES (NULL, "ADSOO",2,6,1); sau INSERT INTO cursuri(den_curs, tip_curs, credite, cod_profesor) VALUES ("ADSOO",2,6,1); Varianta a doua ar arta astfel: a INSERT INTO cursuri SET den_curs="ADSOO", tip_curs=2, credite=6, cod_profesor=1; 31

Se poate s inserm i date din alt tabel ca exemplul urmtor: a a s n a INSERT INTO studenti SELECT FROM studenti_straini anumite cazuri dorim s inserm date dintr-un ier local. Datele ar trebui s e In a a s a cuprinse ntr-un ier care are cte o s a nregistrare pe linie i care are s ntre valori caracterul TAB. Evident, cmpurile ar trebui s e prezente ordinea care sunt tabele. a a n n n Instructiunea care are ca efect citirea din ier arat astfel: s a LOAD DATA LOCAL INFILE cursuri.txt INTO TABLE cursuri;

2.3.2

Interogarea REPLACE

Interogarea REPLACE seamn foarte mult cu interogarea INSERT. Rolul ei este de a a a insera tabel o nou n a a nregistrare i, dac deja exist o alt s a a a nregistrare cu aceeai cheie s primar sau cu aceeai valoare pentru un cmp unic, atunci nti terge vechea a s a a s nregistrare dup care face inserarea. a Sintaxa acestei comenzi este aproape identic cu cea a lui INSERT: a REPLACE [LOW_PRIORITY | DELAYED] [INTO] tbl_name [(col_name,...)] VALUES (expr | DEFAULT,...),(...),... sau REPLACE [LOW_PRIORITY | DELAYED] [INTO] tbl_name SET col_name=expr | DEFAULT, ... sau REPLACE [LOW_PRIORITY | DELAYED] [INTO] tbl_name [(col_name,...)] SELECT ... Pentru tabelele care nu au cheie primar sau cmpuri cu index unic, aceast comand a a a a este identic cu INSERT. a Aceast interogare este o extensie MySQL a limbajului SQL. a momentul care se dorete folosirea lui REPLACE, se parcurg urmtorii pai: In n s a s 1. se ncearc inserarea obinuit a s a 2. dac inserarea obinuit nu functioneaz: a s a a se terge s nregistrarea veche care nu respect conditia a se insereaz noua a nregistrare 32

Un exemplu de folosire este urmtorul: a REPLACE INTO tipuri_curs VALUES(2,"alta");

2.3.3

Interogarea UPDATE

Interogarea UPDATE are urmtoarea form: a a UPDATE [LOW_PRIORITY] [IGNORE] tbl_name SET col_name1=expr1 [, col_name2=expr2 ...] [WHERE where_condition] [ORDER BY ...] [LIMIT row_count] sau UPDATE [LOW_PRIORITY] [IGNORE] table_references SET col_name1=expr1 [, col_name2=expr2 ...] [WHERE where_condition] Dup cum se poate vedea primul exemplu, sectiunea SET precizeaz care sunt coloanele a n a a cror valoare se modic, iar sectiunea WHERE pentru ce a a nregistrri se aplic interogarea. a a Chiar dac la prima vedere, sensul clauzei ORDER BY nu este aa de evident, ea se a s poate folosi in situatia care se dorete modicarea valorilor unei coloane numerice, care n s este i cheie primar. Dac s-ar produce modicarea s a a ntr-o ordine aleatoare ar putea aprea a conicte la modicarea valorilor (duplicate), pe cnd dac se fac modicrile de la cea mai a a a mare valoare ctre cea mai mic nu apare eroare. a a Cea de-a doua variant a lui UPDATE se folosete cazul interogrilor pe mai multe a s n a tabele. Prezentm continuare cteva exemple: a n a S se modice toate notele mai mici dect 4, nota 4. a a n UPDATE note SET nota=4 WHERE nota<4 AND nota>1; S se creasc toate numerele matricole din tabela studenti cu o unitate. a a UPDATE studenti SET nrmatricol=nrmatricol+1 ORDER BY nrmatricol DESC; S se creasc data a a nrolrii cu o zi pentru acei studenti care sunt din Braov. a s 33

UPDATE studenti, inrolari SET data_inrolare=data_inrolare + INTERVAL 1 DAY WHERE studenti.nrmatricol=inrolari.nrmatricol AND oras=brasov sau UPDATE inrolari SET data_inrolare=data_inrolare + INTERVAL 1 DAY WHERE nrmatricol IN ( SELECT nrmatricol FROM studenti WHERE oras=Brasov ) Dup cum se poate observa, aceast interogare modic date din doar una din cele 2 a a a tabele. Totui este posibil s se modice i colone din 2 tabele. s a s

2.3.4

Interogarea DELETE

Interogarea DELETE are urmtoarea form: a a DELETE [LOW_PRIORITY] [QUICK] [IGNORE] FROM tbl_name [WHERE where_condition] [ORDER BY ...] [LIMIT row_count] sau DELETE [LOW_PRIORITY] [QUICK] [IGNORE] tbl_name[.*] [, tbl_name[.*]] ... FROM table_references [WHERE where_condition] sau DELETE [LOW_PRIORITY] [QUICK] [IGNORE] FROM tbl_name[.*] [, tbl_name[.*]] ... USING table_references [WHERE where_condition] Prima form a interogrii DELETE are ca efect tergerea acelor a a s nregistrri din tabela a specicat, care respect conditia din clauza WHERE. Dac clauza WHERE nu este specia a a cat, atunci se terg toate a s nregistrrile din tabela specicat. a a Clauza LIMIT specic numrul maxim de a a nregistrri care se pot terge. Clauza ORa s DER BY specic ordinea care se terg a n s nregistrrile i are sens numai conjunctie cu a s n LIMIT. 34

A doua form a lui DELETE are ca efect tergerea de a s nregistrri din unul sau mai multe a tabele, dar cooncordant cu n a nregistrri din alte tabele. a Acelai lucru face i formularea a treia, dup cum vom putea observa exemplele s l s a n urmtoare. a S se tearg toate a s a nregistrrile din tabela note. a DELETE FROM note; S se tearg informatiile despre totii studentii care sunt din Brasov. a s a DELETE FROM studenti WHERE oras=Brasov; S se tearg toate a s a nrolrile care corespund unor studenti din Brasov. a DELETE inrolari FROM inrolari, studenti WHERE inrolari.nrmatricol=studenti.nrmatricol AND oras=brasov DELETE FROM inrolari USING inrolari, studenti WHERE inrolari.nrmatricol=studenti.nrmatricol AND oras=brasov

2.3.5

Interogarea TRUNCATE

Aceast interogare are ca efect tergerea tuturor a s nregistrrilor dintr-o tabel. a a Sintaxa ei este urmtoarea: a TRUNCATE [TABLE] tbl_name Aceasta este o extensie Oracle care a fost adoptat i MySQL. a s n Pentru anumite tipuri de stocare i anumite versiuni de MySQL TRUNCATE folosete s s de fapt DELETE. Pentru ultimele versiuni de MySQL i pentru anumite tipuri de stocare, s TRUNCATE este mai rapid deoarece nu terge a s nregistrrile pe rnd. Trebuie fcute cteva a a a a observatii: TRUNCATE terge tabela i o recreeaz, acesta ind motivul pentru care este mai s s a rapid Se reseteaz valorile contorului pentru auto increment a 35

Deoarece nu se invoc DELETE, nu se actioneaz triggerrul ON DELETE a a TRUNCATE functioneaz chiar dac datele sunt corupte sau dac ierul de index a a a s este corupt. Un exemplu, care realizeaz tergerea tuturor as nregistrrilor din tabela studenti este: a TRUNCATE TABLE studenti;

36

Capitolul 3 Crearea obiectelor bazei de date


3.1 Crearea unei baze de date

Pentru a crea o baz de date folosim instructiunea CREATE DATABASE. Baza de date a pe care o folosim exemplele din acest curs se numete mydatabasei a fost creat n s s a n urma instructiunii urmtoare: a CREATE DATABASE mydatabase; Instructiunea CREATE DATABASE are urmtoarea sintax: a a CREATE DATABASE | SCHEMA [IF NOT EXISTS] db_name [create_specification [create_specification] ...] create_specification: [DEFAULT] CHARACTER SET charset_name | [DEFAULT] COLLATE collation_name Un set de caractere este o multime de simboluri i codri, timp ce termenul de colla s a n tion se refer la seturi de reguli referitoare la compararea acestor caractere. Pentru detalii a suplimentare referitoare la utilizarea lor recomandm studierea documentatiei MySQL. a Dac vrem s folosim baza de date creat anterior, trebuie ai s o selectm folosind a a a nt a a instructiunea USE: USE mydatabase; Pentru a vedea ce tabele cuprinde baza de date introducem: SHOW TABLES; Inainte de a trece mai departe este important s elegem i cum este retinut o baz de a nt s a a date din punct de vedere zic. O astfel de baz de date este retinut sub forma unui director a a care contine mai multe iere. Acest director poart numele bazei de date i este situat s a s n 37

directorul data aat directorul care avem instalat aplicatia MySQL. functie de n n a In engine-ul folosit se poate ca modalitile de stocare s difere, motiv pentru care vom intra at a detalii specice cnd vorbim de engine-uri. n a Totui, trebuie specicat c pentru ecare tabel se face un ier cu extensia .FRM care s a s contine tabela i denitiile coloanelor. Indexul i datele pot stocate unul sau mai multe s s n iere auxiliare, depinznd de tipul engine-ului folosit. Fiierul .FRM este creat deasupra s a s engine-urilor. Odat creat baza de date, urmtorul pas pe care trebuie s-l facem este s crem tabele, a a a a a a dar pentru acest lucru trebuie s tim ce tipuri de date ne pune la dispozitie MySQL. Acestea as sunt prezentate sectiunea imediat urmtoare. n a

3.2

Tipuri de date

MySQL ofer mai multe categorii de tipuri de date care vor detaliate cele ce urmeaz: a n a tipuri de date numerice, pentru iruri de caractere, pentru timp etc. s

3.2.1

Tipuri numerice
Tabela 3.1: Tipuri de date numerice

tabela 3.1 prezentm tipurile de date numerice care se pot folosi MySQL. In a n

Tip BIGINT BIT NUMERIC REAL FLOAT INT MEDIUMINT SMALLINT TINYINT

Dimensiune 8 bytes variaz a 8 bytes 4 bytes 4 bytes 3 bytes 2 bytes 1 bytes

Sinonime

DEC, DECIMAL DOUBLE, DOUBLE PRECISION INTEGER

Pentru tipurile de date prezentate, se pot stabili mai multe caracteristici: AUTO INCREMENT - specic dac acel cmp trebuie s e generat automat. Se a a a a poate folosi numai cazul tipurilor de date n ntregi. ZEROFILL - specic dac la aarea datelor din acel cmp trebuie s se foloseasc a a s a a a zerouri la aarea lui, dac are mai putine caractere dect numrul caracterelor care s a a a trebuie aate. s UNSIGNED - poate retine numai numere pozitive, de dou ori mai mari dect numrul a a a 38

maxim admis. Acest lucru este posibil deoarece bitul de semn se folosete i el pentru s s a retine numrul. a Pentru toate tipurile de date se poate specica parantez, pe cte spatii s se n a a a reprezinte. Pentru tipurile de date care retin numere reale se poate specica i numrul de cifre s a de dup virgul. a a Vom prezenta exemple de declarare a unor variabile sectiunea dedicat creeri tabelelor. n a Deoarece s-a constat c este foarte folosit practic tipul BIGINT ca i cheie primar, a n a s a s-a denit i tipul de dat SERIAL care este sinonim cu BIGINT PRIMARY KEY NOT s a NULL AUTO INCREMENT.

3.2.2

Tipuri pentru iruri de caractere s

Pentru lucrul cu iruri de caractere sunt disponibile mai multe tipuri de date reprezentate s tabela 3.2. n Tabela 3.2: Tipuri de date pentru iruri de caractere s Tip CHAR CHARACTER NCHAR VARCHAR TINYTEXT TEXT MEDIUMTEXT LONGTEXT Variant a binar a BINARY BINARY BINARY VARBINARY TINYBLOB BLOB MEDIUMBLOB LONGBLOB Dimensiune maxim a 255 255 255 65535 255 65535 16777215 4294967295

Diferenta ntre tipurile CHAR i VARCHAR este c pentru un tip CHAR se folosete s a s aceeai zon de memorie pentru retinerea lui, indiferent de lungimea actual a datei retinute, s a a timp ce pentru VARCHAR se folosete doar atta zon de memorie ct este nevoie. Acest n s a a a lucru are un impact important asupra performantei bazei de date, sensul care, dac n n a folosim CHAR lungimea nregistrrilor este constant, timp ce cu VARCHAR lungimea a a n nregistrrilor este variabil i accesul direct la a as nregistrri se face mai a ncet. Observatie: Degeaba folosim mai multe coloane de tipul CHAR ntr-o tabel dac avem a a mcar o coloan de tipul VARCHAR! a a Diferenta ntre tipurile normale i tipurile binare este c la tipurile normale se lucreaz s a a cu caractere timp ce la tipurile binare lucrm cu bytes. n a 39

3.2.3

Tipuri pentru lucrul cu date

Pentru lucrul cu date, avem disponibile tipurile de date reprezentate tabela 3.3. Putem n uor observa c avem tipuri care retin date calendaristice, timpul precum i date calendariss a s tice combinate cu timpul. Tabela 3.3: Tipuri de date pentru date i timp s Tip DATE DATETIME TIME TIMESTAMP YEAR Dimensiune 3 bytes 8 bytes 3 bytes 4 bytes 1 byte Format YYYY-MM-DD YYYY-MM-DD hh:mm:ss hh:mm:ss YYYY-MM-DD hh:mm:ss YYYY

Un tip de date mai deosebit este TIMESTAMP. Dac a ntr-o coloan de tipul TIMESa TAMP se insereaz valoarea NULL, automat acea coloan se insereaz valoarea datei a n a a curente. Bine eles c pentru tipurile de date de tip dat i timp exist numeroase functii care nt a as a pot utilizate. Acestea vor prezentate capitolul dedicat functiilor MySQL. n

3.2.4

Alegerea ecient a tipurilor de date a

momentul care dorim s alegem un tip de date, ar bine pentru optimizare, s In n a a respectm urmtoarele reguli: a a Smaller is better - s alegem tipuri potrivite, sucient de mari ca s putem retine a a datele dar ct mai mici posibil. Acest lucru ecientizeaz att memoria pe disc ct i a a a a s memoria din cache-ul CPU. Simple is good - numerele ntregi se compar mai simplu dect irurile de caractere (nu a a s au character set sau collation). Avoid NULL if possible - pentru MySQL este mult mai greu s lucreze cu cmpuri care a a pot avea valoarea NULL dect cu cmpuri care nu pot avea aceast valoare. Acest a a a lucru este cu att mai evident cnd coloana respectiv este indexat. a a a a Alegeti cu grij ntre FLOAT, DOUBLE - DECIMAL - primele 2 au dezavantajul c a a se fac calcule aproximative, dar mai repede; tipul DECIMAL face calcule exacte dar mai inecient. Alegeti cu grij ntre CHAR i VARCHAR. Se prefer folosirea lui VARCHAR cnd a s a a una sau mai multe conditii sunt adevarate: Dimensiunea maxim a coloanei este mult mai mare dect dimensiunea medie a a 40

Actualizrile sunt destul de rare (dac ar dese ar conduce la fragmentri ale a a a memoriei) Cnd avem character set complex, care retine ecare liter pe un numr variabil a a a de bytes. Se prefer folosirea lui CHAR cnd: a a Avem iruri de caractere mici s Cnd toate valorile au dimensiuni aproximativ egale - de exemplu cnd se stocheaz a a a parole MD5 Cnd facem foarte des actualizri ale datelor a a anumite situatii tipul ENUM este mai ecient dect CHAR sau VARCHAR: In a create table persoane ( cod_persoana SERIAL, nume VARCHAR(30) NOT NULL, sex ENUM(masculin,feminin) NOT NULL ) insert into persoane values (null,Ion,masculin); select sex+0 from persoane; -- va afisa numere de 0 si 1 select * from persoane order by sex; -- pune inainte persoanele de sex masculin select * from persoane order by field (sex,feminin,masculin); Printre dezavantajele acestei abordri ar faptul c numrul de valori permise e x, a a a precum i faptul c la JOIN-uri trebuie fcute foarte multe cutri pentru a face s a a a a potrivirile. Printre avantaje este faptul c se folosete mai putin memorie, inclusiv a s a pentru cmp ct i pentru cheile care sunt retinute. a a s Pentru retinerea unei adrese IP se poate folosi nu un VARCHAR(15) ci un INT pe 32 s biti, cu ajutorul functiilor INET ATON() i INET NTOA(). 41

3.3
3.3.1

Crearea tabelelor
Crearea unor tabele simple

Iat c a venit i momentul pentru a crea tabele. Acest lucru se realizeaz foarte simplu, a a s a cu ajutorul instructiunii CREATE TABLE, care primete numele tabelului, paranteze s n rotunde numele ecrei coloane i caracteristicile ei, precum i tipul tabelei respective. a s s Sintaxa instructiunii CREATE TABLE este una din cele mai complicate, ea artnd a a n documentatia MySQL astfel: CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name (create_definition,...) [table_option ...] sau: CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name [(create_definition,...)] [table_option ...] select_statement sau: CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name LIKE old_tbl_name | (LIKE old_tbl_name) create_definition: column_definition | [CONSTRAINT [symbol]] PRIMARY KEY [index_type] (index_col_name,...) | INDEX|KEY [index_name] [index_type] (index_col_name,...) | [CONSTRAINT [symbol]] UNIQUE [INDEX|KEY] [index_name] [index_type] (index_col_name,...) | FULLTEXT|SPATIAL [INDEX|KEY] [index_name] (index_col_name,...) | [CONSTRAINT [symbol]] FOREIGN KEY [index_name] (index_col_name,...) [reference_definition] | CHECK (expr) column_definition: col_name data_type [NOT NULL | NULL] [DEFAULT default_value] [AUTO_INCREMENT] [UNIQUE [KEY] | [PRIMARY] KEY] [COMMENT string] [reference_definition] data_type: BIT[(length)] | TINYINT[(length)] [UNSIGNED] [ZEROFILL] | SMALLINT[(length)] [UNSIGNED] [ZEROFILL] 42

| | | | | | | | | | | | | | | | | | | | | | | | | | | | |

MEDIUMINT[(length)] [UNSIGNED] [ZEROFILL] INT[(length)] [UNSIGNED] [ZEROFILL] INTEGER[(length)] [UNSIGNED] [ZEROFILL] BIGINT[(length)] [UNSIGNED] [ZEROFILL] REAL[(length,decimals)] [UNSIGNED] [ZEROFILL] DOUBLE[(length,decimals)] [UNSIGNED] [ZEROFILL] FLOAT[(length,decimals)] [UNSIGNED] [ZEROFILL] DECIMAL(length,decimals) [UNSIGNED] [ZEROFILL] NUMERIC(length,decimals) [UNSIGNED] [ZEROFILL] DATE TIME TIMESTAMP DATETIME YEAR CHAR(length) [CHARACTER SET charset_name] [COLLATE collation_name] VARCHAR(length) [CHARACTER SET charset_name] [COLLATE collation_name] BINARY(length) VARBINARY(length) TINYBLOB BLOB MEDIUMBLOB LONGBLOB TINYTEXT [BINARY] [CHARACTER SET charset_name] [COLLATE collation_name] TEXT [BINARY] [CHARACTER SET charset_name] [COLLATE collation_name] MEDIUMTEXT [BINARY] [CHARACTER SET charset_name] [COLLATE collation_name] LONGTEXT [BINARY] [CHARACTER SET charset_name] [COLLATE collation_name] ENUM(value1,value2,value3,...) [CHARACTER SET charset_name] [COLLATE collation_name] SET(value1,value2,value3,...) [CHARACTER SET charset_name] [COLLATE collation_name] spatial_type

index_col_name: col_name [(length)] [ASC | DESC] index_type:

43

USING BTREE | HASH reference_definition: REFERENCES tbl_name [(index_col_name,...)] [MATCH FULL | MATCH PARTIAL | MATCH SIMPLE] [ON DELETE reference_option] [ON UPDATE reference_option] reference_option: RESTRICT | CASCADE | SET NULL | NO ACTION table_option: ENGINE|TYPE [=] engine_name | AUTO_INCREMENT [=] value | AVG_ROW_LENGTH [=] value | [DEFAULT] CHARACTER SET charset_name | CHECKSUM [=] 0 | 1 | COLLATE collation_name | COMMENT [=] string | CONNECTION [=] connect_string | DATA DIRECTORY [=] absolute path to directory | DELAY_KEY_WRITE [=] 0 | 1 | INDEX DIRECTORY [=] absolute path to directory | INSERT_METHOD [=] NO | FIRST | LAST | MAX_ROWS [=] value | MIN_ROWS [=] value | PACK_KEYS [=] 0 | 1 | DEFAULT | PASSWORD [=] string | ROW_FORMAT [=] DEFAULT|DYNAMIC|FIXED|COMPRESSED|REDUNDANT|COMPACT | UNION [=] (tbl_name[,tbl_name]...) select_statement: [IGNORE | REPLACE] [AS] SELECT ...

(Some legal select statement)

O astfel de tabel (un exemplu mai simplu) se creeaz astfel: a a create table studenti( nrmatricol bigint primary key not null, nume varchar(30) not null, prenume varchar(30) not null, CNP varchar(13) not null, sex char(1)not null, 44

datan date not null, oras varchar(30) not null, judet varchar(30) not null, tara varchar(30) not null ) Engine=InnoDB; Dup cum se poate vedea se specic primul rnd numele tabelei, dup care pentru a a n a a ecare cmp parte se specic numele, tipul lui, dac poate sau nu s ia valoarea NULL, a n a a a dac este cheie primar, nal stabilindu-se tipul de tabel. a a n Pentru ecare coloan se mai pot preciza anumite informatii precum un mic comentariu a i valoarea implicita (default). s Iat un exemplu: a CREATE TABLE pers ( cod_pers BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT codul persoanei, nume VARCHAR(30) NOT NULL COMMENT numele persoanei, data_inrolare DATE NOT NULL DEFAULT NOW() COMMENT data la care s-a inrolat persoana ) Valoarea implicit mai poate folosit i cadrul unor interogri UPDATE: a a s n a UPDATE studenti SET data_inrolarii=DEFAULT Se mai pot preciza i alte informatii la crearea unui tabel, referitoare la indeci i chei s s s strine, dar acestea sunt prezentate sectiunile urmtoare. a n a

3.3.2

Copierea tabelelor

Se poate crea o tabel care s aib exact aceeai structur ca i o tabel existent, dar la a a a s a s a a nceput s e goal. Acest lucru se poate face cu instructiunea CREATE TABLE ... LIKE. a a Iat i un mic exemplu care creaz o astfel de tabel: as a a CREATE TABLE studenti2 LIKE studenti; Putem verica faptul c totul a functionat bine prin instructiunea urmtoare care ne a a prezint structura tabelei autori2: a DESCRIBE studenti2; 45

Trebuie remarcat, c aceast situatie, nu s-au copiat i informatiile despre indeci i a n a s s s constrngeri de integritate. a Dac vrem s copiem att structura ct i anumite date, putem proceda astfel: a a a a s CREATE TABLE studenti2 AS ( SELECT * FROM studenti ) Se poate s i lum structura unei tabele i s modicm anumite lucruri: as a s a a CREATE TABLE studenti3 ( nume VARCHAR(30) NULL, prenume VARCHAR(30) NULL ) AS (SELECT * FROM studenti)

3.3.3

Crearea tabelelor temporare

Se poate s creem tabele care s nu reziste dect pe perioada unei sesiuni. Acestea poart a a a a numele de tabele temporare. Ele pot , de asemenea, terse i de utilizator. s s Un astfel de exemplu, de creare a unei tabele temporare este urmtorul: a CREATE TEMPORARY TABLE studenti2 ( studentid BIGINT PRIMARY KEY AUTO_INCREMENT NOT NULL, nume VARCHAR(20) NOT NULL ) Trebuie fcute cteva observatii importante: a a O astfel de tabel se poate folosi la fel ca i orice alt tabel. a s a a Numai utilizatorul care a creat-o o poate folosi. Putem avea o tabel temporar i una permanent cu acelai nume. Totui, astfel a as a s s n de situatii, tabela temporar o ascunde pe cea permanent. a a Ca i in cazul tabelelor normale, se poate folosi IF NOT EXISTS, pentru ca dac exist s a a deja o tabel temporar cu acel nume s nu ne dea eroare: a a a CREATE TEMPORARY TABLE test IF NOT EXISTS (...) 46

3.3.4

Optiuni ale tabelelor

momentul care creem tabele, putem specica i alte informatii care nu au fost In n s prezentate pn acum, precum: engine-ul folosit, cum se lucreaz cu valori auto increment, a a a stabilirea de comentarii la nivel de tabele, lucruri legate de numrul de a nregistrri din tabele a etc. Stabilirea ENGINE-ului folosit pentru un tabel ENGINE-ul corespunztor unui tabel specic modul care datele din tabel sunt stocate, a a n cum pot accesate i cum sunt rezolvate tranzactiile. s Exist engine-uri care sunt mai bune la realizarea select-urilor, unele mai bune la updatea uri sau altele care se potrivesc mai bine pentru tabele temporare. Pentru a vedea o lista cu toate engine-urile disponibile putem executa: SHOW ENGINES; Dou dintre cele mai importante engine-uri sunt MyISAM i InnoDB (dac nu specicm a s a a altceva, cel implicit este MyISAM). Sintaxa pentru specicare este urmtoarea: a CREATE TABLE pers ( persid BIGINT PRIMARY KEY NOT NULL, nume VARCHAR(30) NOT NULL) ENGINE=InnoDB Pentru tabelele temporare este recomandabil ca engine-ul folosit s e MEMORY, care a automat distruge tabel momentul care serverul de baze de date este oprit. a n n Se poate aa engine-ul implicit folosind urmtoarea comand: s a a SELECT @@STORAGE_ENGINE; Principalele engine-uri din MySQL sunt: MyISAM - pentru tabele care nu suport tranzactii. Avem o vitez foarte mare la a a stocarea i obtinerea datelor i suport full text searching capabilities s s a MEMORY - tabele care sunt pstrate memoria RAM. Nu suport tranzactii. a n a MERGE - permit ca o colectie de mai multe tabele identice s e tratate ca unul a singur. Nici acestea nu suport tranzactii. a InnoDB - suport tranzatii i chei strine (FOREIGN KEY) a s a BDB - suporta tranzactii 47

Example - nu se folosete practic, este doar un exemplu simplu de cum s-ar imples n a menta un engine nou pentru cei care ar interesati s-i scrie propriul engine as NDBCLUSTER (NDB) - pentru tabele care sunt distribuite pe mai multe calculatoare ARCHIVE - pentru tabele care contin cantiti foarte mari de date i care nu suport at s a indeci. s CSV - retine datele iere text, separate prin virgul (CSV - Comma Separated n s a Values). Engine-urile se mpart dou mari categorii, cele care suport tranzactii i cele care nu n a a s suport. a Avantajele celor care nu suport sunt urmtoarele: a a sunt mai rapide au nevoie de mai putin spatiu pe disk mai putin memorie pentru a realiza actualizri a a Printre avantajele celor care suport tranzactii: a sunt mai sigure ( caz de probleme hardware integritatea datelor poate pstrat mai n a a uor) s se poate s combinm mai multe instructiuni i s le acceptm pe toate odat cu a a s a a a COMMIT se poate da ROLLBACK dac vrem s refacem nite operatii a a s putem stabili singuri nivelul de concurenta Principalele caracteristici ale engine-ului MyISAM sunt urmtoarele: a Fiecare tabel se retine 3 iere: .frm (formatul tabelei), .MYD (MyData - datele a n s din tabel) i .MYI (MyIndex - indecii tabelei) a s s Numrul maxim de a nregistrri dintr-o tabel este 232 (cu conguratii speciale 264 ) a a O tabel poate avea maxim 64 de indeci ( cu conguratii speciale 128) a s Lungimea maxim a cheii este de 1000 bytes a s s Cu optiunile DATA DIRECTORY i INDEX DIRECTORY se pot pune datele i in decii alte directoare dect cel care se retine ierul .frm (pentru performante mai s n a n s bune) Unele din principalele caracteristici ale engine-ului InnoDB sunt: 48

Concurenta i performant s a mbuntite mediile multiutilizator a at n Limita maxim a unei baze de date este de 64 TB a Retine tabelele i indecii s s ntr-un tabelspace, care se poate arti mai multe iere mp n s Pentru retinerea ierelor folosete formatul .frm plus un InnoDB data dictionary. s s Acesta este motivul pentru care nu se pot muta tabelele i bazele de date de pe un s server pe altul numai prin simpla mutare a directoarelor. O tabel poate avea maxim 1000 coloane a Actiunile cascad legate de chei strine nu activeaz triggere n a a a A nu se converti tabelele sistem ale MySQL de la MyISAM la InnoDB, deoarece aceast a operatie nu este suportat. a Stabilirea strategiei pentru auto increment Dup cum am putut vedea, dac avem coloane care avem numere care vrem s se a a n a genereze automat, putem folosi optiunea AUTO INCREMENT. Automat, se genereaz toate a numerele ncepnd cu 1 i cu pasul 1. a s n Putem specica o valoare de la care s a nceap AUTO INCREMENT-ul, ca exemplul: a CREATE TABLE studenti (...) AUTO_INCREMENT=100; Comentarii pentru tabel La fel cum putem s stabilim nite comentarii pentru ecare coloan, asemntor se pot a s a a a stabili comentarii i la nivel de tabel. s Acestea se pot stabili ca exemplul urmtor: n a CREATE TABLE studenti (...) COMMENT Retine informatii despre studenti s Optiunile AVG ROW LENGTH, MAX ROWS i MIN ROWS Pentru ca engine-ul s functioneze mai bine putem preciza care este lungimea medie a a i unei nregistrri ( bytes), numrul maxim de a n a nregistrri pe care bnuim c-l vom avea i a a a s numrul minim. a Un exemplu este prezentat continuare: n 49

CREATE TABLE studenti (...) AVG_ROW_LENGTH=20 MAX_ROWS=2000000 MIN_ROWS=1000000

3.3.5

Tabelele i catalogul MySQL s

versiunile mai noi de MySQL exist o baz de date care se numete information schema In a a s i care contine numeroase informatii precum cele despre tabele, coloanele lor etc. s Tot aici se salveaz toate comentariile, informatiile despre engine-uri etc. a Se recomand studierea acestei baze de date pentru a elege mai bine cum retine MySQL a nt informatiile referitoare la structura bazelor de date.

3.3.6

Specicarea constrngerilor de integritate a

momentul care lucrm cu o baz de date, trebuie ca orice moment baza de date In n a a n s se ae a ntr-o stare valid. a Constrngerile de integritate sunt regulile pe care continutul bazei de date trebuie s le a a respecte tot timpul. Ele descriu ce actualizri asupra bazei de date sunt permise. a Astfel de constrngeri sunt NOT NULL ( a fost deja prezentat), PRIMARY KEY, a a FOREIGN KEY, UNIQUE. Stabilirea unei chei primare (PRIMARY KEY) O cheie primar este o coloan sau un grup de coloane care identic mod unic orice a a a n nregistrare. Dup cum se tie deja, cheile primare nu pot avea valoarea NULL. a s Cheia primar poate specicat astfel: a a CREATE TABLE studenti( cod_student BIGINT PRIMARY KEY NOT NULL AUTO_INCREMENT, .... ) sau CREATE TABLE carti_autori( cod_carte BIGINT NOT NULL, cod_autor BIGINT NOT NULL, ...., PRIMARY KEY(cod_carte, cod_autor) ) Cea de-a doua variant se folosete atunci cnd avem chei primare compuse din mai multe a s a cmpuri. a 50

Dac avem un cmp care este cheie primar, automat se sub elege c el nu poate avea a a a nt a valoarea NULL. Totui este un lucru bun s precizm acest lucru. s a a Cteva observatii: a O tabel nu poate avea mai mult de o cheie primar. a a Teoria relational spune c ar trebui s avem obligatoriu o cheie primar, dar MySQL a a a a nu ne oblig la acest lucru. a Cheia primar trebuie s e alctuit din cel mai mic set de coloane care ne asigur a a a a a unicitatea. Automat, pentru ecare cheie primar se creeaz un index. Dac vrem s dm un nume a a a a a acestei constrngeri, putem face acest lucru: a CREATE TABLE studenti ( ... PRIMARY KEY primary_key_studenti (cod_student) ) Stabilirea cheilor alternative (UNIQUE) Se poate MySQL s stabilim i chei alternative folosind UNIQUE. Aceste chei altern a s native sunt chei candidat care nu au fost alese chei primare. O diferenta fata de cheile primare este faptul c ele pot admite i valoarea NULL, dar a s nu admit alte duplicate. Stabilirea cheilor strine (FOREIGN KEYS) a primul rnd trebuie prentat notiunea de constrngere de integritate referential. In a a a a O constrngere de integritate referential se refer la faptul c valorile din anumite a a a a coloane trebuie neaprat s-i gaseasc corespondentul nite valori din alt tabel. a as a n s a a situatia care engine-ul folosit este InnoDB, avem dreptul s lucrm cu chei strine In n a a a (foreign keys). De exemplu, am putea crea tabela inrolari astfel: CREATE TABLE inrolari( cod_inrolare BIGINT PRIMARY KEY AUTO_INCREMENT, nrmatricol BIGINT NOT NULL, cod_curs BIGINT NOT NULL, data_inrolare DATE NOT NULL, FOREIGN KEY(nrmatricol) REFERENCES studenti(nrmatricol) ON UPDATE CASCADE ON DELETE CASCADE, 51

FOREIGN KEY (cod_curs) REFERENCES cursuri(cod_curs) ) ENGINE=InnoDB; Cheile strine se pot referi numai la chei primare sau la coloane UNIQUE. Pot i grupuri a s de coloane dac valoarea lor este garantat s e unic. a a a a mod implicit, nu se poate terge, acest caz, nici o In s n nregistrare din tabela studenti atta timp ct tabela inrolari exist a a n a nregistrri care se refer la acea a a nregistrare. Operatiile care pot produce probleme sunt UPDATE i DELETE, de aceea avem dou s a situatii care trebuie s specicm ce se ampl: ON UPDATE i ON DELETE. n a a nt a s Avem 5 actiuni posibile: CASCADE (face ca actualizarea/ tergerea s se fac cascad) s a a n a RESTRICT (nu se poate actualiza/ terge dac exist s a a nregistrri legate de aceasta) a SET NULL (se nlocuiesc toate aparitiile acelei valori cu NULL chiar dac acea coloan a a nu ar accepta acest lucru) NO ACTION (este identic cu RESTRICT) SET DEFAULT (se ncearc setarea valorii respective la valoarea ei DEFAULT) a Constrngerile de integritate se mai pot verica i folosind CHECK, ca exemplele a s n urmtoare: a CREATE TABLE studenti( ... sex CHAR(1) NOT NULL CHECK(sex IN(m,f)), datan DATE NOT NULL CHECK (datan>1980-10-12) ..., CONSTRAINT verificare_tara CHECK (tara IN (Romania,Germania)) ) Dup cum am vzut ultimul exemplu se poate ca s dm nume constrngerilor, lucru a a n a a a care se va dovedi util un pic mai trziu. a

3.4

Stergerea tabelelor - DROP TABLE

Pentru a terge tabele s ntregi (i date i structur i indeci) putem folosi instructiunea s s as s DROP TABLE(S) care are urmtoarea sintax: a a 52

DROP [TEMPORARY] TABLE [IF EXISTS] tbl_name [, tbl_name] ... [RESTRICT | CASCADE] O tabel poate tears numai dac nu are chei strine care pointeaz la ea. a s a a a a Altfel, pentru a putea terge o astfel de tabel ai tergem constrngerile e folosim s a nt s a optiunea CASCADE. Aceasta din urm ar putea avea ca efect chiar i stergerea tuturor a s tabelelor din baza de date, anumite circumstante. n

3.5

Redenumirea tabelelor - RENAME TABLE

Se poate s redenumim un tabel folosind comanda RENAME TABLE, care are urmtoarea a a sintax: a RENAME TABLE tbl_name TO new_tbl_name [, tbl_name2 TO new_tbl_name2] ... Un exemplu ar arta astfel: a RENAME TABEL studenti TO students;

3.6

Schimbarea structurii tabelului - ALTER TABLE

Una din cele mai complexe comenzi SQL este ALTER TABLE, care are urmtoarea a sintax: a ALTER [IGNORE] TABLE tbl_name alter_specification [, alter_specification] ... alter_specification: table_option ... | ADD [COLUMN] column_definition [FIRST | AFTER col_name ] | ADD [COLUMN] (column_definition,...) | ADD INDEX|KEY [index_name] [index_type] (index_col_name,...) | ADD [CONSTRAINT [symbol]] PRIMARY KEY [index_type] (index_col_name,...) | ADD [CONSTRAINT [symbol]] UNIQUE [INDEX|KEY] [index_name] [index_type] (index_col_name,...) | ADD [FULLTEXT|SPATIAL] [INDEX|KEY] [index_name] (index_col_name,...) | ADD [CONSTRAINT [symbol]] FOREIGN KEY [index_name] (index_col_name,...) [reference_definition] | ALTER [COLUMN] col_name SET DEFAULT literal | DROP DEFAULT 53

| CHANGE [COLUMN] old_col_name column_definition [FIRST|AFTER col_name] | MODIFY [COLUMN] column_definition [FIRST | AFTER col_name] | DROP [COLUMN] col_name | DROP PRIMARY KEY | DROP INDEX|KEY index_name | DROP FOREIGN KEY fk_symbol | DISABLE KEYS | ENABLE KEYS | RENAME [TO] new_tbl_name | ORDER BY col_name [, col_name] ... | CONVERT TO CHARACTER SET charset_name [COLLATE collation_name] | [DEFAULT] CHARACTER SET charset_name [COLLATE collation_name] | DISCARD TABLESPACE | IMPORT TABLESPACE index_col_name: col_name [(length)] [ASC | DESC] index_type: USING BTREE | HASH Prezentm cteva exemple de interogri care folosesc aceast instructiune: a a a a S se redenumeasc tabela studenti students a a n ALTER TABLE studenti RENAME TO students s S se modice proprietatea auto increment i comentariul pentru tabela studenti a ALTER TABLE studenti AUTO_INCREMENT=1000 COMMENT=tabela studenti S se schimbe engine-ul tabelei studenti InnoDB. a n ALTER TABLE studenti ENGINE=InnoDB

3.6.1

Schimbarea coloanelor

Prezentm exemple de interogri: a a S se insereze o nou coloan grupa, ir de caractere de 4 caractere, dup cmpul sex. a a a s a a 54

ALTER TABLE studenti ADD COLUMN grupa CHAR(4) AFTER sex Automat toate valorile din noua coloan vor initializate cu NULL. Dac acea coloan a a a nu ar permis valoarea NULL, s-ar inserat valoarea implicit pentru cmpul respeca a tiv. S se tearga coloana grupa din tabela studenti. a s ALTER TABLE studenti DROP grupa Se vor terge toate obiectele care depind de aceast coloan. s a a S se schimbe numele coloanei sex gen. a n ALTER TABLE studenti CHANGE sex gen S se schimbe cmpul nume astfel at s retin un ir de caractere de 50 de caractere. a a nc a a s ALTER TABLE studenti CHANGE nume nume VARCHAR(50) NOT NULL S se pun cmpul oras pe pozitia a doua. a a a ALTER TABLE studenti CHANGE oras oras VARCHAR(30) AFTER nrmatricol ALTER TABLE studenti MODIFY oras VARCHAR(30) AFTER nrmatricol S se tearg valoarea implicit a cmpului datan. a s a a a ALTER TABLE studenti ALTER datan DROP DEFAULT

3.6.2

Schimbarea constrngerilor de integritate a

Pentru a ilustra cum se poate face acest lucru vom prezenta cteva exemple: a S se fac legatura a a ntre tabelele studenti i inrolari. s 55

ALTER TABLE inrolari ADD CONSTRAINT fk_studenti FOREIGN KEY nrmatricol REFERENCES studenti(nrmatricol) S se elimine cheia primar a tabelei studenti. a a ALTER TABLE studenti DROP PRIMARY KEY S se tearg prima constrngere care a fost creat la a s a a a nceputul acestei sectiuni. ALTER TABLE inrolari DROP CONSTRAINT fk_studenti

3.7

Lucrul cu indeci s

momentul care lucrm cu baze de date, anumite operatii se pot face mai multe In n a n moduri. Dintre aceste moduri, unele sunt mai eciente, altele mai putin eciente. Sunt unele operatii, precum CREATE TABLE sau GRANT care nu pot optimizate, timpul lor de executie ind unul constant. Alte operatii, precum SELECT, INSERT, UPDATE i DELETE pot foarte mult s inuentate de modul care sunt scrise sau de modul care sunt retinute datele. n n Un astfel de mijloc, prin care se pot optimiza anumite operatii este folosirea indecilor. s

3.7.1

Cum se retin datele?

Inregistrrile dintr-o baz de date sunt stocate iere. functie de tipul de engine a a n s In folosit sau chiar de optiunea utilizatorului putem avea mai multe variante: Se poate ca pentru ecare tabel parte s avem cte un ier (cazul MyISAM). a n a a s Pentru toat baza de date s avem un singur ier (InnoDB - cazul implicit). a a s La rndul lor, datele dintr-un tabel sunt organizate pagini de date, a cror dimensiune a n a variaz functie de engine-ul folosit i de sistemul de operare (dimensiuni uzuale sunt cele a n s de 2K, 4K, 8K, 32K etc.). Numrul de a nregistrri care se retin a ntr-o pagin de memorie a este dictat att de dimensiunea paginii ct i de dimensiunea unei a a s nregistrri. a Atunci cnd se adaug noi a a nregistrri se adaug la sfritul ultimei pagini, sau dac a a as a aceasta s-a umplut, se adaug a ntr-o pagin nou. a a Motivul pentru care noile nregistrri nu se pun zonele care deja au fost eliberate prin a n tergeri este c, mai ales cazul tabelelor cu foarte multe s a n nregistrri, cutarea unei zone a a libere poate dura foarte mult. Un lucru foarte important de eles este c datele se aduc de pe hard-disk pe pagini i nt a s de abia dup aceea ele se prelucreaz memoria intern (RAM). a a n a 56

3.7.2

Ce este un index i cum functioneaz? s a

Indecii sunt folositi pentru a regsi anumite valori mult mai repede. Fr indeci ar s a aa s trebui parcurse toate nregistrrile pe rnd, ceea ce a a nseamn c, cu ct este mai mare a a a tabela cu att costurile sunt mai mari. a Atentie! Trebuie s m foarte atenti atunci cnd folosim diverse tools-uri pentru a a a genera continutul unei baze de date sau cnd folosim ORM-uri deoarece acestea foarte rar a creeaz indei cu toate c rolul acestora este foarte important. a s a Atentie! Indexul contine valori dintr-o coloan specicat sau mai multe coloane. Or a a dinea lor este foarte important deoarece cutrile se fac rapid numai dup prexe ale ina a a a decilor. s Atentie! Creearea unui index pe dou coloane nu este acelai lucru cu a crea 2 indeci a s s ecare pe cte o coloan. a a principiu, pentru accesarea In nregistrrilor dintr-un tabel exist mai multe metode, a a dintre care, cele mai folosite sunt dou: a metod de accesare secvential a datelor (cnd se parcurg toate a a a nregistrrile tabelei a pe rnd, pentru a se efectua o anumit operatie - este o metod care poate conduce la a a a o parcurgere costisitoare situatii care s-ar putea adopta solutii mai bune. Este ca n n i cum cartea de telefon am cuta un numr prin parcurgerea tuturor numelor din s n a a carte.) metoda de accesare indexat - se folosete un mecanism asemntor a s a a ntr-o oarecare msur celui folosit cartea de telefon. a a n MySQL un index e construit ca un arbore care are mai multe noduri. Este posibil s In a vrem s facem parcurgeri de mai multe tipuri: a gsirea unei a nregistrri cu o anumit valoare a a parcurgerea unei tabele pe baza unei coloane ordonate cnd vrem s obtinem mai multe valori a a Uneori este util s avem a nregistrrile ordonate zic functie de o anumit cheie, lucru a n a care face parcurgerea mult mai ecient. a Trebuie fcute mai multe observatii: a Fiierul index este mereu cooncordanta cu continutul tabelei, ceea ce s n nseamn c a a la operatiile de UPDATE, DELETE i INSERT el trebuie reactualizat. s Evident, putem avea i indeci neunici. s s Pe o tabel putem deni mai multi indeci iar un index poate i compus din mai a s s multe cmpuri. a Nodurile unui index sunt i ele stocate zic, ceea ce s nseamn c i ele ocup spatiu pe a as a disc. 57

Actualizrile tabelelor duc la actualizri ale indecilor. Acestea presupun, principiu a a s n umplerea locurilor libere din arbore, iar dac acest lucru nu se poate, se poate ajunge a i la crearea de noi noduri i eventual reorganizarea mai complex a arborelui. Aceste s s a operatii pot consuma destul de mult timp. Exist mai multe tipuri de indeci: a s Indeci care folosesc B-arbori s Indeci care folosesc tabele de dispersie (hash-tables) s Trebuie spus c ecare engine are anumite tipuri de indeci pe care le suport. Se poate a s a chiar ca acelai tip de index s aib implementri un pic diferite pentru engine-uri diferite. s a a a functie de situatie se poate ca un anumit tip de index s e mai potrivit dect altul. In a a Indeci care folosesc B-arbori s Indecii care folosesc B-arbori - sunt cei mai folositi ind recunoscuti de aproape toate s engine-urile, cu exceptia ARCHIVE ( recunoate doar pentru cmpurile de tip AUTO INCREMENT). l s a Unele engine-uri lucreaz cu variante foarte asemntoare dar un pic diferite (NDB folosete a a a s de fapt un T-Tree, chiar dac noi zicem s lucreze cu BTREE). a i a Fiecare engine poate retine indecii diferit: MyISAM retine s i ntr-un format compresat pe cnd InnoDB nu. a Ideea de baz unui B-Tree este c toate valorile sunt stocate ordine, ecare pagin a a n a frunz ind la aceeai distanta de nodul rdcin (arbore balansat). a s a a a Modul care se retine un astfel de index este reprezentat gura 3.1. n n

Figura 3.1: Reprezentarea unui index cu B-Tree 58

Aceste tip de indeci sunt ecienti la sortri i la cutarea unor intervale de date. s a s a Un exemplu de cum ar putea arta un index este cel din gura 3.2. a

Figura 3.2: Exemplu de valori indexate Tipuri de interogri care folosesc astfel de indeci sunt: a s ctri dup toate coloanele indexului aa a cutri dup doar un prex al indexului (primele coloane din index, ordinea din a a a n index) un criteriu legat de prima coloan, care s e compatibil cu indexul a a ctare dup prima coloan cu valori cuprinse a a a ntr-un interval ctare dup o valoare x din prima coloan i ceva compatibil cu indecii din a doua. a a a as s se poate s avem i index-only queries care nu acceseaz mediul de stocare a datelor. a s a ne ajut i la ORDER BY dac avem coloane care s respecte restrictiile prezentate as a a anterior dac criteriile de cutare contin 3 coloane, de ex., iar index sunt doar dou le va a a n a folosi pe primele 2. Atentie! E posibil s avem mai multi indei cu aceleai coloane dar ordine diferit. a s s n a 59

Indei bazati pe tabele de dispersie s Sunt construiti cu ajutorul tabelelor de dispersie i sunt folositi pentru cutri exacte. s a a Pentru ecare nregistrare se calculeaz un hash-code al coloanelor indexate, care va o a valoare ntreag care probabil va diferit pentru a a nregistrri cu valori diferite. a Un engine care suport astfel de indeci este MEMORY (suport chiar indei neunici). a s a s Dac mai multe valori au aceeai valoare a funtiei de dispersie vor stocate a s ntr-o list. a Sunt mai rapizi dect B-Indecii dar au limitri: a s a Trebuie neaprat citite a nregistrri din memorie. a Nu se pot folosi pentru sortri. a Nu se pot folosi pentru chei partiale (nici mcar pentru prexe). a Suport numai operatii de egalitate precum = sau IN. a Accesul e foarte rapid dac nu avem foarte multe coliziuni !!! a Unele operatii pot foarte costisitoare dac avem multe coliziuni (ex: tergerea unei a s nregistrri). a Engine-ul NDB Cluster suport hash-tables dar numai pentru valori unice. a Engine-ul InnoDB folosete adaptive hash indexes. Cnd anumite valori sunt folosite s a foarte des, si construiete un hash-index deasupra indecilor B-Tree, ceea ce permite cutri s s a a foarte rapide. Acest proces este automat i nu poate controlat sau congurat. s Un exemplu mai deosebit S presupunem c avem o coloan a a a ntr-un tabel care contine adrese web i foarte des s vrem s facem ctri dup adrese web, de genul: a aa a SELECT * FROM adrese WHERE url="http://www.mysql.com" Am dori s indexm coloana url, dar problema care apare este c dimensiunea coloanei a a a este mare, ceea ce va ngreuna att mentinerea indexului ct i toate operatiile care se vor a a s efectua asupra tabelei. Putem creea o coloan special care s retin codul CRC al coloanei url, urmnd ca a a a a a toate cutrile s le facem cu interogri de genul: a a a a SELECT * FROM adrese WHERE url_crc=CRC32("http://www.mysql.com") AND url="http://www.mysql.com"; 60

Alternativa ar fost s indexm tot irul de caractere. Evident, pot aprea coliziuni, dar a a s a aceasta nu e neaprat o problem dac nu avem index unic. a a a Mai mult, putem face un trigger, care momentul care inserm o nou n n a a nregistrare, s poat actualiza valoarea cmpului url crc. a a a BEFORE INSERT ON adrese FOR EACH NEW ROW BEGIN SET NEW.url_crc=CRC32(NEW.url) END --la fel se poate face si la BEFORE UPDATE situatii de genul acesta trebuie s analiz probabilitatea de a aprea coliziuni (la 93000 In a a a valori, probabilitatea e de 1%). Acest lucru este ilustrarea celebrei probleme Birthday Paradox : probabilitatea ca din 23 de persoane, dou s e nscute aceeai zi este de 50% iar din 75 de persoane probabilitatea a a a n s este de 99.9%. Strategii de indexare pentru performante bune Trebuie s m atenti la lucrul cu indeci deoarece pot aprea probleme neateptate: a s a s Izolarea coloanei care contine indexul -- nu se foloseste indexul SELECT x FROM y WHERE x+1<5 ... TO_DAYS(CURRENT_DATE)-TO_DAYS(date_col)<=10 -- se foloseste indexul ... date_col>=DATE_SUB(CURRENT_DAY,INTERVAL 10 DAY) Prexarea indecilor i selectivitatea lor - anumite situtii nu vrem s indexm un s s In a a ntreg cmp, ci doar un prex al lui, deoarece cmpul este foarte mare. Trebuie s m a a a atenti s avem o selectivitate sucient. a a Un dezavantaj ar c nu se mai pot folosi la ORDER BY sau GROUP BY. a anumite situatii poate avea sens s denim indeci pe suxe. Un exemplu ar dac In a s a retinem ntr-o coloan adrese de mail i vrem s facem cutri dup domeniul adresei. a s a a a a Clustered indexes - fac ca pentru un astfel de index nregistrrile s e sortate zic pe a a MySQL nu se poate selecta disc. Putem avea maxim un astfel de index pe tabel. In coloana care s e clustered index, dar alte SGBD-uri acest lucru este posibil. a n Unul din avantajele acestui tip de index este c a nregistrrile apropiate se gsesc pe a a putine pagini de memorie. 61

Atentie! Este foarte bine ca valorile care se gsesc astfel de cmpuri s nu e a n a a aleatoare (deoarece ar putea conduce la multe page split-uri. Dezavantaje: Actualizarea coloanelor indexului ar foarte costisitoare, deoarece ar trebui s se a mute nregistrri. a Poate genera page splits cnd o a nregistrare trebuie plasat a ntr-o pagin care este a deja plin. a

3.7.3

Procesarea instructiunii SELECT

Pn acum am vzut o variant simplicat a modului care se proceseaz instructiunea a a a a a n a SELECT. Totui, anumite situatii lucrurile sunt mai complicate, deoarece aceast instructiune s n a poate optimizat. a Pentru ecare interogare, MySQL ncearc s realizeze cea mai bun modalitate de exea a a cutare. Aceast munc este efectuat de o component numit query optimizer (optimizator a a a a a de interogri). Acest lucru poate realizat pe baza mai multor strategii, care au la baz: a a timpul ateptat de executie s numrul de a nregistrri a prezenta sau nu a indecilor s De exemplu, pentru a aa studentul cu numrul matricol 100, strategia general s-ar s a n a parcurge urmtorii pai: a s result:=[]; FOR EACH s IN studenti DO IF s.nrmatricol=100 THEN result+=s; ENDFOR; Dac am avea strategia optimizat, pe baza de indeci, instructiunea s-ar putea rezolva a a s astfel: result:=[]; FOR EACH s IN studenti WHERE s.nrmatricol =100 DO result+=s; ENDFOR; Dac, de exemplu, am vrea s vedem studentii din Braov, care au numrul matricol < a a s a 10 am avea urmtoarea interogare: a 62

SELECT FROM studenti WHERE nrmatricol < 10 AND oras="Brasov"; Prezentm, continuare schemele pentru strategia general i pentru strategia optia n a s mizat: a result:=[]; FOR EACH s IN studenti DO IF (s.nrmatricol<10) AND (s.oras="Brasov") DO result+=s; ENDFOR; --------------------------------------------------result:=[]; FOR EACH s IN studenti WHERE nrmatricol<10 DO IF s.oras="Brasov" DO result+=s; ENDFOR;

3.7.4

Crearea indecilor s

Sintaxa pentru crearea unui index este urmtoarea: a CREATE [UNIQUE|FULLTEXT|SPATIAL] INDEX index_name [index_type] ON tbl_name (index_col_name,...) index_col_name: col_name [(length)] [ASC | DESC] index_type: USING BTREE | HASH Prezentm, continuare cteva exemple de creare a indecilor: a n a s S se creeze un index hash pentru oraul studentilor: a s CREATE INDEX stud_oras USING HASH ON studenti(oras); S se creeze un index unic pe nume, pe tabela studenti: a CREATE UNIQUE INDEX nume_stud ON studenti(nume); 63

momentul care adugm un index la o tabel, In n a a a nregistrrile din acea tabel trebuie a a s respecte conditiile legate de index, altfel crearea nu reuete. a s s Automat, cnd se creeaz o cheie primar sau alternativ se creeaz un index pentru a a a a a ea. Indexul va purta numele de PRIMARY dac este pentru o cheie primar i respectiv a as numele primei coloane pentru care este fcut dac este vorba de o cheie alternativ. a a a Indecii pot alterati folosind instructiunea ALTER TABLE, ca exemplele urmtoare: s n a S se adauge la tabela studenti un index pe coloana nume a ALTER TABLE studenti ADD INDEX stud_nume USING BTREE (nume); S se adauge un index unic functie de nume i prenume pe tabela studenti: a n s ALTER TABLE studenti ADD UNIQUE INDEX stud_nume_pren USING HASH (nume, prenume);

3.7.5

Denirea indecilor s mpreun cu tabela a

Pentru a crea un index se poate folosi oricare din urmtoarele trei metode: a instructiunea CREATE INDEX instructiunea ALTER TABLE instructiunea CREATE TABLE Prezentm, continuare dou exemple care crearea indecilor se face cadrul instructiunii a n a n s n CREATE TABLE: S se creeze tabela studenti, indexndu-se dup cmpul nume tabela. a a a a CREATE TABLE studenti ( ..... INDEX stud_nume(nume) ) S se creeze tabela studenti i un index unic dup nume i prenume care s foloseasc a s a s a a un hash-index: CREATE TABLE studenti ( ....... UNIQUE INDEX stud_nume_pren USING HASH (nume, prenume) ); 64

3.7.6

Stergerea indecilor s

Pentru a se terge un index dintr-o tabel se folosete interogarea DROP INDEX care s a s are sintaxa: DROP INDEX index_name ON tbl_name Un index se poate terge i folosind interogarea ALTER TABLE. s s

3.7.7

Alegerea coloanelor pentru indeci s

Pentru ca SELECT-urile s se fac cel mai rapid posibil toate cazurile ideal ar s a a n a facem cte un index pe ecare coloan. Totui acest lucru nu este posibil datorit modului a a s a care se lucreaz cu indeci. n a s Recomandabil este s avem index pentru: a cheile primare (se face automat) i pentru cheile candidat. s pentru cheile strine, deoarece felul acesta operatiile de JOIN se vor face mai repede. a n Relativ la efectul indecilor, trebuie remarcate urmtoarele lucruri: s a Cu ct tabela contine mai multe a nregistrri cu att e mai mare efectul indecilor. a a s Cu ct valorile a nregistrrilor sunt mai variate, cu att e mai util indexul. a a Dac pentru valoarea cutat sunt foarte putine a a a nregistrri care o respect, indexul a a este mai ecient. Alegerea indecilor ajut foarte mult la sortarea s a nregistrrilor dintr-o tabel, la folosirea a a lui DISTINCT i la GROUP BY. s

3.8

Optimizarea performantei interogrilor a

Una din principalele probleme cnd scriem interogri ineciente este c interogrile noasa a a a tre acceseaz prea multe date (prea multe a nregistrri sau prea multe coloane sau MySQL a trebuie s analizeze prea multe a nregistrri). a Cteva greeli comune sunt: a s Sunt aduse toate datele din care sunt apoi preluate aplicatie doar cteva n a nregistrri. a Totui, MySQL pentru acest lucru a trebuit s creeze un s a ntreg result-set, care apoi a fost trimis la utilizator prin retea. Vrem s vedem toate informatiile despre studentii care s-au a nrolat la vreun curs: 65

-- GRESIT SELECT * FROM studenti s INNER JOIN inrolari i USING (nrmatricol) -- CORECT SELECT s.* FROM studenti s INNER JOIN inrolari i USING (nrmatricol) Trebuie s m atenti cnd executm interogri de tipul SELECT * FROM ..., deoarece a a a a cel mai adesea nu avem nevoie de toate coloanele. Dup ce ne-am asigurat c MySQL ne aduce exact datele de care avem nevoie, ar bine a a s ne gndim dac nu cumva modul de lucru al MySQL nu este inecient. Putem msura a a a a mai multe lucruri, precum: Timpul de executie Numrul de a nregistrri examinate a Numrul de a nregistrri returnate. a Timpul de executie ne poate spune cam care sunt locurile din aplicatie care se pierde n cel mai mult timp. Totui, aceasta nu este neaprat un indicator pentru faptul c interogarea s a a este ecient sau nu, deoarece nu ine cont de complexitatea problemei. a t Ideal ar ca numrul de a nregistrri returnate s e ct mai aproape de numrul de a a a a nregistrri examinate, dar foarte des acest lucru nu este posibil. a principiu, MySQL poate trata o clauza WHERE mai multe moduri: In n Folosete indexul pentru a obtine s nregistrarea dorit. a Folosete covering indexes pentru a nu accesa datele din tabele. s Ia toate datele din tabele, dup care dup o scanare, alege doar a a nregistrrile care se a potrivesc. Se pot folosi mai multe moduri de a restructura interogrile: a E mai bine s avem interogri complexe sau mai multe interogri simple? anii a a a In trecuti se considera ca ind foarte important ca s facem ct mai putin trac pe retea. a a Acest lucru e valabil i acum, dar din ce ce mai putin. Totui, este de preferat s s n s a facem un anumit lucru din putini pai. s Cteodat e mai bine s artim o interogare cu foarte multe operatii mai multe a a a mp n alte subinterogri, ecare cu mai putine operatii: a 66

--initial DELETE FROM messages WHERE created < DATE_SUB(NOW( ),INTERVAL 3 MONTH); --intr-un program rows_affected = 0 do { rows_affected = do_query( "DELETE FROM messages WHERE created < DATE_SUB(NOW( ),INTERVAL 3 MONTH) LIMIT 10000") } while rows_affected > 0 Este bine s folosim anumite situatii ceea ce poart numele de join decomposition: a n a --initial SELECT * FROM tag JOIN tag_post ON tag_post.tag_id=tag.id JOIN post ON tag_post.post_id=post.id WHERE tag.tag=mysql; --ulterior SELECT * FROM tag WHERE tag=mysql; SELECT * FROM tag_post WHERE tag_id=1234; SELECT * FROM post WHERE post.id in (123,456,567,9098,8904); Aceast abordare poate avea mai multe avantaje: a Se poate face caching mult mai ecient. Se blocheaz ecare tabel pentru perioade mai scurte, dect s e toate tabelele a a a blocate pentru mai mult timp. Se poate distribui mult mai uor baza de date pe mai multe calculatoare. s Folosirea lui IN permite MySQL s sorteze id-urile mai ecient, ceea ce ulterior a permite regsirea mai uoar a datelor. a s a Datele sunt folosite accesate numai o dat dac se face join-ul la nivelul aplicatiei, a a dar de mai multe ori dac se face la nivelul serverului de baze de date. a

3.8.1

Lucruri de baz relativ la executia interogrilor a a

Cnd trimitem o interogare la un server se parcurg urmtorii pai: a a s 1. Clientul trimite interogarea SQL la server. 67

2. Serverul veric dac nu cumva cache nu are deja salvate datele. a a n 3. Serverul parseaz, preproceseaz i optimizeaz interogarea SQL a as a ntr-un query execution plan. 4. Query execution engine-ul execut planul fcnd apel la storage engine. a a a 5. Serverul trimite napoi rezultatul la client. O interogare poate una din urmtoarele stri (se poate vedea cu SHOW FULL n a a PROCESSLIST): Sleep, Query, Locked, Analyzing and statistics, Copying to tmp table [on disk], Sorting result, Sending data. O component foarte important este optimizatorul de interogri. Acesta a a a ncearc s a a prezic costuri pentru diverse planuri de execuctie i s-l aleag pe cel mai bun. a s a a Unitatea de cost este citirea unei pagini aleatoare de date de 4KB. Se poate vedea costul unei interogri astfel: a SELECT SQL_NO_CACHE oras, COUNT(*) FROM studenti GROUP BY oras SHOW STATUS LIKE last_query_cost Exist dou tipuri de optimizri: a a a optimizri statice - sunt optimizri care se parcurg pe arborele parsat. Pot gndite a a a ca nite optimizri la compilare (se bazeaz pe reguli algebrice care ecientizeaz ins a a a terogrile) i se vor face la fel a s ntotdeauna cnd se va executa interogarea. a optimizri dinamice - optimizri la momentul rulrii care pot depinde de valoarea a a a cutat sau de numrul de a a a nregistrri din index, etc. a Optimizatorul de interogri poate face optimizri precum: a a Reordonarea join-urilor (poate foarte important) a Convertirea OUTER JOIN-urilor INNER JOIN-uri ( anumite situatii cnd acest n n a lucru este posibil) Aplicarea de reguli algebrice echivalente Optimizri pentru COUNT, MIN, MAX a Evaluarea i reducerea expresiilor constante s Optimizri ale subinterogrilor a a 68

3.9

Utilizarea view-urilor

principiu, MySQL exist dou tipuri de tabele: In n a a tabele reale - sunt create cu CREATE TABLE i ele stocheaz date propriu-zise. s a virtuale (derivate sau vederi) - care nu stocheaz nici o a nregistrare ci doar anumite interogri. Ele exist doar cnd sunt folosite interogri. a a a n a

3.9.1

Crearea de view-uri

Pentru crearea view-urilor se folosete urmtoarea sintax: s a a CREATE [OR REPLACE] [ALGORITHM = UNDEFINED | MERGE | TEMPTABLE] [DEFINER = user | CURRENT_USER ] [SQL SECURITY DEFINER | INVOKER ] VIEW view_name [(column_list)] AS select_statement [WITH [CASCADED | LOCAL] CHECK OPTION] Exemplu: S se creeze un view care returneaz toate oraele distincte din tabela studenti. a a s S se foloseasc acest view a a ntr-o interogare: CREATE VIEW view_orase AS SELECT DISTINCT oras FROM studenti; SELECT * FROM view_orase WHERE oras LIKE B%; Dup cum se poate uor observa, un view poate interogat la fel ca orice alt tabel. a s a a Mai mult, orice schimbare care apare tabela de baz se reect imediat i view. n a a s n Se poate ca la denirea unui view s se foloseasc un alt view ca exemplul urmtor: a a n a CREATE VIEW view_orase_b AS SELECT * FROM view_orase WHERE oras LIKE B%; Dac se dorete ca view-ul s e creat dac nu exist deja sau s e a s a a a a nlocuit dac deja a exist, se poate folosi CREATE OR REPLACE: a 69

CREATE OR REPLACE VIEW view_orase_b AS SELECT * FROM view_orase WHERE oras LIKE B%; mod implicit, un view motenete numele coloanelor din care si ia datele. Dac se In s s a dorete altceva, se poate face acest lucru. s Exemplu: CREATE VIEW view_studenti (numele, prenumele) AS SELECT nume, prenume FROM studenti; Datele dintr-un view pot actualizate de ctre cel care-l folosete. Acest lucru a s nseamn a c se pot face interogri de tipul INSERT, UPDATE i DELETE pe un view. a a s

3.9.2

Optiuni ale view-urilor

Uneori se poate ampla, ca urma interogrii s se modice continutul tabelului i nt n a a s totui view-ul s nu reecte acest lucru. Este cazul dac inserm o s a a a nregistrare care mod n normal nu ar aprut in view-ul initial, pentru c acesta avea o clauz WHERE care o a a a excludea. Dac vrem s evitm astfel de situatii, putem folosi optiunea WITH CHECK. a a a Iat i un exemplu: as CREATE VIEW view_studenti AS SELECT * FROM studenti WHERE oras=Brasov WITH CHECK OPTION; Dac un view contine WITH CHECK atunci: a UPDATE-ul nu reuete dect dac, urma modicrilor, s s a a n a nregistrarea ramne a n view. INSERT-ul nu reuete dect dac, s s a a nregistrarea care s-ar aduga se regsete view. a a s n DELETE-ul terge doar s nregistrrile din view. a Implicit avem WITH CASCADED CHECK OPTION, ceea ce nseamn c se veric a a a conditiile i pentru view-uri imbricate. s Dac s-ar folosi WITH LOCAL CHECK OPTION atunci nu s-ar verica dect conditiile a a din view-ul curent. mod implicit se consider c utilizatorul curent este cel care a denit view-ul. Dac In a a a se dorete schimbarea acestui lucru, se poate folosi optiunea DEFINER: s 70

CREATE DEFINER=mihai@localhost VIEW view_studenti_b AS SELECT * FROM studenti WHERE nrmatricol<100; Cel care denete view-ul trebuie s aib drept de SELECT pe tabela (tabelele) pe care s a a actioneaz view-ul. Cei care-l folosesc nu trebuie s respecte acest lucru. Acest lucru se a a ampl dac optiunea SQL SECURITY este setat la SQL SECURITY DEFINER. nt a a a Dac optiunea are valoarea SQL SECURITY INVOKER atunci cel care actioneaz viewa a ul trebuie s aib drepturile necesare pentru tabelele pe care le acceseaz. a a a Pentru un view se mai poate specica i algoritmul care s e folosit la evaluarea views a ului: MERGE - instructiunea SELECT care apeleaz view-ul este combinat cu textul lui a a pentru a se obtine interogarea care trebuie efectuat. a TEMPTABLE - se execut ai formula view-ului, iar apoi, pe datele dintr-un tabel a nt temporar se execut noua interogare. a UNDEFINED - MySQL determin singur ce metod va aplicat (este varianta ima a a plicit). a Dei nu vom detalia cele ce urmeaz, toate aceste optiuni pot modicate folosind s n a instructiunea ALTER VIEW...

3.9.3

Stergerea view-urilor

Pentru a terge un view, se folosete instructiunea DROP VIEW cu sintaxa: s s DROP VIEW [IF EXISTS] view_name [, view_name] ... [RESTRICT | CASCADE] Cnd se terge un view, automat se terg toate cele dependente de el. mod asemntor, a s s In a a cnd se terge o tabel se terg toate view-urile dependente de ea. a s a s

3.9.4

Restrictii referitoare la actualizarea view-urilor

Un view poate actualizat numai dac exist o relatie de la 1 la 1 fata de tabela de baz a a a implicat. a Trebuie respectate mai multe conditii: SELECT-ul nu poate contine DISTINCT SELECT-ul nu poate contine functii agregate SELECT-ul nu poate contine mai mult de o tabel a 71

SELECT-ul nu poate contine subinterogri corelate a SELECT-ul nu poate contine clauza GROUP BY, HAVING, ORDER BY sau operatii pentru lucrul cu multimi O coloan virtual (calculat) nu poate actualizat a a a a SELECT-ul trebuie s contin toate coloanele care au clauza NOT NULL tabela de a a n baz. a

3.9.5

De ce sa folosim view-urile?

Exist mai multe motive pentru care se folosesc: a Simplicarea unor rutine complexe Reorganizarea tabelelor Dezvoltarea pas cu pas a interogrilor SELECT a Specicarea constrngerilor de integritate - prin folosirea lui WITH CHECK a O mai buna securitate a datelor - pot folosite pentru a proteja de anumiti utilizatori anumite prti ale tabelelor. a

72

Capitolul 4 Crearea obiectelor procedurale


Pn anii 1986-1987 SQL era un limbaj pur declarativ. Totui, acei ani au a a n s n nceput s apar procedurile stocate. a a O procedur stocat const a a a ntr-o bucat de cod care se salveaz pe serverul de baze de a a date ntr-o form precompilat. Ea poate contine mai multe instructiuni SELECT, INSERT a a precum i structuri conditionale i repetitive (IF THEN ELSE, WHILE DO). s s Ulterior, au aprut i alte tipuri de constructii precum: functiile stocate, triggere-le i a s s event-urile.

4.1

Proceduri stocate

O procedur stocat reprezint o bucat de cod care contine instructiuni declarative i a a a a s procedurale stocate ntr-o baz de date. Ele pot folosite din interiorul altor proceduri a stocate, triggere, altor programe sau chiar din aplicatii client MySQL. Iat un exemplu de procedur stocat care terge din tabela studenti un student cu un a a a s numr matricol specicat ca parametru de intrare (IN): a DELIMITER $$ DROP PROCEDURE IF EXISTS mydatabase.delete_student $$ CREATE PROCEDURE mydatabase.delete_student (IN nrmat INTEGER) BEGIN DELETE FROM studenti WHERE nrmatricol=nrmat; END $$ DELIMITER ; Dup cum se poate vedea, o procedur stocat are 3 prti: a a a a un nume ( cazul nostru delete student) n 73

nite parametri (nrmatricol) s un corp al procedurii stocate Apelarea instuctiunii CREATE PROCEDURE de mai sus nu conduce la rularea instuctiunii DELETE, ci la retinerea procedurii memorie i o vericare partial a ei. Pentru a putea n s a rula procedura stocat trebuie folosit instructiunea CALL: a a CALL delete_student(100);

4.1.1

Transmiterea parametrilor

Parametrii unei proceduri stocate pot de 3 feluri: parametri de intrare - se folosete cuvntul cheie IN la specicarea lor s a parametri de ieire - OUT s parametrii i de intrare i de ieire - INOUT s s s Observatie: Dac o procedur stocat nu are parametri, atunci trebuie totui s folosim a a a s a paranteze rotunde goale locul care ar trebuit s e lista de parametri. n n a Numele parametrului trebuie s e diferit de numele coloanelor. Dac ar la fel, MySQL a a ar bnui c de fapt ambele locuri care folosim avem nume de coloane. a a n n l

4.1.2

Corpul procedurilor stocate

Corpul procedurii stocate contine ntre cuvintele cheie BEGIN i END mai multe instructiuni s care pot procedurale sau declarative, precum i eventuale declaratii de variabile. s La fel ca orice limbaj de programare mai multe instructiuni pot grupate n ntr-o instructiune compus prin BEGIN...END. a Fiecare bloc BEGIN...END trebuie s se termine cu ;. Exceptie face corpul procedurii a stocate.

4.1.3

Variabile locale i variabile utilizator s

MySQL, pentru a putea folosi o variabil trebuie s o declarm In a a a nainte. Prezentm, a continuare cteva exemple: n a DECLARE var1 DECIMAL(4,2); DECLARE var2 INTEGER; DECLARE var3 INTEGER DEFAULT 0; 74

Instructiunile DECLARE VARIABLE trebuie s e primele instructiuni din cadrul unui a bloc BEGIN...END. Evident, o variabil local exist doar sectiunea BEGIN...END care este declarat. a a a n n a Variabilele utilizator sunt acele variabile care sunt denite de utilizator i au o vizibilitate s la nivel de sesiune. Denumirea lor ncepe cu caracterul @. Prezentm dou exemple de proceduri stocate care folosesc att variabile locale ct i a a a a s utilizator: S se scrie o procedur stocat care primete ca parametru un numr i returneaz a a a s a s a n cel de-al doilea numrul imediat urmtor: a a DELIMITER $$ DROP PROCEDURE IF EXISTS mydatabase.next_value $$ CREATE PROCEDURE mydatabase.next_value (IN nr1 INTEGER, OUT nr2 INTEGER) BEGIN DECLARE t INTEGER DEFAULT nr1+1; SET nr2 = t; END $$ DELIMITER ; Pentru a verica procedura stocat, se pot rula urmtoarele instructiuni din linie de a a comand: a SET @x=3; CALL next_value(@x, @y); SELECT @y; S se scrie o procedur stocat care returneaz numrul de a a a a a nregistrri din tabela a studenti. DELIMITER $$ DROP PROCEDURE IF EXISTS mydatabase.nrstudenti $$ CREATE PROCEDURE mydatabase.nrstudenti (OUT nr INTEGER) BEGIN SET nr = (SELECT COUNT(*) FROM studenti); END $$ DELIMITER ; Se poate ncerca prin urmtoarele instructiuni: a 75

CALL nrstudenti(@nrs); SELECT @nrs; Pentru atribuirea de valori unei variabile se folosete instructiunea SET (att pentru s a variabile locale ct i pentru cele utilizator). a s

4.1.4

Structuri de control

continuare vom prezenta structurile de control care pot folosite procedurile stocate, In n prin intermediul unor exemple: S se scrie o procedur stocat care s primeasc ca parametri 3 numere i s returneze a a a a a s a al 4-lea parametru maximul dintre cele 3 numere: n DELIMITER $$ DROP PROCEDURE IF EXISTS mydatabase.max3nr $$ CREATE PROCEDURE mydatabase.max3nr ( IN x INTEGER, IN y INTEGER, IN z INTEGER, OUT rez INTEGER) BEGIN IF x>=y AND x>=z THEN SET rez=x; ELSEIF y>=z THEN SET rez=y; ELSE SET rez=z; END IF; END $$ DELIMITER ; Se apeleaz astfel: a SET @x=3, @y=20, @z=4; CALL max3nr(@x, @y, @z, @max); SELECT @max; S se scrie o procedur stocat care calculeaz suma cifrelor unui numr transmis ca a a a a a parametru de intrare i pune rezultatul s ntr-un parametru de ieire: s DELIMITER $$

76

DROP PROCEDURE IF EXISTS mydatabase.suma_cifre $$ CREATE PROCEDURE mydatabase.suma_cifre (IN x INTEGER, OUT rez INTEGER) BEGIN DECLARE suma INT DEFAULT 0; WHILE x>0 DO SET suma=suma+x MOD 10; SET x=x DIV 10; END WHILE; SET rez=suma; END $$ DELIMITER ; Se apeleaz astfel: a CALL suma_cifre(342, @x); SELECT @x; S se construiasc o procedur stocat care primete ca parametru un numr i rea a a a s a s turneaz al doilea numrul de numere prime mai mici sau egale dect acel numr. a n a a a DELIMITER $$ DROP PROCEDURE IF EXISTS mydatabase.prime $$ CREATE PROCEDURE mydatabase.prime (IN n INTEGER, OUT k INTEGER) BEGIN DECLARE i INTEGER DEFAULT 2; DECLARE ok INTEGER; declare j INTEGER; SET k=0; prime_loop: LOOP IF i>n THEN LEAVE prime_loop; END IF; SET ok=1; SET j=2;

77

prim: LOOP IF j > i/2 THEN LEAVE prim; END IF; IF i MOD j=0 THEN SET ok=0; LEAVE prim; END IF; SET j=j+1; END LOOP prim; IF ok=1 THEN SET k=k+1; END IF; SET i=i+1; END LOOP prime_loop; END $$ DELIMITER ; Observatie: Aa cum LEAVE este corespondentul din limbajele de programare al lui s BREAK, ITERATE este corespondentul lui CONTINUE. Se apeleaz astfel: a CALL prime(10, @k); SELECT @k;

4.1.5

Apelarea procedurilor stocate

Sintaxa pentru apelarea unei proceduri stocate este urmtoarea: a CALL sp_name([parameter[,...]]) CALL sp_name[()] Trebuie inut cont de anumite reguli: t Numrul de parametri efectivi trebuie s e egal cu numrul de parametri formal (cel a a a folosit la crearea procedurii stocate). Dac se apeleaz procedura stocat folosind numele unei baze de date, atunci pentru a a a tabelele care n-au specicat explicit o baz de date se folosete acea baz de date. a a s a Evident se poate transmite ca parametru orice valoare scalar. Aceasta este calculat a a nainte de a transmis procedurii stocate. a 78

Se poate chiar s apelm o procedur stocat ca exemplul: a a a a n CALL prime((SELECT COUNT(*) FROM studenti), @k); Se poate chiar s avem apeluri recursive ale procedurilor stocate. a Exercitiu: S se construiasc o procedur stocat care s foloseasc recursivitatea. a a a a a a

4.1.6

Interogarea datelor cu SELECT INTO

Aceast interogare face ca o singur a a nregistrare dintr-o tabel s e retinut a a a ntr-o variabil. a Sintaxa noi instructiuni este: SELECT [ALL | DISTINCT | DISTINCTROW ] [HIGH_PRIORITY] [STRAIGHT_JOIN] [SQL_SMALL_RESULT] [SQL_BIG_RESULT] [SQL_BUFFER_RESULT] [SQL_CACHE | SQL_NO_CACHE] [SQL_CALC_FOUND_ROWS] select_expr [, select_expr ...] [FROM table_references [WHERE where_condition] [GROUP BY col_name | expr | position [ASC | DESC], ... [WITH ROLLUP]] [HAVING where_condition] [ORDER BY col_name | expr | position [ASC | DESC], ...] [LIMIT [offset,] row_count | row_count OFFSET offset] [PROCEDURE procedure_name(argument_list)] [INTO OUTFILE file_name export_options | INTO DUMPFILE file_name | INTO var_name [, var_name]] [FOR UPDATE | LOCK IN SHARE MODE]] Iat i un exemplu: as DELIMITER $$ DROP PROCEDURE IF EXISTS mydatabase.studenti_oras $$ CREATE PROCEDURE mydatabase.studenti_oras (IN oras_in CHAR(50), OUT nr INTEGER) BEGIN SELECT COUNT(*) FROM studenti WHERE oras=oras_in 79

INTO nr; END $$ DELIMITER ; Se poate ca folosind SELECT INTO s atribuim mai multe valori acelai timp (dou a n s a instructiuni SET): SELECT oras, judet FROM studenti WHERE nrmatricol=100 INTO rez_oras, rez_judet

4.1.7

Mesaje de eroare, handlere i conditii s

Toate erorile din MySQL au un numr i o descriere, i mai mult mai multe erori sunt a s s grupate ntr-un alt cod numit SQLSTATE. De exemplu, pentru codul SQLSTATE 23000 putem avea mai multe tipuri de erori: eroarea 1022 - cheie duplicat a eroarea 1048 - coloana nu poate avea valoarea NULL eroarea 1052 - coloan ambigu a a mod normal, momentul care apare o eroare, procedura stocat se In n n a ntrerupe. Cu o versiune special a lui DECLARE se poate ca totui acest lucru s nu se ample. a s a nt Sintaxa acestei constructii este urmtoarea: a DECLARE handler_type HANDLER FOR condition_value [, condition_value] ... statement handler_type: CONTINUE | EXIT | UNDO condition_value: SQLSTATE [VALUE] sqlstate_value | condition_name | SQLWARNING | NOT FOUND | SQLEXCEPTION | mysql_error_code 80

Iat i un exemplu: as CREATE PROCEDURE error_1 (OUT ERROR CHAR(5)) BEGIN DECLARE CONTINUE HANDLER FOR SQLSTATE 23000 SET ERROR = 23000; SET ERROR = 00000; INSERT INTO tipuri_curs VALUES (2,tip nou); END exemplul de mai sus se stabilete c, dac apare o eroare de tipul 23000, variabila In s a a error primete o anumit valoare. s a Se pot declara i handlere pentru erori de tipul: s DECLARE CONTINUE HANDLER FOR 1062 SET ERROR = 23000; DECLARE CONTINUE HANDLER FOR 1136 SET ERROR = 21S01; Se pot trata i erori mai generale ca exemplul urmtor: s n a CREATE PROCEDURE another_error (OUT ERROR CHAR(5)) BEGIN DECLARE CONTINUE HANDLER FOR SQLWARNING, NOT FOUND, SQLEXCEPTION SET ERROR = XXXXX; SET ERROR = 00000; INSERT INTO tipuri_curs VALUES (2,another option); END SQLWARNING se folosete pentru erori al cror cod s a ncepe cu 01, NOT FOUND pentru erori al cror cod a ncepe cu 02 iar SQLEXCEPTION pentru erori al cror cod a ncepe cu altceva. Se poate ca s dm nume mai semnicative anumitor erori, pentru a le putea folosi a a ulterior procedura stocat: n a CREATE PROCEDURE another_error (OUT ERROR CHAR(5)) BEGIN DECLARE NON_UNIQUE CONDITION FOR SQLSTATE 23000; DECLARE CONTINUE HANDLER FOR NON_UNIQUE SET ERROR = 23000; SET ERROR = 00000; INSERT INTO tipuri_curs VALUES (2,another option); END S-a folosit aici DECLARE...CONDITION..., care are sintaxa: 81

DECLARE condition_name CONDITION FOR condition_value condition_value: SQLSTATE [VALUE] sqlstate_value | mysql_error_code Trebuie fcute mai multe observatii: a Handlerele si conditiile pot denite la nceputul unui bloc BEGIN...END i sunt s valabile acel bloc i toate subblocurile. n s n Nu se poate ca exact acelai bloc s se redeneasc un handler. n s a a Handlerul poate redenit ntr-un sub-bloc. Cnd apare o eroare, se caut un handler potrivit blocul curent, dup aceea blocul a a n a n imediat superior i tot aa, pn cnd se gsete unul care eroarea e tratat. s s a a a a s n a

4.1.8

Folosirea cursoarelor

Cursoarele au fost create pentru a trata acele SELECT-uri care pot returna mai mult de o nregistrare (spre diferenta de SELECT...INTO... care poate trata doar cazul cnd se a returneaz o singur a a nregistrare). Exist 4 instructiuni pentru lucrul cu cursoare: DECLARE CURSOR, OPEN CURSOR, a FETCH CURSOR i CLOSE CURSOR. s Aceste instructiuni au urmtoarele semnicatii: a DECLARE CURSOR - permite declararea unui cursor i stabilirea tabelei pe care se s aplic a OPEN CURSOR - deschiderea unui cursor, o singur dat la a a nceput FETCH CURSOR - permite retinerea datelor din nregistrarea curent i trecerea la as nregistrarea urmtoare a CLOSE CURSOR - nchiderea cursorului Ele au urmtoarea sintax: a a DECLARE cursor_name CURSOR FOR select_statement OPEN cursor_name FETCH cursor_name INTO var_name [, var_name] ... CLOSE cursor_name 82

Iat cum s-ar putea numra a a nregistrrile dintr-o tabel folosind cursoare: a a DELIMITER $$ DROP PROCEDURE IF EXISTS mydatabase.students_number $$ CREATE PROCEDURE mydatabase.students_number (OUT number INTEGER) BEGIN DECLARE nrmatr INTEGER; DECLARE found BOOLEAN DEFAULT TRUE; DECLARE studenti_cursor CURSOR FOR SELECT nrmatricol FROM studenti; DECLARE CONTINUE HANDLER FOR NOT FOUND SET FOUND = FALSE; SET number = 0; OPEN studenti_cursor; FETCH studenti_cursor INTO nrmatr; WHILE FOUND DO SET number = number + 1; FETCH studenti_cursor INTO nrmatr; END WHILE; CLOSE studenti_cursor; END $$ DELIMITER ; S se scrie o procedur stocat care terge toate a a a s nregistrrile din tabela studenti care a nu au corespondent tabela inrolari: n DELIMITER $$ DROP PROCEDURE IF EXISTS mydatabase.delete_students $$ CREATE PROCEDURE mydatabase.delete_students() BEGIN DECLARE nrmatr INTEGER; DECLARE found BOOLEAN DEFAULT TRUE; DECLARE studenti_cursor CURSOR FOR SELECT nrmatricol FROM studenti; 83

DECLARE CONTINUE HANDLER FOR NOT FOUND SET FOUND = FALSE; OPEN studenti_cursor; FETCH studenti_cursor INTO nrmatr; WHILE FOUND DO IF (SELECT COUNT(*) FROM inrolari WHERE nrmatricol=nrmatr) =0 THEN DELETE FROM studenti WHERE nrmatricol=nrmatr; END IF; FETCH studenti_cursor INTO nrmatr; END WHILE; CLOSE studenti_cursor; END $$ DELIMITER ;

4.1.9

Specicarea anumitor caracteristici ale procedurilor stocate

Se pot specica caracteristici ale procedurilor stocate ntre parametri transmii i corpul s s procedurii stocate. Dac specicm NO SQL aceasta spune lui MySQL c acea procedur stocat nu a a n a n a a folosim instructiuni SQL (nu se acceseaza baza de date). a CREATE [DEFINER = user | CURRENT_USER ] PROCEDURE sp_name ([proc_parameter[,...]]) [characteristic ...] routine_body proc_parameter: [ IN | OUT | INOUT ] param_name type type: Any valid MySQL data type characteristic: LANGUAGE SQL | [NOT] DETERMINISTIC | CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA | SQL SECURITY DEFINER | INVOKER 84

| COMMENT string routine_body: Valid SQL procedure statement exemple: CREATE DEFINER = mihai@% PROCEDURE test() (OUT var INTEGER) BEGIN SET VAR1 = 10; END

4.1.10

Stergerea procedurilor stocate

Stergerea procedurilor stocate se face cu ajutorul comenzii DROP PROCEDURE cu sintaxa: DROP PROCEDURE | FUNCTION [IF EXISTS] sp_name Iat i un exemplu: as DROP PROCEDURE IF EXISTS mydatabase.studenti_oras;

4.1.11

Securitatea procedurilor stocate

Pentru a putea executa o procedur stocat un utilizator trebuie s aib drept de EXEa a a a CUTE asupra ei. Acesta se poate acorda astfel: GRANT EXECUTE ON PROCEDURE my_proc TO mihai; Utilizatorul care are drept de a executa o anumit procedur nu trebuie s aib drepturi i a a a a s asupra tabelelor folosite din procedura stocat. Totui, alte sisteme de gestiune a bazelor a s n de date se poate ampla ca acest lucru s e necesar. nt a

4.1.12

Avantaje ale procedurilor stocate

Principalele avantaje ale utilizrii procedurilor stocate sunt: a Mentenanta mai uoar a codului - Dac avem o procedur stocat care numr cti s a a a a aa a descendenti are un nod dintr-un arbore, nu trebuie s schimbm codul programului a a dac structura tabelei se schimb. a a 85

Minimizarea tracului n retea - Nu se execut ecare interogare separat, ci toate a interogrile se execut i apoi se transmite rezultatul ctre programul apelant. a as a Evitarea duplicrii codului - Dac aceeai baz de date se folosete mai multe a a s a s n aplicatii, nu trebuie duplicat codul pentru ecare limbaj parte. Putem scrie cod n care s e partajat a ntre aceste aplicatii.

4.2

Functii stocate

Functiile stocate seamn foarte mult cu procedurile stocate dar exist i cteva diferente a a as a importante: O functie stocat poate avea parametri de intrare, dar nu poate avea parametri de a ieire. Functia ai este parametru de ieire. s nss s Ele nu se apeleaz folosind instructiunea CALL, ci la fel ca orice functie scalar. a a Ele trebuie s conctin o instructiune RETURN, care nu poate folosit cazul a a a n procedurilor stocate. Sintaxa denirii unei functii stocate este urmtoarea: a CREATE [DEFINER = user | CURRENT_USER ] FUNCTION sp_name ([func_parameter[,...]]) RETURNS type [characteristic ...] routine_body func_parameter: param_name type type: Any valid MySQL data type characteristic: LANGUAGE SQL | [NOT] DETERMINISTIC | CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA | SQL SECURITY DEFINER | INVOKER | COMMENT string routine_body: Valid SQL procedure statement Prezentm, continuare, cteva exemple de functii stocate: a n a 86

S se scrie o functie care calculeaz maximul dintre dou numere. a a a DELIMITER $$ DROP FUNCTION IF EXISTS mydatabase.maxim $$ CREATE FUNCTION mydatabase.maxim (x int, y int) RETURNS INT BEGIN IF x>=y THEN RETURN x; ELSE RETURN y; END IF; END $$ DELIMITER ; Functia se apeleaz astfel: a SELECT maxim(4,10); S se scrie o functie care returneaz numrul de studenti dintr-un anumit ora. a a a s DELIMITER $$ DROP FUNCTION IF EXISTS mydatabase.studenti_oras $$ CREATE FUNCTION mydatabase.studenti_oras (orass char(30)) RETURNS INT BEGIN RETURN (SELECT COUNT(*) FROM studenti WHERE oras=orass); END $$ DELIMITER ; Functia se apeleaz astfel: a SELECT studenti_oras(Brasov); O functie care calculeaz numrul de zile a a ntre dou date: a DELIMITER $$ DROP FUNCTION IF EXISTS mydatabase.studenti_oras $$ CREATE FUNCTION mydatabase.number_of_days (start_date DATE,end_date DATE) 87

RETURNS INTEGER BEGIN DECLARE days INTEGER; DECLARE next_date, previous_date DATE; SET days = 0; SET next_date = start_date + INTERVAL 1 DAY; WHILE next_date <= end_date DO SET days = days + 1; SET previous_date = next_date; SET next_date = next_date + INTERVAL 1 DAY; END WHILE; RETURN days; END$$ DELIMITER ; Trebuie fcute cteva observatii: a a Functiile stocate pot apela la rndul lor alte functii sau proceduri stocate. a Se pot construi functii stocate recursive. Pentru o functie stocat se poate specica un dener i diverse caracteristici la fel ca a s i pentru o procedur stocat. s a a Se poate modica o functie stocat folosind instructiunea ALTER FUNCTION. a Acordarea de privilegii se poate face la fel ca cazul procedurilor stocate. n Stergerea unei functii se poate face folosind instructiunea DROP FUNCTION cu sin taxa: DROP PROCEDURE | FUNCTION [IF EXISTS] sp_name

4.3

Triggere

Dup cum am putut vedea pn acum, un server de baze de date este pasiv prin denitie. a a a Aceasta nseamn c el nu face nimic fr a i se cere prin intermediul unei interogri SQL. a a aa a aceast sectiune vom prezenta modul care MySQL poate deveni un server activ prin In a n intermediul triggerelor. Un trigger este o bucat de cod (instructiuni declarative i procedurale) care se execut a s a de ctre server momentul care se execut anumite operatii i anumite conditii sunt a n n a s ndeplinite. 88

Principala diferenta ntre triggere i proceduri stocate este aceea c triggerele nu sunt s a apelate explicit de ctre utilizator, ci mai degrab sunt apelate transparent de ctre MySQL a a a anumite conditii. n Exemple de situatii care se execut un trigger sunt adugarea unei noi n a a nregistrri sau a atunci cnd se terge o a s nregistrare.

4.3.1

Sintaxa instructiunii CREATE TRIGGER

Instructiunea CREATE TRIGGER are 3 prti: a momentul care se apeleaz triggerul n a evenimentul care genereaz triggerul a actiunea efectuat de trigger a Sintaxa instructiunii CREATE TRIGGER este urmtoarea: a CREATE [DEFINER = user | CURRENT_USER ] TRIGGER trigger_name trigger_time trigger_event ON tbl_name FOR EACH ROW trigger_stmt Observatii: Nu se pot asocia triggere cu tabele temporare sau view-uri. Pentru a putea crea un trigger, trebuie ca utilizatorul care-l creeaz s aib privilegiul a a a TRIGGER asupra tabelei pentru care-l creeaz (de la versiunea 5.1.6 in sus, pentru a precedentele trebuia s aib privilegiul SUPER). a a a n a triger time reprezint momentul care se execut triggerul. Poate BEFORE sau AFTER. trigger moment reprezint evenimentul care produce executarea triggerului. Poate a unul dintre: INSERT (inclusiv INSERT, LOAD DATA i REPLACE), UPDATE sau s DELETE (este activat la folosirea lui REPLACE i DELETE, dar nu i cazul TRUNs s n CATE TABLE sau DROP TABLE, deoarece ultimele dou nu folosesc DELETE). a Nu se poate s avem dou triggere pentru acelai eveniment i acelai moment. De a a s s s exemplu, nu putem avea 2 triggere BEFORE UPDATE. Momentan, triggerele nu sunt activate de operatiile care rezult din constrngeri legate a a de cheile strine !!!!! a Exemplu: S se scrie un trigger care, momentul care se introduce o a n n nregistrare n a nregistrare ntr-o tabel tipuri care va retine utilizaa n tabela tipuri curs, retine o alt torul care a fcut inserarea, momentul care a fcut-o, precum i id-ul a n a s nregistrrii: a 89

-- crearea tabelei CREATE TABLE tipuri( user VARCHAR(30) NOT NULL, data DATE NOT NULL, id BIGINT NOT NULL ); -- crearea triggerului DELIMITER $$ DROP TRIGGER IF EXISTS mydatabase.test $$ CREATE TRIGGER mydatabase.test AFTER INSERT ON tipuri_curs FOR EACH ROW BEGIN INSERT INTO tipuri VALUES(USER(), CURDATE(),NEW.tip_curs); END $$ DELIMITER ; Observatie: Am folosit FOR EACH ROW ceea ce nseamn c se va executa codul pentru a a ecare inregistrare introdus. FOR EACH STATEMENT ar a nsemna c se execut trigger-ul a a pentru ecare interogare (inca nu e suportat). a Un trigger poate apela i proceduri stocate, ca exemplul urmtor: s n a DELIMITER $$ DROP PROCEDURE IF EXISTS mydatabase.insert_tipuri $$ CREATE PROCEDURE mydatabase.insert_tipuri (_user char(30), _data date, tipid bigint) BEGIN INSERT INTO tipuri VALUES (_user, _data, tipid); END $$ DELIMITER ; ----------------------------------DELIMITER $$ DROP TRIGGER IF EXISTS mydatabase.test $$ 90

CREATE TRIGGER mydatabase.test AFTER INSERT ON tipuri_curs FOR EACH ROW BEGIN CALL insert_tipuri(user(), curdate(),new.tip_curs); END $$ DELIMITER ;

4.3.2

Stergerea triggerelor

Stergerea triggerelor se poate face cu instructiunea DROP TRIGGER: DROP TRIGGER table_name.trigger_name

4.4

Event-uri

mod normal, MySQL, dup cum am vzut pn acum, toate operatiile care se In n a a a a efectueaz sunt datorate unor interogri cerute de utilizator sau de aplicatii client. a a Totui exist posibilitatea retinerii baza de date a unor operatii care s se efectueze la s a n a un moment de timp sau periodic. O situatie care se pot folosi evenimente este cnd vrem ca, periodic, datele din anumite n a tabele s e mutate alte tabele pentru a ri arhivate. a n Evenimentele au fost adugate MySQL a n ncepnd cu versiunea 5.1.6. a

4.4.1

Crearea unui eveniment

Un eveniment poate creat folosind instructiunea CREATE EVENT care are urmtoarea a sintax: a CREATE [DEFINER = user | CURRENT_USER ] EVENT [IF NOT EXISTS] event_name ON SCHEDULE schedule [ON COMPLETION [NOT] PRESERVE] [ENABLE | DISABLE | DISABLE ON SLAVE] [COMMENT comment] DO sql_statement; schedule: 91

AT timestamp [+ INTERVAL interval] ... | EVERY interval [STARTS timestamp [+ INTERVAL interval] ...] [ENDS timestamp [+ INTERVAL interval] ...] interval: quantity YEAR | QUARTER | MONTH | DAY | HOUR | MINUTE | WEEK | SECOND | YEAR_MONTH | DAY_HOUR | DAY_MINUTE | DAY_SECOND | HOUR_MINUTE | HOUR_SECOND | MINUTE_SECOND Dup cum se poate vedea, aceast instructiune are 2 prti: a a a momentul sau intervalul care s se produc evenimentul n a a actiunea care trebuie s se produc a a Un eveniment poate activ (el poate folosit, aa este imediat ce este creat) sau inactiv s (este retinut catalogul de evenimente dar nu este vericat de planicatorul de evenimente). n Executarea unui eveniment poart numele de invocare. De ecare dat cnd este invocat a a a un eveniment se efectueaz actiunea corespunztoare. a a Pentru ca folosirea evenimentelor s e activat, trebuie pornit planicatorul de evenia a mente: SET GLOBAL EVENT_SCHEDULER = TRUE El poate oprit prin instructiunea: SET GLOBAL EVENT_SCHEDULER = FALSE Planicatorul de evenimente poate pornit i atunci cnd se pornete serverul MySQL: s a s mysqld ... -event_scheduler=1 Pentru a ilustra modul de lucru cu eventuri, crem o tabel events invoked: a a CREATE TABLE events_invoked( event_type VARCHAR(30) NOT NULL, data DATE NOT NULL ); Iat i cteva exemple de evenimente: as a S se scrie un eveniment care s se produc chiar acelai moment i care s insereze a a a n s s a o valoare tabel. n a CREATE EVENT event1 ON SCHEDULE AT NOW() DO INSERT INTO EVENTS_INVOKED VALUES (DIRECT, NOW()) 92

S se scrie un eveniment care s se produc la nalul anului 2010. a a a CREATE EVENT END2010 ON SCHEDULE AT 2010-12-31 11:00:00 DO INSERT INTO EVENTS_INVOKED VALUES (END2010, NOW()) S se scrie un eveniment care s se produc peste exact 3 zile. a a a CREATE EVENT THREEDAYS ON SCHEDULE AT NOW() + INTERVAL 3 DAY DO INSERT INTO EVENTS_INVOKED VALUES (THREEDAYS, NOW()) S se creeze un eveniment care s se produc prima zi de duminic care urmeaz. a a a n a a CREATE EVENT NEXT_SUNDAY ON SCHEDULE AT CASE DAYNAME(NOW()) WHEN Sunday THEN NOW() + INTERVAL 7 DAY WHEN Monday THEN NOW() + INTERVAL 6 DAY WHEN Tuesday THEN NOW() + INTERVAL 5 DAY WHEN Wednesday THEN NOW() + INTERVAL 4 DAY WHEN Thursday THEN NOW() + INTERVAL 3 DAY WHEN Friday THEN NOW() + INTERVAL 2 DAY WHEN Saturday THEN NOW() + INTERVAL 1 DAY END DO INSERT INTO EVENTS_INVOKED VALUES (NEXT_SUNDAY,NOW()) S se creeze acelai eveniment ca cel precedent, dar mai succint. a s CREATE EVENT NEXT_SUNDAY ON SCHEDULE AT NOW() + INTERVAL (8 - DAYOFWEEK(NOW())) DAY DO INSERT INTO EVENTS_INVOKED VALUES (NEXT_SUNDAY,NOW()) S se creeze un eveniment care se va produce ziua urmtoare la ora 11. a n a CREATE EVENT MORNING11 ON SCHEDULE AT TIMESTAMP(CURDATE() + INTERVAL 1 DAY, 11:00:00) DO INSERT INTO EVENTS_INVOKED VALUES (MORNING11, NOW()) 93

S se creeze un eveniment care s se execute la ecare 2 ore, a a ncepnd de peste 3 ore a i pn la ora 11pm a zilei curente. s a a CREATE EVENT EVERY2HOUR ON SCHEDULE EVERY 2 HOUR STARTS NOW() + INTERVAL 3 HOUR ENDS CURDATE() + INTERVAL 23 HOUR DO INSERT INTO EVENTS_INVOKED VALUES (EVERY2HOUR, NOW()) S se execute o anumit instructiune de 6 ori, a a ncepnd de peste exact o zi la ora 12, a la interval de 1 minut. CREATE EVENT SIXTIMES ON SCHEDULE EVERY 1 MINUTE STARTS TIMESTAMP(CURDATE() + INTERVAL 1 DAY,12:00:00) ENDS TIMESTAMP(CURDATE() + INTERVAL 1 DAY,12:00:00) + INTERVAL 5 MINUTE DO INSERT INTO EVENTS_INVOKED VALUES (SIXTIMES, NOW()) S se ruleze o instructiune duminica, pentru 5 saptmni la rnd. a a a a CREATE EVENT FIVESUNDAYS ON SCHEDULE EVERY 1 WEEK STARTS CASE DAYNAME(NOW()) WHEN Sunday THEN NOW() WHEN Monday THEN NOW() + INTERVAL 6 DAY WHEN Tuesday THEN NOW() + INTERVAL 5 DAY WHEN Wednesday THEN NOW() + INTERVAL 4 DAY WHEN Thursday THEN NOW() + INTERVAL 3 DAY WHEN Friday THEN NOW() + INTERVAL 2 DAY WHEN Saturday THEN NOW() + INTERVAL 1 DAY END ENDS CASE DAYNAME(NOW()) WHEN Sunday THEN NOW() WHEN Monday THEN NOW() + INTERVAL 6 DAY WHEN Tuesday THEN NOW() + INTERVAL 5 DAY WHEN Wednesday THEN NOW() + INTERVAL 4 DAY WHEN Thursday THEN NOW() + INTERVAL 3 DAY WHEN Friday THEN NOW() + INTERVAL 2 DAY WHEN Saturday THEN NOW() + INTERVAL 1 DAY END + INTERVAL 4 WEEK DO INSERT INTO EVENTS_INVOKED VALUES (FIVESUNDAYS,NOW()) 94

Ce face urmtorul eveniment? a CREATE EVENT SUNDAYS ON SCHEDULE EVERY 1 WEEK STARTS TIMESTAMP(CASE DAYNAME(NOW()) WHEN Sunday THEN NOW() WHEN Monday THEN NOW() + INTERVAL 6 DAY WHEN Tuesday THEN NOW() + INTERVAL 5 DAY WHEN Wednesday THEN NOW() + INTERVAL 4 DAY WHEN Thursday THEN NOW() + INTERVAL 3 DAY WHEN Friday THEN NOW() + INTERVAL 2 DAY WHEN Saturday THEN NOW() + INTERVAL 1 DAY END, 15:00:00) ENDS TIMESTAMP( CASE DAYNAME(CONCAT(YEAR(CURDATE()),-12-31)) WHEN Sunday THEN CONCAT(YEAR(CURDATE()),-12-31) WHEN Monday THEN CONCAT(YEAR(CURDATE()),-12-31) - INTERVAL 1 DAY WHEN Tuesday THEN CONCAT(YEAR(CURDATE()),-12-31) - INTERVAL 2 DAY WHEN Wednesday THEN CONCAT(YEAR(CURDATE()),-12-31) - INTERVAL 3 DAY WHEN Thursday THEN CONCAT(YEAR(CURDATE()),-12-31) - INTERVAL 4 DAY WHEN Friday THEN CONCAT(YEAR(CURDATE()),-12-31) - INTERVAL 5 DAY WHEN Saturday THEN CONCAT(YEAR(CURDATE()),-12-31) - INTERVAL 6 DAY END, 15:00:00) DO INSERT INTO EVENTS_INVOKED VALUES (SUNDAYS, NOW())

4.4.2

Proprieti ale evenimentelor at

Exemple de astfel de proprieti sunt: at ON COMPLETION NOT PRESERVE - momentul care s-a terminat evenimentul n n el este ters, ON COMPLETION PRESERVE - dup ce s-a terminat el este pstrat, s a a chiar dac nu se va mai executa a COMMENT - permite stocarea unui comentariu relativ la eveniment DISABLE - face ca evenimentul s e dezactivat implicit a 95

4.5

Utilizatori i securitate s

O problem foarte important orice sistem soft este mecanismul de securitate i a a n s gestiune a drepturilor utilizatorilor. Intr-un sistem de gestiune a bazelor de date, aceasta este de maxim important. a a MySQL exist 4 mari categorii de privilegii care se pot acorda: In a Privilegii la nivel de coloane (de exemplu, un anumit utilizator are dreptul sa modice date ntr-un tabel, dar numai pe anumite coloane) Privilegii la nivel de tabele (de ex., un utilizator are dreptul s fac interogri SELECT a a a numai pe anumite tabele) Privilegii la nivel de baz de date, referitor la toate obiectele specice ale acesteia (de a ex, privilegiul de a crea noi tabele). Privilegii utilizator relativ la toate bazele de date recunoscute de MySQL (crearea/ tergerea unor baze de date) s Vom prezenta continuare modul care se pot crea noi utilizatori, crora li se pot n n a acorda anumite drepturi folosind comanda GRANT i, dac este nevoie, li se pot revoca s a drepturile folosind REVOKE.

4.5.1

Adugarea i tergerea utilizatorilor a s s

Pentru adugarea de noi utilizatori se folosete comanda CREATE USER, care are a s urmtoarea sintax: a a CREATE USER user [IDENTIFIED BY [PASSWORD] password] [, user [IDENTIFIED BY [PASSWORD] password]] ... Cel care folosete aceast instructiune trebuie s aib dreptul de CREATE USER la nivel s a a a global sau s aib dreptul de INSERT la nivelul bazei de date mysql. a a Trebuie precizat numele utilizatorului nou, urmat de parola acestuia, iar cazul n n care parola este deja transformat folosind MD5, trebuie s e prezent i cuvntul cheie a a s a PASSWORD. Dac nu se introduce nici o parol, atunci utilizatorul se poate logina fr parol, ceea a a aa a ce totui nu este o idee foarte bun. s a Numele unui utilizator este alctuit din dou prti: a a a numele propriu-zis al utilizatorului calculatorul de la care se poate conecta utilizatorul (poate un nume de calculator sau % sau o combinatie ntre cele dou). Dac nu se precizeaz nimic, automat se a a a consider c este %. a a Prezentm cteva exemple: a a 96

S se creeze un utilizator dumitru care s se poat conecta de pe orice calculator i a a a s care s aib parola parola. a a CREATE USER dumitru@% IDENTIFIED BY parola; S se creeze un nou utilizator radu care s se poat conecta numai de pe calculatorul a a a local. Nu se va preciza nici o parol. a CREATE USER radu@localhost; Observatie: Doi utilizatori cu dou calculatoare de pe care se pot loga sunt considerati a doi utilizatori distincti, putnd asignate drepturi diferite ecruia. a a Pentru a terge un utilizator se folosete comanda DROP USER, care are sintaxa: s s DROP USER user [, user] ... Trebuie fcute cteva observatii: a a momentul care se terge un utilizator, automat se terg toate drepturile asignate In n s s lui. Dac se terge un utilizator nu se terg automat i obiectele create de el. Astfel, a s s s tabelele, vederile, procedurile stocate etc. create de el ramn continuare. a n Pn la versiunea 5.0.2 nu se puteau terge dect utilizatori pentru care nu existau a a s a drepturi. Dup aceasta se terg automat i drepturile. a s s momentul care se terge un utilizator, dac acesta este loginat, el poate sa-i In n s a s continue operatiile pe care le face pn cnd se a a a nchide sesiunea lui.

4.5.2

Schimbarea numelor utilizatorilor i a parolelor s

Pentru a schimba numele unui utilizator exist instructiunea RENAME USER, cu sina taxa: RENAME USER old_user TO new_user [, old_user TO new_user] ... Putem avea eroare dac utilizatorul nu exist sau dac deja exist utilizatorul nou. a a a a S se scrie o interogare care s realizeze redenumirea utilizatorului dumitru@localhost a a ovidiu@localhost: n RENAME USER dumitru@localhost TO ovidiu@localhost; Se poate schimba parola unui utilizator folosind instructiunea SET PASSWORD, care are sintaxa: 97

SET PASSWORD [FOR user] = PASSWORD(some password) Iat i dou exemple: as a S se schimbe parola utilizatorului curent parola: a n SET PASSWORD = PASSWORD(parola); S se schimbe parola utilizatorului radu parola: a n SET PASSWORD FOR radu = PASSWORD(parola);

4.5.3

Acordarea de privilegii la nivel de coloane i tabele s

MySQL suport urmtoarele tipuri de privilegii: SELECT, INSERT, UPDATE, DELETE, a a REFERENCES, CREATE, ALTER, INDEX, DROP, ALL (ALL PRIVILEGES). Un privilegiu poate acordat doar de un utilizator care are la rndul lui suciente a privilegii. Privilegiile se pot oferi cu instructiunea GRANT, care are sintaxa prezentat cele ce a n urmeaz: a GRANT priv_type [(column_list)] [, priv_type [(column_list)]] ... ON [object_type] tbl_name | * | *.* | db_name.* TO user [IDENTIFIED BY [PASSWORD] password] [, user [IDENTIFIED BY [PASSWORD] password]] ... [REQUIRE NONE | [SSL| X509] [CIPHER cipher [AND]] [ISSUER issuer [AND]] [SUBJECT subject]] [WITH with_option [with_option] ...] object_type = TABLE | FUNCTION | PROCEDURE with_option = GRANT OPTION | MAX_QUERIES_PER_HOUR count | MAX_UPDATES_PER_HOUR count | MAX_CONNECTIONS_PER_HOUR count | MAX_USER_CONNECTIONS count 98

Dac se acord privilegii unui utilizator care nu exist a, automat acel utilizator este a a a nc creat. Prezentm, continuare, cteva exemple de acordare de drepturi: a n a S se acorde dreptul de SELECT asupra tabelei studenti utilizatorului mihai@localhost, a care nu exist i trebuie creat acum. as GRANT SELECT ON mydatabase.studenti TO mihai@localhost IDENTIFIED BY parola; S se acorde dreptul de UPDATE pe coloanele oras, judet si tara utilizatorului mia hai@localhost. GRANT UPDATE ON studenti TO mihai@localhost S se acorde utilizatorului mihai@localhost dreptul de a face UPDATE-uri pe coloanele a nume i prenume din tabela studenti. s GRANT UPDATE(nume, prenume) ON studenti TO mihai@localhost;

4.5.4

Acordarea de privilegii la nivelul bazei de date

Privilegiile prezentate anterior se aplic la nivel de tabel. Se pot da drepturi i relativ la a s o ntreag baz de date. a a Se pot acorda urmtoarele privilegii: SELECT, INSERT, DELETE, UPDATE, REFERa ENCES, CREATE, ALTER, DROP, INDEX, CREATE TEMPORARY TABLES, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EXECUTE ROUTINE, LOCK TABLES, ALL (ALL PRIVILEGES). Prezentm, continuare, dou exemple: a n a S se acorde drepturile de SELECT, INSERT, UPDATE i DELETE, asupra tuturor a s tabelelor din baza de date mydatabase. GRANT SELECT, INSERT, UPDATE, DELETE ON mydatabase.* TO mihai@localhost; S i se acorde utilizatorului cristi dreptul de a face SELECT i INSERT toate a s n tabelele de pe server. GRANT SELECT, INSERT ON * TO cristi; 99

4.5.5

Acordarea de privilegii la nivel de utilizator

Pentru ecare privilegiu care a fost prezentat la sectiunea precedent se pot deni priv a ilegii la nivel de utilizator (ele nu se refer doar la anumite obiecte, ci au o aplicabilitate a general). a Aceste privilegii sunt: SELECT, INSERT, DELETE, UPDATE, REFERENCES, CREATE, ALTER, DROP, INDEX, CREATE TEMPORARY TABLES, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EXECUTE ROUTINE, LOCK TABLES (acestea existau i sectiunea precedent), CREATE USER, SHOW DATABASES, FILE, s n a PROCESS, RELOAD, REPLICATION CLIENT, REPLICATION SLAVE, SHUTDOWN, SUPER, USAGE. Iat i cteva exemple: as a S se acorde utilizatorului mihai drepturile CREATE, ALTER i DROP pentru toate a s obiectele din baza de date. GRANT CREATE, ALTER, DROP ON *.* TO mihai; timpul instalrii MySQL se acord utilizatorului root urmtoarele drepturi: In a a a GRANT ALL PRIVILEGES ON *.* TO root; S se acorde utilizatorului cristi dreptul de a crea alti utilizatori: a GRANT CREATE USER ON *.* TO cristi;

4.5.6

Dreptul de a da drepturi: optiunea WITH GRANT

mod normal, utilizatorul care primete un drept nu poate s-l transmit mai departe. In s a a Totui acest lucru se poate face dac atunci cnd se acord un drept se specic optiunea s a a a a WITH GRANT OPTION. Iat dou exemple: a a S se acorde dreptul de SELECT asupra tuturor bazelor de date utilizatorului mihai, a astfel at el s poat s-l transmit mai departe. nc a a a a GRANT SELECT ON *.* TO mihai WITH GRANT OPTION; 100

Ce se ampl dac se execut urmtoarele interogri? nt a a a a a GRANT CREATE ON *.* TO mihai; GRANT SELECT, INSERT ON *.* TO mihai WITH GRANT OPTION; urma executrii celor 2 interogri, utilizatorul mihai poate s dea mai departe, In a a a att drepturile de SELECT i INSERT, ct i dreptul de CREATE. a s a s

4.5.7

Restrictionarea privilegiilor

Se poate ca unui utilizator s i se acorde drepturi i cu anumite constrngeri, precum a s a exemplul urmtor: n a GRANT SELECT ON *.* TO mihai WITH MAX_QUERIES_PER_HOUR 1

Alte restrictionri posibile ar putea : MAX CONNECTIONS PER HOUR, MAX UPDATES PER HO a MAX USER CONNECTIONS. Valoarea 0 pentru oricare din aceste proprieti implic nelimitarea acelei proprieti. at a at

4.5.8

Revocarea privilegiilor

Privilegiile pot revocate prin interogarea REVOKE: REVOKE priv_type [(column_list)] [, priv_type [(column_list)]] ... ON [object_type] tbl_name | * | *.* | db_name.* FROM user [, user] ... REVOKE ALL PRIVILEGES, GRANT OPTION FROM user [, user] ... Aceast instructiune permite revocarea drepturilor unor utilizatori. Pentru a o putea a folosi, utilizatorul respectiv trebuie s aib privilegiul GRANT OPTION i s aib drepturile a a s a a pe care le revoc. a Prezentm cteva interogri: a a a 101

S se revoce toate drepturile utilizatorului mihai@localhost: a REVOKE ALL, GRANT OPTION FROM mihai@localhost; Observatie: Aceast instructiune nu terge i utilizatorul, ci doar toate drepturile lui. a s s S se revoce dreptul de INSERT al utilizatorului cristi asupra tabelei studenti: a REVOKE INSERT ON studenti FROM cristi; Dac un utilizator are drepturi care se suprapun (cum ar faptul ca poate s fac a a a SELECT pe o tabel i poate s fac SELECT pe toate tabelele dintr-o baz de date), a s a a a retragerea unuia din drepturi nu implic i retragerea celuilalt. as Observatie: Se pot acorda drepturi unui utilizator i pentru view-uri. Acest lucru ajut s a la mbuntirea securitii. a at at

4.6

Tranzactii i lucrul intr-un mediu multiuser s

toate exemplele pe care le-am utilizat pn acum am pornit de la presupunerea c noi In a a a suntem singurii utilizatori ai sistemului de gestiune al bazei de date. Totui, realitate, lucrurile sunt mult mai complicate, deoarece MySQL este folosit s n n mod concurent de mai multi utilizatori. Problema care se pune este ce se ampl dac mai nt a a multi utilizatori acceseaz aceeai a s nregistrare simultan. Pentru a studia acest lucru vom prezenta conceptele de tranzactie, savepoint, lock, dead lock i nivel de izolare. s O observatie important este faptul c nu toate engine-urile suport lucrul cu tranzactii. a a a Unele din engine-urile care nu suport sunt MyISAM i Memory, iar unul care suport este a s a InnoDB.

4.6.1

Conceptul de tranzactie

O tranzactie este un set de nregistrri care se execut numele unui utilizator i care a a n s pot refcute situatia care acesta si dorete acest lucru. a n n s mod implicit, aplicatiile client care utilizeaz MySQL, sunt setate modul autocomIn a n mit. Aceasta nseamn c orice instructiune SQL este considerat ca o tranzactie, ea putnd a a a a refcut doar dac se efectueaz instructiunea complementar. a a a a a Implicit, cnd ne conectm la MySQL, variabila autocommit este setat la 1. Pentru a a a a schimba acest lucru putem efectua urmtoarea instructiune: a SET @@autocommit = 0 102

Dac dup ce am fcut acest lucru, efectum cteva comenzi SQL care modic a a a a a a nregistrrile a din BD, executm comanda ROLLBACK, automat toate acestea sunt refcute. a a Se poate vedea acest lucru dac se execut urmtoarele interogri: a a a a SET @@autocommit = 0; SELECT * FROM note; DELETE FROM note; SELECT * FROM note; ROLLBACK; SELECT * FROM note; Astfel sunt clare 2 lucruri: cu ROLLBACK se refac toate instructiunile de la nceputul tranzactiei cu COMMIT se salveaz modicrile fcute. a a a Motivul pentru care avem nevoie de tranzactii este faptul c timp ce se produc mai a n multe instructiuni dependente una de alta, se poate ca ceva s nu mearg bine i atunci s-ar a a s lsa baza de date a ntr-o stare inconsistent. a Observatie important: Exist anumite instructiuni pentru care nu se poate face undo i a a s care, prin executarea lor, automat implic un commit. Astfel de instructiuni sunt CREATE a TABLE, ALTER FUNCTION, GRANT i DROP INDEX. s

4.6.2

Pornirea unei tranzactii

Pornirea unei noi tranzactii se poate face implicit, dup ce s-a apelat commit sau prin a folosirea instructiunii START TRANSACTION. O instructiune START TRANSACTION conduce la comiterea tuturor instructiunilor care apartineau tranzactiei precedente. Mai mult dect att, modul autocommit este dezac a a tivat. Dup terminarea tranzactiei care tocmai a ncepe, modul autocommit este setat la vechea lui valoare, indiferent care era aceasta.

4.6.3

Lucrul cu savepoints

Se poate s se refac tot ceea ce s-a efectuat tranzactia curent folosindu-se ROLLa a n a BACK WORK. Dac se dorete, se poate, de asemenea, s se salveze o anumit stare i s a s a a s a se aduc tranzactia la acea stare. a Se creeaz un savepoint, prin instructiunea: a 103

SAVEPOINT nume_savepoint Se poate reveni la acea stare prin instructiunea: ROLLBACK WORK TO SAVEPOINT nume_savepoint; Observatie: momentul care se revine la un anumit savepoint, nu se pot reface dect In n a instructiunile din tranzactia curent. Iat un exemplu: a a SET AUTOCOMMIT=0; SAVEPOINT test1000; SELECT * FROM tipuri_curs; INSERT INTO tipuri_curs VALUES(NULL, bla); ROLLBACK TO test1000; SELECT * FROM tipuri_curs; Tranzactiile pot folosite i contextul procedurilor stocate. s n Observatie: Dac o tranzactie a ncepe nainte de procedura stocat, i se termin doar a s a dup ea, atunci instructiunile din procedur se consider a fcute acea tranzactie. a a a a n

4.6.4

Probleme care pot aprea datorit accesului concurent a a

O astfel de problem ar putea dac a a ntr-o tranzactie, se terg toate s nregistrrile dintr-o a tabel. Ce s-ar ampla cu ceilalti utilizatori care folosesc acea tabel pn cnd tranzactia a nt a a a a ajunge starea commit? n Exist mai multe astfel de probleme, care pot grupate astfel: a Dirty Read (Uncommited Read) - Aceast problem apare atunci cnd un utia a a lizator vede nite date pe care alt utilizator nu le-a comis a. s nc U1: INSERT INTO tipuri_curs VALUES(null,optional2); U2: SELECT * FROM tipuri_curs; U1: ROLLBACK; Nonrepeatable Read (Nonreproducible Read) - Acest lucru se ampl atunci nt a cnd la citiri diferite avem pentru aceeai a s nregistrare date diferite interiorul unei n singure tranzactii. 104

U1: SELECT cod_student FROM studenti WHERE oras=Brasov INTO @test; U2: UPDATE studenti SET oras=sibiu WHERE cod_student=2; U2: COMMIT; U1: SELECT nume, prenume,oras FROM studenti WHERE cod_student IN @test; Phantom Read - cadrul aceleiai tranzactii, la dou citiri distincte se obtin In s a nregistrri diferite. a U1: SELECT * FROM tipuri_curs; U2: INSERT INTO tipuri_curs VALUES (NULL,ceva); U2: COMMIT; U1: SELECT * FROM tipuri_curs; Lost Update - Se ampl cnd doi utilizatori modic aceleai date, amndoi avnd nt a a a s a a la baz datele originale. Astfel, modicarea fcut de unul dintre ei se va pierde. a a a U1: UPDATE tipuri_curs SET den_tip=CONCAT(den_tip,a) WHERE cod_tip=1; U2: UPDATE tipuri_curs SET den_tip=CONCAT(den_tip,b) WHERE cod_tip=1; U1: COMMIT; U2: COMMIT; cele ce urmeaz vom prezenta mecanismele pe care le prezint MySQL pentru a rezolva In a a astfel de probleme. Evident c s-ar putea lucra aa fel at doi utilizatori s nu poat executa simultan a n s nc a a tranzactii, dar acest lucru ar ncetini foarte tare serverul de baze de date. Am spune c avem a o concurent sczut. a a a

4.6.5

Mecanismul de locking

Mecanismul de locking este unul ct se poate de simplu. momentul care o a In n nregistrare este folosit ea este blocat, nemaiputnd folosit de o alt tranzactie, pn cnd nu se a a a a a a a a execut commit. a Acest mecanism rezolv cele 4 probleme pe care le-am prezentat anterior. a Se consider c mecanismul functioneaz corect dac cele 2 tranzactii dau un rezultat a a a a care s-ar obtine dac ele s-ar executa serial (indiferent ce ordine). a n Evident, aceste lock-uri se mentin nite buere, care nu sunt vizibile pentru utilizator. n s Prin folosirea lor se asigur faptul c tranzactiile sunt executate serial. a a Pentru a mri nivelul de concurenta, exist de fapt dou tipuri de locking: a a a share lock (read) - alti utilizatori pot citi acea nregistrare dar nu o pot modica. 105

exclusive lock (write) - alti utilizatori nu pot folosi acea nregistrare pn cnd ea nu a a a este eliberat. a Trebuie s m foarte atenti atunci cnd scriem tranzactii, pentru a nu produce situatii a a de DEADLOCK. MySQL nu le detecteaz. a Atunci cnd se fac numeroase operatii asupra unei a ntregi tabele, se poate s se blocheze a toat tabela cu LOCK TABLE. a Sintaxa ei este: LOCK TABLES tbl_name [[AS] alias] lock_type [, tbl_name [[AS] alias] lock_type] ... lock_type: READ [LOCAL] | [LOW_PRIORITY] WRITE UNLOCK TABLES La sfritul unei tranzactii LOCK-ul este eliberat automat. as MySQL suport urmtoarele tipuri de locking: a a READ - aplicatia poate citi tabela, alte aplicatii pot de asemenea s o citeasc dar nu a a pot modica tabela. READ LOCAL - (numai pentru tabele MyISAM) mai multi utilizatori pot aduga a nregistrri simultan, dar numai anumite conditii. a n WRITE - aplicatia poate modica tabela, timp care alte aplicatii nu o pot nici n mcar accesa. a s a LOW PRIORITY WRITE - aplicatia citete tabela, alte aplicatii pot citi din tabel. O alta aplicatie poate primi lock-ul numai dac s-a terminat cea curent. a a

4.6.6

Nivelul de izolare

plus fata de ceea ce tiam, ecare tranzactie MySQL are un anumit nivel de izolare. In s n Avem urmtoarele 4 nivele de izolare: a Serializable - utilizatorii sunt cel mai separati unii de altii Repeatable read - Avem blocri atunci cnd se citesc date i blocri exclusive atunci a a s a cnd se scriu. Putem siguri c dac se face un SELECT de mai multe ori, rezultatele a a a vor aceleai. Singura problema este cazul lost update. s n 106

Cursor stability (read committed) - Este la fel ca precedentul, doar c momentul a n care s-a procesat un SELECT, datele sunt deblocate. Blocrile exclusive se fac la n a fel ca cazul precedent, deblocrile ind fcute doar cnd tranzactia s-a terminat. n a a a Dirty read (read uncommitted) - Este la fel ca precedenta, numai c se elibereaz a a lock-urile exclusive imediat ce s-a fcut modicarea. Aceasta a nseamn c, un utilizator a a poate vedea modicrile fcute de alt utilizator a a nainte ca acesta s fac commit. a a Se poate deni un nivel de izolare numai cu acele engine-uri care suport tranzactii, cum a sunt: InnoDB i BDB. s Pentru a vedea nivelul setat la un moment dat, putem efectua urmtoarea interogare: a SELECT @@GLOBAL.TX_ISOLATION; sau SHOW GLOBAL VARIABLES LIKE TX_ISOLATION; Valoarea implicit a acestui indicator este REPEATABLE READ. a Se poate schimba nivelul de izolare folosind comanda SET TRANSACTION, care are sintaxa: SET [GLOBAL | SESSION] TRANSACTION ISOLATION LEVEL READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE Instructiunea SET TRANSACTION poate i ea s s a nceap o tranzatie la fel ca START a TRANSACTION. Dac o tranzactie dorete s fac un lock la un moment dat, atunci ea trebuie s atepte a s a a a s ca cel care a fcut lock-ul s elibereze resursa ( cazul care cineva a blocat-o). a a n n

4.6.7

Momentul procesrii interogrilor a a

Mereu am pornit de la presupunerea c interogrile INSERT, UPDATE, DELETE, REa a PLACE i SELECT se execut imediat. s a Totui se poate s alegem una din urmtoarele variante: s a a Delayed - Cel care a apelat instructiunea este anuntat c ea a fost executat, iar ea este a a pus a ntr-o list de ateptare i este executat cnd sistemul crede c este momentul. a s s a a a Low priority - Schimbarea se face atunci cnd nici un alt utilizator nu citete datele. a s High priority - MySQL asigur faptul c nici un alt utilizator nu poate folosi datele a a n timp ce are loc modicarea, nici mcar pentru citiri. a 107

Aceste optiuni apar cazul diverselor comenzi: n DELETE [ LOW_PRIORITY ] [ IGNORE ] ... INSERT [ DELAYED | LOW_PRIORITY | HIGH_PRIORITY ] [ IGNORE ] ... REPLACE [ DELAYED | LOW_PRIORITY] [ IGNORE ] ... UPDATE [ LOW_PRIORITY ] [ IGNORE ] ...

108

Partea II Oracle

109

Capitolul 5 Prezentare general a


5.1 Generaliti at

Oracle ofer un suport foarte complex pentru lucrul cu baze de date i realizarea de a s cele ce urmeaz vom insista mai ales asupra bazelor de date. aplicatii profesionale. In a continuare vom prezenta o variant de server mai putin costisitoare din punct de In a vedere al resurselor i anume Oracle Express Edition. s De-a lungul ultimilor 30 de ani, Oracle a fost i este poate cea mai avansat solutie care s a poate aleas de pe piata sistemelor de lucru cu baze de date. a Numai ultimii ani au aprut numeroase versiuni de Oracle: n a Oracle8 (1997) Oracle8i (1999) (i vine de la Internet) Oracle9i (2001) Oracle Database 10g (2003) (g vine de la grid computing) Oracle Database 11g (2007) Inceputurile acestui SGBD provin din 1977 cnd o companie Software Development Laboa ratories Relational Software a scos un produs numit Oracle V.2. Acesta a fost primul SGBD comercial din lume. Exist mai multe versiuni de server: a Oracle Express Edition - Este versiunea cea mai simpl i este disponibil fr costuri. as a aa Are anumite limitri: memorie de maxim 1GB iar pe disk poate ocupa maxim 4GB. a lipsesc facilitile pentru lucrul cu Java i multe alte lucruri care se pot alni doar Ii at s nt versiunile mai avansate. n Oracle Personal Edition - Folosit de un singur programator pentru a crea aplicatii multiutilizator. Ofer toate facilitile pe care le are Enterprise Edition. a at 111

Oracle Standard Edition One - Pentru aplicatii relativ mici. La fel ca varianta urmtoare a doar c suport maxim 2 procesoare i nu suport RAC (Real Applications Clusters). a a s a Oracle Standard Edition - Pentru aplicatii mici i medii. Suport att RAC ct i pn s a a a s a a la 4 procesoare. Oracle Enterprise Edition - Varianta complet a serverului. Prezint foarte multe a a faciliti care nu sunt inta acestui curs. at t Pentru a elege mai bine ce ofer Oracle, prezentm urmtoarea list de faciliti: nt a a a a at Faciliti pentru dezvoltarea aplicatiilor cu baze de date at Faciliti legate de conexiunea cu bazele de date at Faciliti legate de baze de date distribuite at Faciliti pentru mutarea datelor at Faciliti legate de performant at a Faciliti legate de managementul bazei de date at Faciliti legate de securitate. at

5.2

Arhitectura Oracle

Oracle exist dou entiti care de multe ori sunt folosite pentru a reprezenta acelai In a a at s lucru cu toate c ele sunt diferite: a instant - se refer la software-ul care ruleaz pe server i face posibil accesul la baza a a a s de date. Instanta este logic; ea reprezint structurile retinute memorie i procesele a a n s care se execut pe server. O instanta poate pentru o singur baz de date, pe cnd a a a a o baz de date poate avea mai multe instante. a baz de date - se refer la stocarea zic a bazei de date. Accesul la o baz de date se a a a a face prin intermediul unei instante. O baz de date Oracle contine numeroase lucruri: tablespaces, iere de control, de log, a s de log arhivate i alte tipuri de iere. s s Tablespaces - Toate datele stocate ntr-o baz de date Oracle sunt stocate a ntr-un tablespace. El este o structur logic neavnd echivalent pe disc. Este alctuit din mai multe a a a a iere de date. Atunci cnd creem un tabel, specicm ce tablespace creem i Oracle s a a n l s tie s gseasc un loc liber pentru el ierele de date corespunztoare. s a a a n s a O baz de date Oracle poate avea pn la 8 exabytes (un exabyte are 1 milion de a a a terrabytes). Fiierele zice care alctuiesc o baz de date Oracle sunt de 3 tipuri: s a a 112

Fiiere de control - contin date despre locatia unde se gsesc celelalte dou tipuri de s a a iere, numele bazei de date, cnd a fost creat, informatii despre tablespaces, backups a a uri, log-uri arhivate, etc. Fiiere de date - contin datele propriu-zise, tabelele i indecii, dictionarul de date. s s s Fiiere redo de log - Oracle retine toate modicrile care s-au produs asupra bazei de s a date aceste iere. Ele pot folosite pentru a reface anumite operatii cazul n s n n care este nevoie de acest lucru. Ele sunt folosite de asemenea cnd avem operatii de a tipul ROLLBACK.

5.3

Instalare Oracle

continuare prezentm modul care vom lucra cele ce urmeaz cu Oracle. Trebuie In a n n a precizat c vom folosi versiunea Express Edition. a primul rnd trebuie descrcat de pe Internet Oracle Express Edition. Pentru a putea In a a face acest lucru va trebui s v a a nregistrati pe site-ul oracle.com. Dup aceea instalm serverul de baze de date. Instalarea este una obinuit, aa c nu a a s a s a vom intra foarte multe amnunte. n a continuare putem lucra mai multe moduri: In n folosind aplicatia web implicit : se d clic pe Go to Database Homepage in sectiunea a a corespunztoare din All Programs sau se pornete un browser i se introduce adresa: a s s http://localhost:8080/apex folosind SQLPlus: Tot din sectiunea corespunztoare din All Programs se alege Run a SQL Command Line. folosind Oracle SQL Developer : acesta se poate downloada de pe site-ul Oracle, dup a care se instaleaz prin dezarhivare. a Observati faptul c modul de lucru client/server este identic celui folosit cazul MySQL. a n continuare vom prezenta modul care se lucreaz folosind SQLPlus. fereastra care In n a In apare tastm connect i dm Enter. Introducem numele utilizatorului i executm Enter, a s a s a apoi parola i Enter. s Conectarea putea facut i printr-o instructiune de genul: as connect mihai/parola@localhost Pentru a verica dac suntem conectati sau nu, putem efectua o interogare simp: a a SELECT SYSDATE FROM dual; 113

Sysdate este o functie predenit, iar dual este o tabel predenit, care are o singur a a a a nregistrare i care este folosit astfel de situatii. s a n Cnd am terminat cu o conexiune, putem s ne deconectm folosind disconnect. a a a acest moment se pot executa diverse instructiuni, la fel ca cazul utilitarului mysql. In n Pentru a iei din aplicatie putem scrie exit. s Ca i in cazul MySQL se poate s executm anumite iere cu comenzi SQL. Pentru s a a s acest lucru, din SQLPlus executm: a @ script.sql Se poate ampla s trebuiasc s dm toat calea ctre ierul care contine scriptul nt a a a a a a s SQL.

114

Capitolul 6 Interogarea i actualizarea datelor s


6.1
6.1.1

Generaliti at
Tipuri de date Oracle n

Oracle exist trei tipuri de date: In a Tipuri de date caracter Tipuri de date numerice Tipuri de date pentru date calendaristice Alte tipuri de date Tipuri de date caracter Pentru lucrul cu caractere se pot folosi mai multe tipuri de date. Pentru acestea se pot folosi functiile pentru lucrul cu iruri de caractere. Totui aceste functii nu se pot folosi s s pentru string-uri foarte lungi. Tipurile permise Oracle sunt: n CHAR - se folosete pentru a stoca iruri de caractere cu lungime x. Poate retine s s a iruri cu lungimea cuprins s a ntre 1 i 2000. Dac irul de caractere nu are lungimea s as specicat se completeaz cu spatii la sfrit. a a as VARCHAR2 - stocheaz iruri de caractere cu lungime variabil. Lungimea acestora as a poate pn la maxim 4000 de caractere, ele neind completate cu spatii dac nu au a a a lungimea maxim. Momentan, acest tip este sinonim cu VARCHAR, dar este posibil a ca viitor tipul VARCHAR s e folosit cu alt semnicatie. n a a NCHAR i NVARCHAR sunt folosite pentru a putea avea coloane care s retinem i s n a s iruri de caractere care folosesc alte eturi de caractere dect cel principal. De exemplu, s s a 115

ntr-o baz de date care folosete alfabetul romnesc, vrem ca a s a ntr-o coloan s folosim a a un text limba chinez. n a LONG retine text de pn la 2 GB i provine din versiunile mai vechi de Oracle. a a s Dac dorim s retinem texte foarte lungi este recomandabil s folosim mai degrab a a a a CLOB sau NCLOB. Coloanele de acest tip nu pot folosite WHERE, GROUP n BY, ORDER BY, CONNECT BY sau DISTINCT. Coloanele de acest tip nu pot indexate. CLOB i NCLOB - stocheaz pn la 4GB de caractere pn la versiunea 10g, dar s a a a a a ulterior pot stoca pn la 128TB. a a Tipuri de date numerice Principalul tip de date numeric Oracle este tipul NUMBER. El are dou componente: n a NUMBER (precision, scale) Precizia reprezint numrul maxim de cifre care se poate folosi reprezentarea numrului. a a n a Implicit ea este 38. Scala reprezint numrul maxim de cifre pe care le putem avea dup virgul. Dac nu a a a a a este specicat nici o scal, automat se presupune c este 0. a a a ultimele versiuni de Oracle au mai aprut noi tipuri de date cum ar : SIMPLE INTEGER, In a BINARY FLOAT i BINARY DOUBLE. s Se mai pot folosi i tipurile ANSI, precum DECIMAL, INTEGER, INT, SMALLINT, s FLOAT, DOUBLE PRECISION i REAL dar ele sunt reprezentate de Oracle tot contextul s n lui NUMBER. Tipul DATE Pentru a retine date calendaristice Oracle folosete urmtoarea reprezentare: s a DD-MM-YY HH:MI:SS La fel ca i cazul MySQL, ultimele versiuni de Oracle a fost adugat tipul INTERs n n a VAL. Alte tipuri de date Oracle avem i tipuri de date care nu pot In s ncadrate niciuna din situatiile precen dente: RAW i LONG RAW - stocheaz obiecte care au propriul lor format cum ar bitmas a purile. RAW merge pn la 2KB iar LONG RAW pn la 2GB. a a a a ROWID - este un tip special de coloan numit i pseudocoloan. El reprezint adresa a s a a zic a unei a nregistrri. a 116

LOB - poate stoca pn la 4GB de date. Are mai multe varieti: a a at CLOB - stocheaz numai caractere a NCLOB - stocheaz caractere cu caracter national a BLOB - stocheaz date format binar a n Se poate ca un astfel de cmp s-i stocheze datele i iere externe bazei de date. a as s n s XMLType - poate retine un document XML folosind de fapt un CLOB. Exist functii a predenite care pot prelua valorile unor noduri etc. Tipuri de date utilizator - denite pe baza tipurilor de baz care exist Oracle. a a n

6.1.2

Functii predenite Oracle n

Oracle exist mai multe tipuri de functii: In a functii pentru lucrul cu iruri de caractere; s functii matematice; functii pentru lucrul cu expresii regulate; functii pentru lucrul cu date i timp; s alte functii. Functii pentru lucrul cu iruri de caractere s Prezentm cteva din functiile pentru lucrul cu iruri de caractere: a a s ASCII(x) - codul ASCII al caracterului x CHR(x) - returneaz caracterul asociat unui anumit cod ASCII a CONCAT(x,y) - concateneaz dou iruri de caractere a as INITCAP(x) - prima liter e transformat liter mare iar restul litere mici, pentru a a n a ecare cuvnt parte a n LENGTH(x) - returneaz lungimea unui ir de caractere a s LOWER(x) - irul numai cu litere mici s NVL(x,value) - returneaz x dac nu este null, sau value dac x este null a a a REPLACE(x,search string, replace string - nlocuiete toate aparitiile unui ir de s s caractere cu altul 117

SUBSTR(x,start[,length] - returneaz irul care a s ncepe la pozitia start irul x, n s eventual cu length caractere UPPER(x) - irul transformat litere mari s n

6.1.3

Functii numerice

Prezentm continuare doar o parte din functiile numerice fr a le detalia foarte a n aa tare: ABS(x), ACOS(x), ASIN(x), ATAN(x), BITAND(x,y), COS(x), COSH(x), CEIL(x), EXP(x), FLOOR(x), LOG(x,y), LN(x), MOD(x,y), POWER(x,y), ROUND(x[,y]), SIN(x), SIGN(x), SQRT(x), TAN(x), TRUNC(x[,y]).

6.1.4

Functii pentru lucrul cu date i timp s

Implicit, o dat Oracle se retine formatul: 11-JAN-2009, dar se poate folosi i a n n s cuvntul cheie DATE pentru a introduce date formatul clasic (YYYY-MM-DD). a n Iat dou exemple: a a insert into profesori values (2, Bocu,Dorin,profesor,m,03-AUG-1955); sau insert into profesori values (2, Bocu,Dorin,profesor,m,DATE 1955-08-03); s Pentru lucrul cu date exist dou functii foarte importante TO CHAR i TO DATE. a a Exemple de folosire ale lui TO CHAR: TO_CHAR(datan, MONTH DD,YYYY) TO_CHAR(datan, MONTH DD,YYYY, HH24:MI:SS) TO_CHAR(SYSDATE, DD-MM-YYYY) TO_CHAR(SYSDATE, DD/MM/YYYY) mod asemntor, folosind TO DATE i specicnd un format se poate obtine un obiect In a a s a de tipul DATE: TO_DATE(04-JUL-2007) TO_DATE(July 4, 2007, MONTH DD, YYYY) TO_DATE(7.4.07, MM.DD.YY) Formatul implicit poate schimbat pentru sesiunea curent folosind urmtoarea instrutiune a a SQL: ALTER SESSION SET NLS_DATE_FORMAT = MONTH-DD-YYYY; Un administrator poate face acelai lucru pentru server, cu urmtoarea instructiune: s a ALTER SYSTEM SET NLS_DATE_FORMAT = MONTH-DD-YYYY; 118

Evident, formatul poate ales mod asemntor cu formatele prezentate anterior. n a a Exist mai multe functii pentru lucrul cu date i timp, precum: a s ADD MONTHS(x,y) - adaug la data x, y luni a a LAST DAY(x) - ultima zi a lunii din dat MONTHS BETWEEN(x,y) - numrul de luni a ntre dou date a SYSDATE - returneaz data i timpul curente a s i altele s Pentru lucrul cu date exist Oracle i tipul TIMESTAMP. El prezint dou avantaje: a n s a a pentru secunde poate retine i prti fractionare; s a poate retine i informatii despre zona de timp. s plus fata de functiile prezentate mai exist functii pentru conversii precum i pentru In a s lucrul cu expresii regulate. Pentru mai multe detalii, se recomand consultarea diverselor a documentatii Oracle.

6.2
6.2.1

Interogarea SELECT
Crearea bazei de date exemplu

interogrile care vor prezentate continuare, vom folosi aceeai baz de date ca i In a n s a s cea folosit pentru a ilustra modul de lucru cu MySQL. a Vom folosi un ier script.sql pentru a retine tot ceea ce este necesar. Acesta arat s a astfel: drop table tipuri_curs; create table tipuri_curs( tip_curs integer constraint tipuri_curs_pk primary key, den_tip varchar2(30) not null ); insert into tipuri_curs values (1,obligatoriu); insert into tipuri_curs values (2,optional); insert into tipuri_curs values (3,facultativ);

119

drop table profesori;

create table profesori( cod_prof integer constraint profesori_pk primary key , nume varchar2(30) not null, prenume varchar2(30) not null, grad varchar2(30) not null, sex char(1) not null, datan date ); insert into profesori values (1, Iolu,Mihai,lector,m,03-05-1979); insert into profesori values (2, Bocu,Dorin,profesor,m,03-08-1955); insert into profesori values (3, Ciurea,Eleonor,profesor,m,13-07-1943); insert into profesori values (4, Sasu,Lucian,lector,m,02-08-1977); insert into profesori values (5, Deaconu,Adrian,conferentiar,m,13-03-1974); insert into profesori values (6, Ciupala, Laura, conferentiar, f, null); drop table studenti; create table studenti( nrmatricol integer constraint studenti_pk primary key, nume varchar2(30) not null, prenume varchar2(30) not null, CNP varchar2(13) not null, sex char(1)not null, datan date not null, oras varchar2(30) not null, judet varchar2(30) not null, tara varchar2(30) not null ); insert into studenti values (101, Florescu,Radu,1870409030182,m,09-07-1987, Bucuresti,Bucuresti,Romania);

120

insert into studenti values (102, Ceausescu,Ionut,1880323020382,m,23-03-1988, Brasov,Brasov,Romania); insert into studenti values (103, Ciumarnean,Oana,2880520435434,f,20-05-1988, Brasov,Brasov,Romania); insert into studenti values (104, Neagu,Andrei,1871115456537,m,15-11-1987, Sinaia,Prahova,Romania); insert into studenti values (105, Saracu,Ana-Maria,1880308345322,f,08-03-1988, Fagaras,Brasov,Romania); insert into studenti values (106, Ionita,Emanuel-Ionut,1881023345433,m,23-10-1988, Victoria,Brasov,Romania); insert into studenti values (107, Dumitrescu,Teodora,2881220030325,f,20-12-1988, Cluj-Napoca,Cluj,Romania); insert into studenti values (108, Radoi,Ovidiu,1871005325323,m,05-10-1987, Munchen,Bavaria,Germania); insert into studenti values (109, Tanase,Alexandra,2880301345436,f,01-03-1988, Brasov,Brasov,Romania); insert into studenti values (110, Mocanu,Laura,2880402342344,f,02-04-1987, Brasov,Brasov,Romania); drop table cursuri; create table cursuri( cod_curs integer constraint cursuri_pk primary key, den_curs varchar2(30) not null, tip_curs integer not null, credite integer, cod_profesor integer not null); insert into cursuri values (1, Design patterns,2, 6, 1); insert into cursuri values (2, SGBD (MySQL, Oracle),1, 5, 1); insert into cursuri values

121

(3, Inginerie software,1, 6, 2); insert into cursuri values (4, POO 2,1, 6, 2); insert into cursuri values (5, Algoritmica,1, 6, 3); insert into cursuri values (6, Algoritmica grafurilor,1, 4, 3); insert into cursuri values (7, Programare C#,1, 5, 4); insert into cursuri values (8, Inteligenta artificiala,1, 4, 4); insert into cursuri values (9, Programare procedurala,1, 6, 5); insert into cursuri values (10, Optimizare combinatorie,1, 3, 6); drop table inrolari; create table inrolari( cod_inrolare integer constraint inrolari_pk primary key, nrmatricol integer not null, cod_curs integer not null, data_inrolare date not null); insert into (1, 101, 7, insert into (2, 101, 1, insert into (3, 102, 8, insert into (4, 102, 2, insert into (5, 102, 9, insert into (6, 103, 3, insert into (7, 104, 8, insert into (8, 105, 2, insert into (9, 107, 1, inrolari values 03-09-2007); inrolari values 09-09-2007); inrolari values 14-09-2007); inrolari values 03-09-2007); inrolari values 08-09-2007); inrolari values 14-09-2007); inrolari values 07-09-2007); inrolari values 09-09-2007); inrolari values 03-09-2007);

122

insert into inrolari values (10, 107, 3, 12-09-2007); insert into inrolari values (11, 108, 2, 08-09-2007); insert into inrolari values (12, 108, 9, 08-09-2007); insert into inrolari values (13, 109, 8, 13-09-2007); insert into inrolari values (14, 110, 7, 14-09-2007); insert into inrolari values (15, 110, 4, 14-09-2007); drop table note; create table note( cod_nota integer constraint note_pk primary key, cod_inrolare integer not null, nota integer not null, data date not null); insert into note values (1, 1, 8, 10-01-2008); insert into note values (2, 1, 10, 20-01-2008); insert into note values (3, 2, 3, 12-01-2008); insert into note values (4, 3, 6, 14-01-2008); insert into note values (5, 4, 9, 16-01-2008); insert into note values (6, 6, 7, 12-01-2008); insert into note values (7, 7, 4, 14-01-2008); insert into note values (8, 7, 8, 12-01-2008); insert into note values (9, 8, 9, 10-01-2008); insert into note values (10, 10, 3, 14-01-2008); insert into note values

123

(11, 10, 5, insert into (12, 12, 7, insert into (13, 13, 4, insert into (14, 14, 3, insert into (15, 14, 4,

16-01-2008); note values 13-01-2008); note values 08-01-2008); note values 10-01-2008); note values 20-01-2008);

Vom executa acest script dup ce ne vom conecta la serverul de baze de date folosin a contul nostru. Rularea scriptului se va face prin comanda: @ cale\script.sql

6.2.2

Exemple de interogri a

principiu, multe din lucrurile care mergeau MySQL ramn valabile i cazul In n a s n Oracle. Acestea ind spuse, prezentm mai multe exemple care vor comentate suplimentar a msura care este nevoie. n a n S se aeze pentru toti studentii, numele i prenumele lor: a s s SELECT ROWNUM, ROWID, nume, prenume FROM studenti; ROWNUM returneaz numrul a a nregistrrii, iar ROWID ne arat un identicator unic a a al oricrei a nregistrri din baza de date. a S se calculeze 23*12. a SELECT 23*12 FROM dual; Pentru a putea face un calcul i a aa rezultatul, trebuie s folosim clauza FROM. s s a Special pentru aceste situatii este creat tabela dual. a S se aeze data curenta i utilizatorul curent. a s s SELECT SYSDATE, USER FROM dual; S se aeze data obtinut prin adunarea a 2 zile la data curent. a s a a 124

SELECT SYSDATE+2 FROM dual; S se aeze cte zile mai sunt pn la 1 iunie 2010: a s a a a SELECT TO_DATE(01-06-2010)-SYSDATE FROM dual; S se aeze numele i prenumele studentilor concatenate. a s s SELECT nume || || prenume AS "Nume student" FROM studenti; Se folosete || pentru a concatena valori. s S se aeze toate datele despre profesorii care au data naterii cu valoarea NULL. a s s SELECT * FROM profesori WHERE datan IS NULL; Si Oracle avem cam aceeai comparatori ca i cazul MySQL: =, <, >, <>, !=, n s s n <=, >=. La fel ca cazul MySQL putem folosi cuvintele cheie ANY, SOME i ALL n s cu exact aceeai semnicatie. Si Oracle avem operatorii SQL LIKE, IN, BETWEEN s n i IS NULL. s S se aeze toti studentii care s-au inscris la un curs i cursul la care s-au inscris: a s s SELECT nume, prenume, cod_curs FROM studenti s, inrolari i WHERE s.nrmatricol=i.nrmatricol; Aceeai interogare ca precedenta doar c vrem s vedem i studentii care nu s-au inscris s a a s la nici un curs: SELECT nume, prenume, cod_curs FROM studenti s, inrolari i WHERE s.nrmatricol=i.nrmatricol(+); De remarcat caracterul + ntre paranteze, trecut de partea care avem entitatea care n nu poate NULL (am reprezentat un LEFT JOIN). Analog, puteam avea un RIGHT JOIN dac aveam + partea stng. Nu se poate cu aceast notatie s avem FULL a n a a a a JOIN. 125

Interogrile precedente respect sintaxa ANSI SQL/86. Se poate folosi Oracle i a a n s sintaxa SQL/92, care folosete INNER JOIN, LEFT JOIN, RIGHT JOIN i FULL s s JOIN. Nu mai prezentm exemple deoarece modul de lucru este acelai ca i cazul a s s n MySQL. S se aeze studentul care are un numr matricol citit de la tastatur: a s a a select nume, prenume from studenti where nrmatricol=&nrmat; Se pot deni noi variabile cu DEFINE: DEFINE nrmat=106; Se pot vedea toate variabilele denite cu DEFINE: DEFINE O variabil poate resetat folosind UNDEFINE: a a UNDEFINE nrmat; Se pot face citiri, folosind ACCEPT, care are urmtoarea form: a a ACCEPT variable name [type] [FORMAT format] [PROMPT prompt] [HIDE] Iat i nite exemple: as s ACCEPT nrmat NUMBER FORMAT 999 PROMPT Nr matricol: ACCEPT data DATE FORMAT DD-MON-YYYY PROMPT Date: ACCEPT parola CHAR PROMPT Parola: HIDE Un script poate primi anumiti parametri. Iat un exemplu: a SELECT * FROM studenti WHERE nrmatricol=&1; Acest script ar putea apelat folosind urmtoarea instructiune: a @script.sql 105 Si Oracle, la fel ca MySQL se pot face subinterogri folosind IN i EXISTS. De n n a s asemenea, puteam avea subinterogri corelate i putem folosi UNION, UNION ALL, a s INTERSECT i MINUS. s 126

S se aeze pentru ecare student dac e localnic sau nu. a s a SELECT nume, prenume,CASE oras WHEN Brasov THEN localnic ELSE din alta parte END FROM studenti; S se aeze numele, prenumele i sexul pentru ecare persoana: a s s SELECT nume, prenume, CASE WHEN sex=m THEN masculin WHEN sex=f THEN feminin END FROM studenti; S se aeze pentru ecare ora, cte persoane sunt din acel ora, precum i pe ce loc a s s a s s s-ar clasa oraul din acest punct de vedere: s SELECT oras, COUNT(*), RANK() OVER (ORDER BY COUNT(*) DESC NULLS LAST) AS rank, DENSE_RANK() OVER (ORDER BY COUNT(*) DESC NULLS LAST) AS dense_rank FROM studenti GROUP BY oras ORDER BY COUNT(*) DESC; Interogri pe tabele ierarhice a Dup cum am discutat i cazul MySQL o situatie mai deosebit o reprezint modul a s n a a n care se poate lucra cu tabele ierarhice. cazul MySQL trebuia s facem o mic improvizatie In a a pentru a putea lucra cu ele. Lucrurile sunt mult mai simple cazul Oracle, deoarece acesta are clauzele CONNECT n BY i START WITH care ne ajut astfel de situatii. s a n Sintaxa acestei interogri este urmtoarea: a a SELECT [LEVEL], column, expression,... FROM table [WHERE where_clause] [[START WITH start_condition][CONNECT BY PRIOR prior_condition]]; Prezentm continuare modul care se poate lucra cu acestea: a n n 127

/* creare tabel */ create table categorii( categ_id integer not null constraint categ_pk primary key, den_categ varchar2(20) not null, parent_id integer); /* inserare insert into insert into insert into insert into insert into insert into insert into insert into informatii */ categorii values(1,categ1,null); categorii values(2,categ11,1); categorii values(3,categ12,1); categorii values(4,categ121,3); categorii values(5,categ122,3); categorii values(6,categ123,3); categorii values(7,categ111,2); categorii values(8,categ112,2);

/* toate categoriile */ select * from categorii; /* parcurgere in adancime */ select categ_id, parent_id, den_categ from categorii start with categ_id=1 connect by prior categ_id=parent_id; /* parcurgere in latime */ select categ_id, parent_id, den_categ, LEVEL from categorii start with categ_id=1 connect by prior categ_id=parent_id order by level asc; /* numarul de nivele incepand de la angajatul cu id-ul 1 */ select count(distinct level) from categorii start with categ_id=1 connect by prior categ_id= parent_id; /* Formatarea afisarii */ select categ_id, level, lpad( ,3*level-1) || den_categ

128

as "Categorie" from categorii start with categ_id=1 connect by prior categ_id= parent_id; /* afisarea tuturor parintilor unei categorii */ select level, den_categ from categorii start with categ_id=7 connect by prior parent_id= categ_id; /* afisarea tuturor inregistrarilor formatat pe nivele, fara nodul 2 si descendentii lui */ select categ_id, level, lpad( ,3*level-1) || den_categ as "Categorie" from categorii start with categ_id=1 connect by prior categ_id= parent_id and categ_id!=2;

129

130

Capitolul 7 Crearea obiectelor bazei de date


7.1 Lucrul cu tabele

O tabel se poate crea folosind instructiunea CREATE TABLE care are forma simplia cat urmtoare: a a CREATE [GLOBAL TEMPORARY] TABLE table_name ( column_name type [CONSTRAINT constraint_def DEFAULT default_exp] [, column_name type [CONSTRAINT constraint_def DEFAULT default_exp] ...] ) [ON COMMIT DELETE | PRESERVE ROWS] TABLESPACE tab_space; Dac se folosete GLOBAL TEMPORARY acest lucru semnic faptul c se lucreaz cu o a s a a a tabel temporar. Ea va pstrat pn la sfritul tranzactiei dac este ales ON COMMIT a a a a a a as a DELETE ROWS i pn la sfritul sesiunii dac se alege ON COMMIT PRESERVE ROWS. s a a as a Nu insistm mai mult asupra celorlalate componente pentru c ele sunt exact ceea ce a a ne-am atepta din experienta folosind MySQL. s Pentru a putea aa informatii despre tabele putem efectua urmtoarele instructiuni: a /* vizualizarea informatiilor despre tabela studenti */ DESCRIBE studenti; /* vizualizarea tuturor tabelelor utilizatorului curent */ SELECT table_name, tablespace_name FROM user_tables; Asemntor cu modul care se poate modica un tabel MySQL se poate face acelai a a n n s lucru Oracle folosind instructiunea ALTER TABLE ca exemplele urmtoare: n n a ALTER TABLE studenti ADD created DATE DEFAULT SYSDATE NOT NULL; 131

De asemenea, pentru tabele se pot stabili diferite constrngeri ca exemplele urmtoare: a n a /* constrangere dupa creare tabel */ ALTER TABLE studenti ADD CONSTRAINT sex_ck CHECK (sex IN (f,m)); /* constrangere la creare tabel */ create table profesori( cod_prof integer constraint profesori_pk primary key , nume varchar2(30) not null, prenume varchar2(30) not null, grad varchar2(30) not null, sex char(1) not null check (sex in (f,m)), datan date ); /* specificare cheie straina la creare tabel */ create table inrolari( cod_inrolare integer constraint inrolari_pk primary key, nrmatricol integer not null constraint nrmatricol_fk references studenti(nrmatricol) on delete cascade, cod_curs integer not null, data_inrolare date not null); Atunci cnd se specic o cheie strin, cazul care se terge o a a a a n n s nregistrare din tabela studenti, se poate ampla unul din urmtoarele lucruri: nt a dac nu se specic nimic altceva a a nregistrarea nu va putea tears s a dac se specic ON DELETE CASCADE sunt terse automat a a s nregistrrile corea spunztoare din tabela inrolari a dac se specic ON DELETE SET NULL automat unde apare cheia studentului ters, a a s aceasta este nlocuit cu NULL. a Si specicarea faptului c un anumit cmp nu poate avea valoarea NULL este de asemenea a a o constrngere i ar putea primi i ea un nume la fel ca orice constrngere. a s s a Observatie: O tabel nu poate tears dac are o cheie primar care este legat de o a s a a a a cheie strin printr-o constrngere ??? a a a Pentru o tabel se mai pot face mai multe operatii, precum: a /* redenumirea tabelei */ 132

RENAME studenti TO students; /* stergerea tuturor inregistrarilor si resetarea zonei de memorie */ TRUNCATE TABLE studenti; /* stergerea unei tabele */ DROP TABLE studenti;

7.2

Lucrul cu secvente

Crearea unei secvente se poate face folosind CREATE SEQUENCE: CREATE SEQUENCE sequence_name [START WITH start_num] [INCREMENT BY increment_num] [ MAXVALUE maximum_num | NOMAXVALUE [ MINVALUE minimum_num | NOMINVALUE [ CYCLE | NOCYCLE ] [ CACHE cache_num | NOCACHE ] [ ORDER | NOORDER ];

] ]

Semnicatiile unora din aceste valori sunt: CYCLE - dup ce se ajunge la valoarea maxim se re a a ncepe cu valoarea minim; a NOCACHE - nu se prealoc numere de ctre BD, astfel nu vom avea numere nefolosite a a cnd se oprete baza de date, dar este mai neecient; a s s start num i increment num au implicit valoarea 1. Iat i nite exemple de creare de secvente i folosire a lor: as s s CREATE SEQUENCE s_studenti; CREATE SEQUENCE s_test START WITH 10 INCREMENT BY 5 MINVALUE 10 MAXVALUE 1000 CYCLE CACHE; /* obtinerea urmatoarei valori a secventei */ SELECT s_test.NEXTVAL FROM dual; /* se poate popula o inregistrare si 133

folosind secvente in mod direct */ INSERT INTO tipuri_curs (tip_curs, den_tip) VALUES(s_test.NEXTVAL, la alegere); /* stergerea unei secvente */ DROP SEQUENCE s_test;

7.3

Lucrul cu indeci s

Este bine s se creeze indei pentru acele coloane care au valori de preferinta unice i a s s n plus care au valori ct mai variate dac nu unice. a a Este bine s se foloseasc indecii pentru acele interogri care numrul de a a s a n a nregistrri a returnate este mai mic dect 10% din numrul de a a nregistrri din tabel. a a Un index se poate crea folosind o instructiune de forma urmtoare: a CREATE [UNIQUE] INDEX index_name ON table_name(column_name[, column_name ...]) TABLESPACE tab_space; Un exemplu de creare i de tergere a unui index este urmtorul: s s a CREATE UNIQUE INDEX i_cnp_studenti ON studenti(cnp); DROP INDEX i_cnp_studenti; Se poate ampla s avem indeci care s functioneze pe baza unor functii: nt a s a CREATE INDEX i_nume_studenti ON studenti(UPPER(nume)); /* pentru a putea fi folosit, trebuie ca administratorul sa faca urmatoarea operatie */ ALTER SYSTEM SET QUERY_REWRITE_ENABLED=TRUE; Putem vedea indecii corespunztori unei tabele: s a SELECT index_name, table_name, uniqueness, status FROM user_indexes WHERE table_name=studenti ORDER BY index_name; Pentru tabelele care avem o coloan care are putine valori i acelai timp au foarte n a s n s multe nregistrri se pot folosi bitmap indexes. a Un astfel de index poate creat astfel: CREATE BITMAP INDEX i_sex_studenti ON studenti(sex); 134

7.4

Lucrul cu view-uri

View-urile sunt nite interogri care sunt deja salvate. Datele dintr-un view pot pot s a accesate la fel ca dintr-un tabel. unele view-uri se pot face i operatii INSERT, UPDATE In s i DELETE. s Un view se poate crea printr-o instructiune precum urmtoarea: a CREATE [OR REPLACE] VIEW [FORCE | NOFORCE] VIEW view_name [(alias_name[, alias_name ...])] AS subquery [WITH CHECK OPTION | READ ONLY CONSTRAINT constraint_name]; Semnicatiile ctorva din optiuni sunt: a FORCE - view-ul va creat chiar dac tabelele de baz specicate nu exist; a a a subquery - interogarea care aduce date din tabele sau alte view-uri; WITH CHECK OPTION - numai rndurile care au fost aduse de interogare pot inserate, a actualizate i terse; implicit nu este activat; s s a WITH READ ONLY - datele aduse pot doar citite nu i modicate. s Avem dou tipuri de view-uri: a View-uri simple (pe baza unei interogri care folosete o singur tabel de baz) a s a a a View-uri complexe (pe baza mai multor tabele, sau folosind GROUP BY i/ sau DISs TINCT sau care contin apeluri de funtii. Un view se construiete foarte simplu ca exemplele urmtoare: s n a CREATE VIEW studenti_brasov_view AS SELECT * FROM studenti WHERE oras=Brasov; CREATE VIEW studenti_brasov_view AS SELECT * FROM studenti WHERE oras=Brasov WITH CHECK OPTION CONSTRAINT brasov_students; /* un view in care nu se pot modifica date */ CREATE VIEW studenti_brasov_view AS SELECT * FROM studenti WHERE oras=Brasov WITH READ ONLY CONSTRAINT brasov_students; 135

Se pot face insert-uri, update-uri i delete-uri numai pentru view-uri simple. s Modicarea unui view se poate face folosind CREATE OR REPLACE VIEW ca n exemplul urmtor: a CREATE OR REPLACE VIEW studenti_brasov_view AS SELECT * FROM studenti WHERE oras=Brasov; Un view poate ters folosind DROP VIEW: s DROP VIEW studenti_brasov_view;

7.5

Utilizatori i securitate s

Pentru a crea un utilizator se poate executa urmtoarea instructiune SQL: a CREATE USER user_name IDENTIFIED BY password [DEFAULT TABLESPACE def_tablespace] [TEMPORARY TABLESPACE temp_tablespace]; Pentru a putea schimba parola unui utilizator: ALTER USER user_name IDENTIFIED BY password; De asemenea, parola unui utilizator poate schimbat SQL*Plus, folosind comanda a n PASSWORD. Stergerea unui utilizator se poate face cu comanda: DROP USER user_name; Oracle se pot acorda dou tipuri de drepturi: In a roluri - precum CONNECT i RESOURCE (ele se pot da mai departe dac au fost s a acordate cu WITH ADMIN OPTION) privilegii - precum CREATE TABLE, SELECT, INSERT, etc. (ele pot date mai departe dac au fost acordate cu WITH GRANT OPTION). a Un utilizator poate s fac mai multe interogri referitoare la privilegiile sale: a a a /* vizualizarea tuturor privilegiilor sistem */ SELECT * FROM user_sys_privs ORDER BY privilege; /* vizualizarea privilegiilor utilizatorului 136

asupra tabelei nume_tabela */ SELECT * FROM user_tab_privs_made WHERE table_name=nume_tabela; /* vizualizarea rolurilor unui utilizator */ SELECT * FROM user_role_privs; Acordarea de drepturi se poate face la fel ca i cazul MySQL cu ajutorul comenzii s n GRANT. Revocarea drepturilor se face cu REVOKE ntr-un mod asemntor. a a Oracle se pot crea roluri. Acestor roluri li se pot acorda diverse drepturi. Ele reprezint In a un mod de a partaja comportament comun ntre utilizatori, ind mai uor s se acorde nite s a s drepturi unui rol, i apoi s se acorde acel rol mai multor utilizatori, dect s se acorde s a a a drepturile ecrui utilizator parte. a n O secvent care ilustreaz aceste lucruri este urmtoarea (mihai este un utilizator care a a a deja exist): a CREATE ROLE manager; GRANT SELECT, INSERT, UPDATE, DELETE ON baza.* TO manager; GRANT CREATE USER TO user; GRANT manager TO mihai;

137

138

Capitolul 8 Crearea obiectelor procedurale


8.1 Programarea PL/SQL

Denumirea de PL/SQL vine de la Programming Language/SQL. Acest limbaj a fost adugat a odat cu versiunea 6 a Oracle i permite scrierea de programe folosind SQL i accesarea lor, a s s att din aplicatiile client specializate pentru lucrul cu Oracle ct i din programe Java sau a a s C#. Programele PL/SQL sunt organizate pe blocuri care au urmtoarea structur: a a [DECLARE declaration_statements ] BEGIN executable_statements [EXCEPTION exception_handling_statements ] END; / Un astfel de exemplu de script care poate rulat i din SQL Developer cu F5 sau Run s script este: SET SERVEROUTPUT ON DECLARE a INTEGER :=5; b INTEGER :=2; c INTEGER; BEGIN c:=a*b; DBMS_OUTPUT.PUT_LINE(Rezultat = || c); EXCEPTION 139

WHEN ZERO_DIVIDE THEN DBMS_OUTPUT.PUT_LINE(Division by zero); END; / Acest script ar putea rulat i din SQL*Plus, folosind operatorul @. s

8.1.1

Structuri conditionale i repetitive s

Pentru lucrul aceste programe PL/SQL, se pot folosi urmtoarele structuri conditionale n a i repetitive: s

IF condition1 THEN statements1 ELSIF condition2 THEN statements2 ELSE statements3 END IF; ---------LOOP statements EXIT WHEN cond; END LOOP; /* se pot folosi CONTINUE WHEN cond; sau IF cond THEN CONTINUE; END IF; */ ---------WHILE condition LOOP statements END LOOP; ---------FOR loop_variable IN [REVERSE] lower_bound..upper_bound LOOP statements END LOOP; 140

8.1.2

Cursoare

La fel ca cazul MySQL, i Oracle se pot folosi cursoare. Iat un exemplu (trebuie n s n a precizat c modul de lucru este foarte asemntor): a a a SET SERVEROUTPUT ON DECLARE -- declarare variabile v_nrmatricol studenti.nrmatricol% TYPE; v_nume studenti.nume%TYPE; v_prenume studenti.prenume%TYPE; -- declarare cursor CURSOR v_studenti_cursor IS SELECT nrmatricol, nume, prenume FROM studenti ORDER BY nume, prenume; BEGIN -- deschidere cursor OPEN v_studenti_cursor; LOOP -- obtinerea de inregistrari cu ajutorul cursorului FETCH v_studenti_cursor INTO v_nrmatricol, v_nume, v_prenume; EXIT WHEN v_studenti_cursor%NOTFOUND; DBMS_OUTPUT.PUT_LINE( v_nrmatricol = || v_nrmatricol || , v_nume = || v_nume || , v_prenume = || v_prenume ); END LOOP; -- inchiderea cursorului CLOSE v_studenti_cursor; END; / Acelai lucru se poate face i folosind un cursor precum i structura repetitiv FOR: s s s a SET SERVEROUTPUT ON DECLARE CURSOR v_studenti_cursor IS SELECT nrmatricol, nume, prenume FROM studenti ORDER BY nume, prenume; BEGIN FOR v_student IN v_studenti_cursor LOOP 141

DBMS_OUTPUT.PUT_LINE( nrmatricol = || v_student.nrmatricol || , nume = || v_student.nume || , prenume = || v_student.prenume ); END LOOP; END; /

Dup cum am putut vedea exemplele precedente se poate ampla s apar exceptii a n nt a a momentul care se ruleaz un program. Oracle exist numeroase exceptii precum: ACn n a In a CESS INTO NULL, CASE NOT FOUND, COLLECTION IS NULL, CURSOR ALREADY OPEN, DUP VAL ON INDEX, INVALID CURSOR, INVALID NUMBER, LOGIN DENIED, NO DATA FOUND NOT LOGGED ON, PROGRAM ERROR, ROWTYPE MISMATCH, SELF IS NULL, STORAGE ERROR, SUBSCRIPT BEYOND COUNT, TIMEOUT ON RESOURCE, TOO MANY ROWS, VALUE ERROR, ZERO DIVIDE i OTHERS (pentru a prinde toate exceptiile posibile). s

8.2

Proceduri stocate

O procedur stocat contine interogri SQL i comenzi PL/SQL. Ele permit accesul a a a s centralizat la server i partajarea de comportament s ntre diverse aplicatii. O procedur stocat se poate crea conform urmtoarei sintaxe: a a a CREATE [OR REPLACE] PROCEDURE procedure_name [(parameter_name [IN | OUT | IN OUT] type [, ...])] IS | AS BEGIN procedure_body END procedure_name; Iat, continuare o procedur stocat: a n a a CREATE OR REPLACE PROCEDURE test(a in integer, b out integer) AS BEGIN b:=a+1; END test; / Ea poate apelat din linie de comand astfel: a a variable x number; call test(3,:x); print :x; Un exemplu mai complex este urmtorul: a 142

CREATE PROCEDURE update_studenti_nume( nrmat IN studenti.nrmat%TYPE, localitate IN studenti.localitate%TYPE ) AS studenti_count INTEGER; BEGIN SELECT COUNT(*) INTO studenti_count FROM studenti WHERE nrmatricol = nrmat; IF studenti_count = 1 THEN UPDATE studenti SET oras=localitate WHERE nrmatricol=nrmat; COMMIT; END IF; EXCEPTION WHEN OTHERS THEN ROLLBACK; END update_studenti_nume; / Se poate terge o procedur folosind instrutiunea DROP PROCEDURE: s a DROP PROCEDURE test; Dac momentul care se compileaz o procedur stocat se ampl s apar erori, a n n a a a nt a a a acestea pot vzute folosind instructiunea SHOW ERRORS. a

8.3

Lucrul cu functii

O funtie este foarte asemntoare uneo proceduri stocate, cu exceptia faptului c ea a a a returneaz un rezultat. a O sintax simpl pentru crearea unei functii este urmtoarea: a a a CREATE [OR REPLACE] FUNCTION function_name [(parameter_name [IN | OUT | IN OUT] type [, ...])] RETURN type IS | AS BEGIN function_body END function_name; 143

Prezentm, continuare o functie care calculeaz cel mai mare divizor comun a dou a n a a numere, transmise ca parametri: CREATE OR REPLACE FUNCTION cmmdc (a IN NUMBER, b IN NUMBER) RETURN NUMBER AS x INTEGER := a; y INTEGER := b; r INTEGER; BEGIN WHILE y<>0 LOOP r:=MOD(x,y); x:=y; y:=r; END LOOP; RETURN x; END cmmdc; / Functia ar putea apelat cu o instructiune de genul: a SELECT cmmdc(27,18) FROM dual; Evident, se pot construi functii mult mai complexe i care s contin instructiuni SQL. s a a O funtie poate tears cu instructiunea DROP FUNCTION: s a DROP FUNCTION cmmdc;

8.4

Lucrul cu pachete

Procedurile i functiile se pot grupa pachete. acest fel ne putem crea propriile s n In librarii pe care alti utilizatori le pot reutiliza protnd de avantajul modularizrii. a a Un astfel de pachet are o parte de specicatie i o parte care sunt descrise functii, s n partea de specicatie sunt descrise acele obiecte proceduri, tipuri noi de date i obiecte. In s care dorim s e publice. Cele care nu apar partea de specicatie sunt sunt considerate a n private. Se poate crea un package folosind urmtoarea instructiune simplicat: a a CREATE [OR REPLACE] PACKAGE package_name IS | AS package_specification END package_name; 144

Un exemplu de creare a unui package este urmtorul (dup cum se poate vedea se scrie a a doar specicarea pachetului): CREATE PACKAGE student_package AS TYPE t_ref_cursor IS REF CURSOR; FUNCTION get_studenti_ref_cursor RETURN t_ref_cursor; PROCEDURE update_studenti_nume( nrmat IN studenti.nrmat%TYPE, localitate IN studenti.localitate%TYPE ); END product_package; / Pentru a seta corpul pachetului se folosete o instructiune precum urmtoarea: s a CREATE [OR REPLACE] PACKAGE BODY package_name IS | AS package_body END package_name; Iat i un exemplu pentru pachetul denit anterior: as CREATE PACKAGE BODY student_package AS FUNCTION get_studenti_ref_cursor RETURN t_ref_cursor IS v_students_ref_cursor t_ref_cursor; BEGIN OPEN v_students_ref_cursor FOR SELECT nrmatricol, nume, prenume FROM studenti; RETURN v_students_ref_cursor; END get_studenti_ref_cursor; PROCEDURE update_studenti_nume( nrmat IN studenti.nrmat%TYPE, localitate IN studenti.localitate%TYPE ) AS studenti_count INTEGER; BEGIN SELECT COUNT(*) INTO studenti_count FROM studenti 145

WHERE nrmatricol = nrmat; IF studenti_count = 1 THEN UPDATE studenti SET oras=localitate WHERE nrmatricol=nrmat; COMMIT; END IF; EXCEPTION WHEN OTHERS THEN ROLLBACK; END update_studenti_nume; END student_package; / Pentru a apela procedurile i functiile dintr-un pachet se va folosi aceeai sintax ca i s s a s n cazul procedurilor i funtiilor normale, doar c denumirea functiei sau procedurii trebuie s a n adugat denumirea pachetului urmat de caracterul .. a a a EXEMPLU!!!! Pentru a vedea toate metodele i functiile dint-un pachet se poate scrie urmtoarea s a instructiune SQL: SELECT object_name, procedure_name FROM user_procedures WHERE object_name = nume_pachet; Un pachet poate ters folosind instructiunea DROP PACKAGE: s DROP PACKAGE nume_package;

8.5

Lucrul cu triggere

Un trigger este o procedur care se produce automat atunci cnd asupra unei anumite a a tabele se produce o instructiune de genul INSERT, UPDATE sau DELETE. Trigger-ul se poate produce nainte sau dup instructiunea care se produce i se poate a s executa cte o dat pentru ecare a a nregistrare afectat sau o dat pentru toate (dac sunt a a a afectate mai multe nregistrri). a Un trigger la nivel de rnd poate accesa vechile i noile valori din anumite cmpuri, a s a n timp ce un trigger pentru mai multe nregistrri nu are acest drept. De asemenea, cazul a n care avem un trigger la nivel de n nregistrare se poate s avem o conditie care s limiteze a a aparitia triggerului. Se poate crea un trigger cu urmtoarea sintax: a a 146

CREATE [OR REPLACE] TRIGGER trigger_name {BEFORE | AFTER | INSTEAD OF | FOR} trigger_event ON table_name [FOR EACH ROW] [{FORWARD | REVERSE} CROSSEDITION] [{FOLLOWS | PRECEDES} schema.other_trigger} [{ENABLE | DISABLE}] [WHEN trigger_condition]] BEGIN trigger_body END trigger_name; Semnicatiile cuvintelor cheie mai deosebite sunt: INSTEAD OF - triggerul se va produce locul evenimentului urmrit n a FOR EACH ROW - nseamn ca trigger-ul va la nivel de a nregistrare, apelndu-se pentru a ecare nregistrare afectat de operatia urmrit a a a {ENABLE | DISABLE} - specic dac triggerul este activat sau nu a a a a ndeplinit conditia. a WHEN trigger condition - triggerul se apeleaz numai cnd este Un exemplu de trigger este prezentat continuare: n CREATE TRIGGER before_studenti_localitate_update BEFORE UPDATE OF localitate ON studenti FOR EACH ROW WHEN (new.localitate =brasov) BEGIN dbms_output.put_line(nr_mat = || :old.nrmatricol); dbms_output.put_line(Vechea localitate = || :old.localitate); dbms_output.put_line(Noua localitate = || :new.localitate);

INSERT INTO modif_stud_localitate ( nrmatricol, localitate_veche, localitate_noua ) VALUES ( :old.nrmatricol, :old.localitate, :new.localitate ); END modif_stud_localitate; / Triggerul s-ar apela urma unei instructiuni de genul: n 147

UPDATE studenti SET localitate=Timisoara WHERE nrmatricol IN (104, 108); Un trigger poate activat/dezactivat cu una din metodele: ALTER TRIGGER trigger_name ENABLE; ALTER TRIGGER trigger_name DISABLE; Un trigger poate ters printr-o instructiune DROP TRIGGER: s DROP TRIGGER trigger_name; Triggerele pot folosite pentru a crea o coloan autoincrement a ntr-o tabel, ca exa n emplul urmtor: a CREATE table "PERSOANE" ( "PERS_ID" NUMBER, "NUME" VARCHAR2(20), "PRENUME" VARCHAR2(20), constraint "PERSOANE_PK" primary key ("PERS_ID") ); CREATE sequence "PERSOANE_SEQ"; CREATE trigger "BI_PERSOANE" before insert on "PERSOANE" for each row begin select "PERSOANE_SEQ".nextval into :NEW.PERS_ID from dual; end;

8.6

Tranzactii i lucrul s ntr-un mediu multiuser

La fel ca i cazul MySQL semnalm terminarea unei tranzactii folosind COMMIT i s n a s refacerea instructiunilor din tranzactia curent prin ROLLBACK. a O tranzactie Oracle n ncepe una din urmtoarele 2 situatii: n a cnd ne conectm la o baz de date i facem o interogare; a a a s cnd s-a terminat o tranzactie i am executat o interogare. a s O tranzactie se termin cnd: a a am executat COMMIT sau ROLLBACK; 148

am executat o instructiune CREATE TABLE; am executat o instructiune GRANT; cnd ne deconectm de la server. a a Si Oracle exist conceptul de savepoint: n a SAVEPOINT save1; ... ROLLBACK TO SAVEPOINT save1; Dup cum am artat ceea ce privete MySQL exist 4 nivele de izolare: a a n s a READ UNCOMMITTED (nu este implementat Oracle) n READ COMMITTED (este setat implicit Oracle) n REPEATABLE READ (nu este implementat Oracle) n SERIALIZABLE (este implementat Oracle) n Nivelul de izolare se poate preciza prin instructiunea urmtoare: a SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

149

S-ar putea să vă placă și