Sunteți pe pagina 1din 47

BAZE DE DATE

III.
III.3.1. III.3.2. III.3.3.

SQL (continuare)
(vezi CD din semestrul I) (vezi CD din semestrul I)

Interogarea datelor

Interogarea datelor din mai multe relaii Funcii utilizate n interogri Inserarea datelor

(vezi CD din semestrul I)

III.3.4.

Inserarea datelor reprezint, alturi de modificarea i tergerea datelor, comenzi de actualizare a datelor din baza de date specifice limbajelor relaionale de manipulare a datelor (LMD). Inserarea datelor permite adugarea de tupluri la o relaie, tupluri care pot fi furnizate din afara bazei de date sau pot fi construite cu ajutorul datelor aflate deja n baza de date. Instruciunea INSERT INTO...VALUES... Sintaxa INSERT INTO Nume_tabela (Cmp_1,Cmp_2,...,Cmp_n) VALUES (Val_1,Val_2,...,Val_n); insereaz valorile Val_1,Val_2,...,Val_n ntr-o relaie Nume_tabela care are atributele Cmp_1, Cmp_2,...,Cmp_n. Observaii: 1. Ordinea atributelor Cmp_1, Cmp_2,...,Cmp_n este arbitrar, ns este indicat ca primele atribute s fie cheile primare ale relaiilor. 2. Fiecrui atribut specificat trebuie s i corespund o valoare Val_i care va fi introdus n cmpul respectiv Cmp_i. Domeniile atributelor trebuie s fie compatibile cu tipurile valorilor introduse. Astfel, ntr-un atribut de tip numeric trebuie s se introduc un numr raional etc. 3. Valorile actualizate prin fraze INSERT trebuie s in cont de constrngerile existente. 4. n cadrul listei de valori din a doua parantez, irurile de valori se introduc n ghilimele. Numerele ntregi nu trebuie puse ntre ghilimele. Exemplul 1: S se introduc urmtoarele informaii pentru clientul Avram Bogdan cu cnp 1650721978721: adresa Str. Viilor, nr.4A, bl. 44C, ap. 4, Hunedoara, jud. Hunedoara, telefon 0726100345, email avram@gmail.com, numrul de cont bancar 261028577Y010 corespunztor bncii BCR. INSERT INTO DATE_PERSOANA (cnp, numele, adresa, nr_telefon, email, banca_client, nr_cont_client) 1

VALUES (1650721978721,Avram Bogdan,Str. Viilor, nr.4A, bl. 44C, ap. 4, Hunedoara, jud. Hunedoara, 0726100345, avram@gmail.com,'BCR', '261028577Y010'); Dac o instruciune folosete toate cmpurile tabelului, acestea pot fi omise din specificarea lor: INSERT INTO DATE_PERSOANA VALUES (1650721978721, Avram Bogdan, Str. Viilor, nr.4A, bl. 44C, ap. 4, Hunedoara, jud. Hunedoara, 0726100345, avram@gmail.com,'BCR', '261028577Y010'); n urma executrii frazei INSERT se primete un mesaj de confirmare a inserrii 1 row(s) affected. Erorile posibile n urma execuiei frazei INSERT sunt: - erori de securitate (nu avem dreptul s modificm relaia); - erori de conversie (inserarea unui text n dreptul unei coloane definite ca numeric); - erori de constrngere (nclcri ale unor asocieri ntre dou relaii etc); - erori de sintax. n continuare se vor prezenta cteva exemple de erori. Eroarea datorat ncercrii de a insera o valoare deja existent ntr-un cmp care este cheie primar (posed unicitate).

Exemplu: Inserai descrierea imobilului ofert cu id-ul 1, clientul punnd n vnzare un apartament cu 2 camere, suprafaa de 5000 metrii ptrai, etaj 2, fr garaj, cu central termic i fr termopane. (Pentru a insera aceste date trebuie menionate cteva date specifice relaiei DESCRIERE_IMOBIL din baza de date AGENTIE_IMOBILIARA i anume: cmpurile buleene 'garaj, centrala_termica, termopane se completeaz cu valoarea 0 n caz negativ, respectiv cu valoarea 1 n caz afirmativ.) INSERT INTO DESCRIERE_ IMOBIL (id_co, tip_imobil,etaj, nr_camere, suprafata, garaj, centrala_termica, termopane) VALUES (1,apartament,2,2,5000,0,1,0); n urma execuiei frazei INSERT apare eroarea: Duplicate entry 1 for key 1, adic cheia primar id_co a fost violat, n BD existnd deja o nregistrare n dreptul cheii cu numrul 1. Soluionarea corect a problemei presupune determinarea urmtoarei valori a identificatorului id_co din relaia DESCRIERE_IMOBIL, identificator care se gsete declarat deja n relaia printe CERERI_OFERTE. Aceasta se realizeaz prin interogarea urmtoare: SELECT MAX(id_co)+1 AS next_id FROM DESCRIERE_IMOBIL;

Fig.III.3.4.1.

Vizualizarea urmtoarei valori a identificatorului id_co 2

Asrfel: INSERT INTO DESCRIERE_ IMOBIL (id_co, tip_imobil,etaj, nr_camere, suprafata, garaj, centrala_termica, termopane) VALUES (9,apartament,2,2,5000,0,1,0); Observaie: Domeniul de definiie al atributelor garaj, centrala_termica, termopane este de tip TINYINT. Eroarea datorat nepotrivirii dintre valoarea i tipul cmpului unde se dorete inserat valoarea respectiv.

Exemplu: Inserai o nou cerere pentru clientul existent deja n baza de date Chi Gheorghe cu codul numeric personal 1670321778721, n data de 10 iulie 2006, care solicit un teren n Oradea, pe strada Aleea Clinului, cu preul cuprins ntre 200000 i 300000 (codul localitii este BH410, iar al strazii 234). SELECT MAX(id_co) AS ultimul_id FROM CERERI_OFERTE;

Fig.III.3.4.2.

Vizualizarea ultimului index din tabela CERERI_OFERTE

INSERT INTO CERERI_OFERTE (id_co, tipul, cnp, data_inreg, tip_solutionare, cod_loc, id_strada, nr_imobil, pret_min, pret_max) VALUES ( 18, cerere, 1670321778721, BH410, 0, 2006-07-10, 234, Null, 200000, 300000); n urma execuiei frazei INSERT apare eroarea Incorect data value BH410 for column data_inreg at row 1, adic s-a produs greeala la convertirea unui tip de dat calendaristic dintr-un format de tip text. Valoarea tip VARCHAR BH410 nu aparine domeniului atributului data_inreg, domeniu de tip dat calendaristic. Soluionarea corect a problemei este INSERT INTO CERERI_OFERTE (id_co, tipul, cnp, data_inreg, tip_solutionare, cod_loc, id_strada, nr_imobil, pret_min, pret_max) VALUES ( 18, 'cerere', 1670321778721, '2006-07-10', 0, 'BH410', 234, Null, 200000, 300000); Observaii: 1. Datele necunoscute se completeaz cu NULL, atunci cnd cmpul a fost menionat. n cazul n care nu sunt menionate toate cmpurile unei relaii, acestea vor fi completate automat cu valoarea NULL. 2. Exist situaii n care valorile sunt asociate greit, iar serverul nu identific neconcordana ntre tipuri, cum este cazul urmtorului exemplu: Asocierea valorii BH410 cmpului tipul va transforma tipul solicitrii din cerere n BH410, nereturnnd eroare, deoarece sunt valori de acelai tip, i anume VARCHAR(7). 3. O dat calendaristic se introduce n formatul an-luna-ziua, adic yyyy- mm-dd (exemplu: '2006-07-10'). 4. Pentru eliminarea inconvenientului de a determina mereu ultimul numr curent de nregistrare (SELECT max(nr_factura) FROM FACTURI), se poate folosi 3

autoincrementarea valorii. Aceasta nseamn c serverul MySql va introduce automat n cmp valori ntregi consecutive atunci cnd se vor insera noi tupluri n relaie. Aceasta se realizeaz prin opiunea AUTO_INCREMENT aplicat atributului numeric care poate fi declarat odat cu crearea relaiei CREATE TABLE, ct i ulterior, utiliznd comanda ALTER TABLE. Este de menionat faptul c aceast modificare se poate executa (pentru serverul MySQL5.0) doar asupra tabelelor care nu sunt relaionate cu alte tabele existente n baza de date. Astfel, pentru tabelul FACTURI n care sunt deja existente cteva date, trecerea la starea de autoincrement a atributului nr_factura se face n modul urmtor: ALTER TABLE FACTURI DROP PRIMARY KEY; ALTER TABLE FACTURI MODIFY nr_factura int(7) NOT NULL AUTO_INCREMENT, ADD PRIMARY KEY (id); Instruciunea INSERT INTO FACTURI (id_co, data_factura, cnp, pret) values (10, curdate(), 1820320223201, 10000) ; va insera n relaia FACTURI tuplul cu numrul urmtor ultimului numr de factur. n situaia n care se dorete ca autoincrementarea s nceap de la o anumit valoare, de exemplu nr_facutra s nceap de la 100, se folosete instruciunea ALTER TABLE X AUTO_INCREMENT=100; i astfel primul tuplu inserat dup executarea aceastei instruciuni va avea numrul curent de facutr 100. n cazul n care se elimin ultimul tuplu al relaiei (de exemplu factura cu numrul 100), urmtorul tuplu ce se va introduce va continua numrtoarea (nr_factura va fi egal cu 101). Eroarea datorat diferenei dintre numrul atributelor i numrul valorilor inserate.

Exemplu: Inserai informaiile cu privire la cererea lansat n data de 2006-08-26 de clienta POP VASICA, tiind c aceasta solicit un teren, cu o suprafa de 10000 metrii ptrai, n oraul Baia Mare (codul localitii este MM430). Realizai interogri pentru toate datele aferente clientului necesare inserrii n baza de date. SELECT DP.numele, DP.cnp, CO.id_co, CO.tipul, CO.cod_loc FROM DATE_PERSOANA DP, CERERI_OFERTE CO WHERE DP.numele= 'POP VASICA ' AND DP.cnp=CO.cnp AND CO.cod_loc=MM430 AND CO.data_inreg= 2006-08-26 AND CO.tipul='cerere';

Vizualizarea codului de nregistrare id_co a cererii din localitatea Baia Mare a clientei Pop Vasica Fig.III.3.4.4. INSERT INTO DESCRIERE_IMOBIL (id_co, tip_imobil, etaj, nr_camere, suprafata, garaj) VALUES (16, teren, 10000); 4

Fig.III.3.4.3.

n urma execuiei frazei INSERT apare eroarea Column count doesnt match value count at row 1 adic exist mai multe coloane dect valori specificate n clauza valorilor (6 cmpuri, 3 valori). Soluionarea corect a problemei este INSERT INTO DESCRIERE_IMOBIL (id_co, tip_imobil, etaj, nr_camere, suprafata, garaj) VALUES (16, teren, Null, Null, 10000, Null); Eroarea datorat ncercrii de a insera o valoare existent ntr-un atribut care este cheie strin (din relaia copil) i care nu are corespondent n cheia primar (din relaia printe) pe care o refer

Exemplu: Introducei strada Vasile Alecsandri din localitatea Constana. SELECT MAX(id_strada) AS ultimul_id FROM STRAZI;

Fig.III.3.4.5.

Vizualizarea ultimului id introdus n tabela STRZI

INSERT INTO STRAZI (id_strada,cod_loc,nume_str) VALUES (243,'CT701', Vasile Alecsandri); Executarea frazei insert va genera eroarea datorat de inexistena localitii Constana n tabela printe (LOCALITATI) Cannot add or update a child row: a foreign key constraint fails (`agentie_imobiliara_1/strazi`, CONSTRAINT `strazi_ibfk_1` FOREIGN KEY (`cod_loc`) REFERENCES `localitati` (`cod_loc`)). Pentru a soluiona corect aceast problem se va insera mai nti localitatea Constana n tabela LOCALITATI, apoi se vor insera datele de mai sus referitoare la strada Vasile Alecsandri. Eroarea datorat ncercrii de a nu insera o valoare ntr-un atribut ce nu poate avea valori NULL

Exemplu: Inserai strada Unirii din localitatea Baia Mare (cu codul localitii MM430), judeul Maramure. INSERT INTO STRAZI (id_strada,cod_loc,nume_str) VALUES (null,MM430,UNIRII); n urma execuiei frazei INSERT apare eroarea imposibilitii inserrii unei valori null n dreptul atributului id_strada, deoarece acest atribut nu accept valori nule, avnd caracteristica NOT NULL la momentul declarrii relaiei STRAZI: Column id_strada cannot be null. Soluionarea corect este INSERT INTO STRAZI (id_strada,cod_loc,nume_str) VALUES (244,MM430,UNIRII); Observaie: Astfel, dup cum s-a putut observa i din exemplele de mai sus, o fraz INSERT poate omite unele atribute (dac nu sunt definite ca NOT NULL) din clauza INSERT. O astfel de omitere atrage dup sine actualizarea ca NULL a cmpurilor omise. 5

Instruciunea INSERT INTO...SELECT FROM Sintaxa

INSERT INTO Tabela_Destinaie (Cmp_1,...,Cmp_n) SELECT Val_1,...,Val_n FROM Tabela_1, Tabela_2,... WHERE Condiie_1, Condiie_2,...; permite inserarea datelor Val_1,...,Val_n n relaia Tabela_Destinaie din relaiile Tabela_1, Tabela_2,... Valorile de inserat sunt din relaiile Tabela_1, Tabela_2,... . n utilizarea acestei sintaxe exist o unic tabel destinaie (relaia unde se va realiza inserarea) i una sau mai multe tabele surs (relaii din care se vor prelua valorile de inserat). i n utilizarea acestei sintaxe exist aceleai surse de erori. Trebuie respectate aceleai reguli specificate n INSERT...VALUES. Exemplu: Introducei pentru clientul SAS IOAN aceeai cerere de imobil n aceeai zi i pentru aceeai localitate i strad ca i a clientului BABICIU CONSTANTIN, tiind c cererea va fi nregistrat cu numrul 19 i c BABICIU CONSTANTIN are doar o singur cerere nregistrat n baza de date. INSERT INTO CERERI_OFERTE SELECT 19 AS id_co, tipul, (SELECT cnp FROM DATE_PERSOANA WHERE numele LIKE 'SAS IOAN') AS cnp, data_inreg, tip_solutionare, cod_loc, id_strada, nr_imobil, pret_min, pret_max FROM CERERI_OFERTE WHERE cnp IN (SELECT cnp FROM DATE_PERSOANA WHERE numele LIKE 'BABICIU %');

III.3.5.

Modificarea datelor
III.3.5.1. Modificarea datelor (UPDATE)

Aceast comand de actualizare a relaiilor de baz permite modificarea valorilor din tuplurile unei relaii de baz. Pentru a putea executa instruciunea UPDATE, utilizatorul care o lanseaz n execuie trebuie s aib acest privilegiu. Dac nu este specificat clauza WHERE se vor modifica toate liniile. Sintaxa UPDATE Tabela SET Col_1=Val_1,..., Col_n=Val_n WHERE ... clauza WHERE; schimb valorile atributelor Col_1,...,Col_n din relaia Tabela n valorile Val_1,..., Val_n. Regula principal a modificrilor datelor este c nu se poate modifica dect o singur relaie (nu se pot modifica mai multe relaii simultan). Prin modificare se pot schimba una pn la toate atributele relaiei. 6

Valorile noi pot fi constante, valori ale atributelor din alte relaii sau valori ale atributelor din aceeai relaie. Clauza WHERE reprezint clauza dup care se face filtrarea nregistrilor din relaia n care se face actualizarea datelor. Modificri cu valori constante

Exemplul 1: Schimbai denumirea judeului BISTRITA-NASAUD cu BISTRITA NASAUD, adic fr cratim. UPDATE JUDETE SET nume_judet=BISTRITA NASAUD WHERE simbol_judet=BN; Exemplul 2: Pentru oferta apartamentului de pe strada Victoriei, nr.54, din localitatea Baia Mare, Maramure, pus spre vnzare de ctre 'IONESCU MARA' s se modifice tipul soluionrii acestuia, de la imobil disponibil, la imobil vndut. (Se cunosc deja codificrile necesare: cod localitate MM430, id-ul strazii 152, respectiv 1 pentru imobil soluionat, i 0 n caz contrar). UPDATE cereri_oferte CO, date_persoana DP SET tip_solutionare=1 WHERE CO.cod_loc='MM430' AND CO.id_strada=152 AND CO.tipul='cerere' AND DP.numele='Ionescu Mara' Modificri cu valori din alte relaii

Exemplu: Mrii preurile minime cu 10% la ofertele de apartamentele din localitatea Baia Mare. UPDATE CERERI_OFERTE CO SET CO.pret_min=CO.pret_min*1.1 WHERE CO.cod_loc IN (SELECT cod_loc FROM LOCALITATI L WHERE L.nume_loc='BAIA MARE'); Observaie: Preul minim se nmulete cu valaoarea 1.1 deoarece pentru a mri o cantitate cu 10% se efectueaz raionamentul: cant+cant*10/100 sau cant*(1+10/100) sau cant*(1+0.1) sau cant*1.1. Modificarea mai multor cmpuri dintr-o relaie

Exemplu: Modificai datele personale ale clientului Chira Loredana cu cnp 2660920219212 astfel: numele de familie Achim, numrul de telefon 0721813171, email al@personal.ro, Baia Mare, Maramures. UPDATE DATE_PERSOANA SET numele='ACHIM LOREDANA', nr_telefon=07218131711, email='al@personal.ro' WHERE cnp=2660920219212; Observaie: Pentru a modifica datele unor atribute dintr-un tuplu cu datele corespunztoare altor tupluri din aceeai relaie se creaz un tabel temporar cu aceeai strucutr ca a relaiei iniiale care s conin tuplurile din care se extrag informaiile. Astfel, pentru a modifica adresa clientei Achim Loredana cu cea a lui Achim Mihai, din Cluj, se execut urmtoerea comand: 7

UPDATE DATE_PERSOANA SET adresa= (SELECT adresa FROM AGENTIE_IMOBILIARA.DATE_PERSOANA WHERE numele ='ACHIM MIHAI' AND adresa LIKE '%CLUJ%') WHERE numele='ACHIM LOREDANA; O fraz UPDATE poate implica o serie de erori, dintre care cele mai frecvente sunt: - erori de sintax - erori provocate de modificarea altor date dect cele dorite - erori provocate de modificarea datelor cu alte valori dect cele dorite - erori provocate de constrngeri. Erori de sintax

O eroare de sintax este completarea unor denumiri de atribute greite. UPDATE CERERI_OFERTE SET pret_min=250000, pret_max=350000, suprafata=200 WHERE cnp= 1670321778721; Rularea frazei UPDATE va genera mesajul de eroare al numelui de atribut invalid suprafata, deoarece acest atribut nu face parte din relaia CERERI_OFERTE. ncercarea de actualizare a unor cmpuri cu valori care nu se potrivesc

Exemplu: UPDATE CERERI_OFERTE CO, LOCALITATI L SET CO.data_inreg=L.nume_loc where CO.cnp=1670321778721; Valoarea atributului data_inreg este de tip dat calendaristic i nu poate fi modificat cu numele unei localiti, eroarea fiind de conversie. Actualizarea altor nregistrri dect cele dorite

Acest lucru se ntmpl adesea cnd din clauza WHERE s-a omis o parte, sau atunci cnd se omite chiar ntreaga clauz. Exemplu: Modificai numerele de telefon ale clienilor din Baia Mare astfel nct acestea s nceap cu 0362. UPDATE DATE_PERSOANA SET nr_telefon=0362; Fraza UPDATE va modifica numerele de telefon tuturor clienilor, nu doar a acelora din Baia Mare. nclcarea unor constrngeri

Acest lucru se ntmpl atunci cnd se modific valoarea ntr-o valoare fictiv, cum este cazul exemplului urmtor. 8

Exemplu: Modificai codul localitatii Braov din relaia CERERI_OFERTE (cod_loc=BV230) cu cel al oraului Paris (cod_loc=330). UPDATE LOCALITATI SET cod_loc=330 WHERE cod_loc=BV230; Execuia acestei fraze UPDATE genereaz eroarea cauzat de imposibilitatea modificrii unui cmp dint-o tabel printe atta timp ct n tabela copil exist cmpul referit (cod_loc): Cannot delete or update a parent row: a foreign key constraint fails (`test/oferte`, CONSTRAINT `FK_cod_loc` FOREIGN KEY (`cod_loc`) REFERENCES `localitati` (`cod_loc`)), adic n relaiile copil CERERI_OFERTE i STRZI exist tupluri care utilizeaz codul localitii Braov. Soluionarea corect a frazei UPDATE n acest caz se face n trei etape: 1. se insereaz n tabela printe o nregistrare cu noile valori: INSERT INTO LOCALITATI VALUES (330,'x','PARIS'); 2. a) se modific n tabela copil CERERI_OFERTE valoarea BV230 pentru atributul cod_loc cu noua valoare 330: UPDATE cereri_oferte SET cod_loc='330' WHERE cod_loc='BV230'; b) se modific n tabela copil STRAZI valoarea BV230 pentru atributul cod_loc cu noua valoare 330: UPDATE STRAZI SET cod_loc='330' WHERE cod_loc='bv230'; 3. se terge nregistrarea veche din tabela printe: DELETE FROM LOCALITATI WHERE cod_loc='BV230'; Observaie: O alt metod de eliminare sau modificare a unui cmp dintr-o relaie printe ce se regsete ntr-o relaie copil este cea n care se utilizeaz opiunea de eliminare/ modificare n cascad. Opiunea este ON DELETE/UPDATE CASCADE i se utilizeaz odat cu declararea cheii strine. Astfel, sintaxa este: CREATE TABLE tabel_copil (lista_de_atribute, FOREIGN KEY (atribut_fk) REFERENCES tabel_parinte (atribut_fk) ON DELETE/UPDATE CASCADE); Aceast opiune se poate aduga i ulterior, dup ce relaia a fost creat i populat cu tupluri. Astfel, pentru exemplul de mai sus, o a doua metod de modificare a codului loclaitii Braov - BV230 cu codul Parisului - 330 este: ALTER TABLE CERERI_OFERTE DROP PRIMARZ KEY FK_cod_loc; ALTER TABLE CERERI_OFERTE ADD CONSTRAINT fk_cod_loc FOREIGN KEY fk_cod_loc (cod_loc) REFERENCES LOCALITATI (cod_loc) ON UPDATE CASCADE; apoi se execut modificarea de la nceputul exemplului.

III.3.6.

tergerea datelor

Comanda de tergere a datelor permite tergerea tuplurilor unei relaii de baz. Pentru a se putea executa instruciunea DELETE, utilizatorul care o lanseaz n execuie trebuie s aib acest privilegiu. 9

Comanda DELETE nu terge structura tabelului. n clauza WHERE pot fi folosite i subcereri. Comanda nu poate fi folosit pentru tergerea valorilor unui cmp individual. Acest lucru se poate realiza cu ajutorul comenzii UPDATE. Operaia de tergere trebuie s fie efectuat astfel nct s nu afecteze integritatea referenial. tergerea tuturor tuplurilor unei relaii

Sintaxa DELETE FROM Tabela; realizeaz tergerea tuturor nregistrrilor din relaia Tabela. Sintaxa DELETE FROM Tabele WHERE Condiii; realizeaz tergerea anumitor nregistrri dintr-o relaie. Exemplu: tergei toate persoanele nregistrate n baza de date. DELETE FROM DATE_PERSOANA; n urma execuiei frazei DELETE, relaia DATE_PERSOANA nu va mai conine nici o nregistrare. tergerea anumitor nregistrri dintr-o relaie

Exemplu: tergei clientul Chi Gheorghe din relaia DATE_PERSOANA. DELETE FROM DATE_PERSOANA WHERE numele=CHIS GHEORGHE; n execuia frazei DELETE pot aprea - erori de sintax - erori de constrngeri. Erori de sintax cauzate de denumiri de cmpuri sau tabele greite

Execuia frazei DELETE FROM LOCALITATI WHERE denumire=HARGHITA; returneaz mesajul de eroare prin care se menioneaz c atributul cu numele denumire nu exist n tabela LOCALITATI. Atributul ce desemneaz denumirea localitii este nume_loc. Erori de sintax cauzate de utilizarea aliasurilor n sintaxa DELETE n sintaxa DELETE nu se utilizeaz aliasuri. DELETE FROM CERERI_OFERTE CO WHERE CO.id_co=3; Erori de constrngeri 10

Exemplu: S se tearg localitatea Baia Mare din relaia LOCALIATI. DELETE FROM LOCALITATI WHERE nume_loc=BAIA MARE; Mesajul de eroare afiat n urma execuiei frazei DELETE este cel al conflictului frazei DELETE cu constrngerea fk_cod_loc: nu se poate terge un cmp printe dac n relaiile copil exist cmpul respectiv. Soluia corect a problemei este ndeplinirea regulii de tergere a unei tabele din perspectiva constrngerii, i anume: nu se poate terge o nregistrare dintr-o relaie master (principal, referit, printe) dac exist nregistrri n cel puin una din relaiile referite de aceasta, dect dup tergerea tuturor nregistrrilor din relaiile dependente de aceasta relaiile copil). Alte exemple de tergere a datelor (fraze complexe): Exemplul 1: S se elimine cererile din luna mai care au fost soluionate. DELETE FROM CERERI_OFERTE WHERE tip_solutionare=1 AND MONTH(data_inreg)=5; Exemplul 2: tergei descrierea cererii clientului Pop Vasica n cazul imobilului din localitatea Oradea, afind n prealabil lista cererilor acestui client. Soluie: Relaiile DESCRIERE_OFERTA i CERERI_OFERTE se afl ntr-o asociere de 1:1. Relaia DESCRIERE_OFERTA este relaia copil (secundar, cea care refer), iar relaia CERERI_OFERTE este relaia printe (primar, cea referit), deci va fi posibil eliminarea informaiilor respective. Metoda 1: Pentru a putea terge descrierea cererii de imobil pentru clientul Pop Vasica din relaia DESCRIERE_OFERTA, trebuie vizualizat setul de date referitor la cererile i ofertele clientului Pop Vasica. SELECT DP.numele, CO.id_co, CO.data_inreg, CO.cod_loc, CO.id_strada, CO.pret_min, CO.pret_max, CO.tip_solutionare, DI.tip_imobil, DI.etaj FROM DATE_PERSOANA DP, CERERI_OFERTE CO, DESCRIERE_IMOBIL DI WHERE DP.cnp=CO.cnp AND CO.id_co=DI.id_co AND DP.numele=POP VASICA;

Fig.III.3.6.1.

Vizualizarea cererilor existente n BD pentru clientul Pop Vasica

DELETE FROM DESCRIERE_IMOBIL WHERE id_co = 12;

III.3.7.

Indeci

Se tie deja c ntr-un tabel rndurile sunt stocate n mod neordonat. Acest lucru permite SGBD-ului s efectueze rapid operaiile de introducere (INSERT), 11

actualizare (UPDATE) i tergere (DELETE) de rnduri, dar are ca efect colateral nedorit executarea ineficient a operaiilor de cutare i sortare. Exemplu: Pentru a executa interogarea SELECT * FROM CERERI_OFERTE WHERE data_inreg= 2006-07-10; SGBD-ul trebuie s efectueze o cutare secvenial n ntreg tabelul CERERI_OFERTE, comparnd valoarea din coloana data_inreg a fiecrui rnd cu irul de caractere 2006-07-10. Cutarea unei valori ntr-un tabel este o sarcin simpl n cazul unei baze de date mici, dar bazele de date folosite n producie pot conine tabele cu milioane de rnduri. SGBD-urile pun la dispoziie un mecanism numit index care are rolul de a mri viteza de regsire a datelor , fiind una din principalele ci pentru optimizarea interogrilor. Simplificnd, un index este o list sortat n care fiecare valoare distinct dintr-o coloan indexat (sau dintr-o mulime de coloane indexate) este stocat mpreun cu adresa de pe disc (locaia fizic) a rndurilor care conin acea valoare. n loc s parcurg tot tabelul pentru a gsi anumite rnduri, SGBD-ul citete numai indexul pentru a gsi adresele n vederea accesului direct la date. Cutrile indexate sunt de obicei mai rapide cu cteva ordine de mrime dect cutrile secveniale. Comanda SQL pentru crearea unui index pentru un tabel existent n baza de date este CREATE INDEX i are sintaxa: CREATE [UNIQUE] INDEX nume_index ON nume_tabel (nume_atribut1 [ASC | DESC], [nume_atribut2 [ASC | DESC]], ); Opiunea UNIQUE specific faptul c n indexul corespunztor nu pot exista dou intrri avnd valori identice ale atributelor pe care acesta este definit, adic valorile din coloana (coloanele) care intr n compunerea indexului s fie distincte. Intrrile unui index sunt ordonate implicit n ordinea cresctoare a valorilor atributelor specificate. Dac se dorete o ordonare descresctoare dup valorile unui atribut, atunci pentru aceasta se va specifica opiunea DESC. Indecii pot fi compui sau simpli. Un index este compus dac refereniaz mai multe coloane ale tabelului, iar un index care refereniaz o singur coloan din tabel se numete index simplu. Exemplul1: Creai un index simplu pentru atributul data_inreg cu numele data_index din relaia CERERI_OFERTE: CREATE INDEX data_index ON CERERI_OFERTE (data_inreg); Exemplul2: Creai un index compus pentru atributele data_inreg i tip_soluionare cu numele d_t_index. CREATE INDEX d_t_index ON CERERI_OFERTE (data_inreg, tip_solutionare); Observaii: 1. Comanda CREATE INDEX t_d_index ON CERERI_OFERTE (tip_solutionare, data_inreg); creaz un alt index, cu aceleai coloane ca cel din exemplul 2, dar nu se confund cu acesta. Ordinea trebuie stabilit dup regula: va fi precizat ca prim atribut acela care are valorile distincte cele mai numeroase, dup care urmeaz cel cu valori distincte mai puin numeroase. 12

2. Dac se utilizez opiunea UNIQUE, atunci comanda de creare a indexului d_t_index genereaz eraorea de duplicare a datelor, ceea ce nseamn c doar atributele cu valori unice se pot indexa. O alt modalitate de a crea indeci este de a-i declara odat cu crearea relaiei. Exemplu: Comanda CREATE TABLE NOU (coloana_1 INT, INDEX (coloana_1)); creaz relaia NOU cu un sigur atribut coloana_1 de tip ntreg care este declarat index al tabelului. Sintaxa general pentru tergerea unui index dintr-o relaie este DROP INDEX nume_index ON nume_tabel; Exemplu: DROP INDEX d_t_index ON CERERI_OFERTE; Dezavantajul indecilor este acela al procesrii indecilor n momentul modificrilor (inserare, actualizare, tergere): cu ct exist mai muli indeci pentru o relaie, cu att mai mare este volumul datelor procesate la fiecare modificare a relaiei. Cnd sunt inserate sau eliminate tupluri, trebuie actualizai toi indecii relaiei. Cnd este actualizat un atribut trebuie actualizai toi indecii asociai. Astfel, nu este recomandat crearea unui index dac: - relaia este mic (accesul secvenial va fi mai rapid) - relaia este reactualizat frecvent - atributul conine multe valori NULL -atributul conine date asemntoare (puine valori distincte). Concluzia este c trebuie limitat numrul de indeci n cazul bazelor de date la care operaiile de inserare, tergere i actualizare sunt frecvente. n schimb, indecii sunt utili la optimizarea accesului la date n cazul bazelor de date n care domin operaiile de tip regsire.

III.3.8.

Vederi

O vedere (n englez VIEW iar n literatura de specialitate : imagine, vedere, tabel virtual, tabel derivat, tabel dinamic ) este o relaie virtual care nu exist fizic n baza de date. n SQL o vedere este definit ca o relaie derivat, al crei coninut este determinat din una sau mai multe relaii de baz. Comanda pentru definirea unei vederi este CREATE VIEW i are sintaxa: CREATE [OR REPLACE] VIEW nume_vedere [(coloane_pt_view)] AS constructie_SELECT [WITH CHECK OPTION]; Opiunea OR REPLACE nlocuiete o vedere existent. Opiunea coloane_pt_view reprezint o list opional de nume de atribute pentru vederea cu numele nume_vedere, separate prin virgul. Numrul de atribute din vedere trebuie s fie egal cu numrul de atribute din clauza SELECT a instruciunii construcie_SELECT. Lista de atribute a vederii se utilizeaz n situaiile: - cnd lista de atribute din construcie_SELECT este derivat dintr-o expresie aritmetic, dintr-o funcie agregat (SUM, MIN, MAX, etc.) sau dintr-un literal; - cnd dou sau mai multe atribute ar avea acelai nume; - cnd se dorete atribuirea unui atribut al vederii un nume diferit de cel al atributului din care este derivat. Dac lista coloane_pt_view este omis, atunci atributele vederii vor moteni numele atributelor din instruciunea construcie_SELECT. 13

Instruciunea SELECT constructie_SELECT precizeaz atributele i tuplurile utilizate din relaiile componente ale vederii. Opiunea WITH CHECK OPTION se apeleaz n cazul vederior neactualizabile i previne inserarea sau modificarea tuplurilor vederii, cu excepia acelor tupluri pentru care clauza constructie_SELECT este adevrat. Atfel ea asigur c n cazul unei operaii INSERT sau UPDATE nu va fi adugat sau actualizat nici un tuplu care nu se ncadreaz n condiiile specificate la definirea vederii. Vederile au urmtoarele avantaje: Simplificarea accesului la date: vederile ascund complexitatea datelor i simplific instruciunile, astfel nct utilizatorii pot efectua operaii asupra vederilor mult mai uor dect pot efectua operaii direct asupra unei relaii; Actualizarea automat: cnd este actualizat o relaie de baz, modificrile se propag n mod automat n toate vederile care fac referire la relaia respectiv; Creterea securitii: vederile filtreaz datele coninute n relaiile componente,

limitnd accesul unor categorii de utilizatori la anumite date. Exemplul1: (securitatea) S se creeze o vedere care ascunde informaiile personale bancare ale clienilor din baza de date AGENTIE_IMOBILIARA. CREATE VIEW DATE_PERSOANA_VIEW AS SELECT cnp,numele,adresa,nr_telefon,email FROM DATE_PERSOANA; Exemplul2: (acces simplificat, actualizare implicit) S se realizeze o vedere care s calculeze numrul de imobile treanzacionate, numrul imobilelor rmase spre tranzacionare i valoarea total a ncasrilor. CREATE OR REPLACE VIEW STATISTICA_VIEW_1 (nr_imobile_vandute,nr_imobile_ramase,valoare_totala) AS SELECT COUNT(F.id_factura) AS nr_imobile_vandute, ((SELECT COUNT(*) AS nr_imobile FROM CERERI_OFERTE) (SELECT COUNT(*) AS nr_vandute FROM FACTURI)) AS nr_imobile_ramase, SUM(F.total) AS valoare_totala FROM FACTURI F, CERERI_OFERTE CO where CO.id_co=F.id_co; SELECT * FROM STATISTICA_VIEW_1; Fig.III.3.8.1. Afiarea rezultatului oferit de vederea STATISTICA_VIEW_1

Exemplul3: S se realizeze o list imobil_lux_view cu toate cererile sau ofertele de lux din baza de date astfel nct aceast list s poat fi mrit mereu cu date imobile de aceeai categorie, adic de lux. CREATE OR REPLACE VIEW IMOBIL_LUX_VIEW AS SELECT * FROM CERERI_OFERTE WHERE pret_min BETWEEN 2000000 AND 3000000 WITH CHECK OPTION; 14

SELECT * FROM IMOBIL_LUX_VIEW;

Fig.III.3.8.2.

Afiarea imobilelor de lux

INSERT INTO IMOBIL_LUX_VIEW VALUES (31, 'oferta', 2820420223201, '2007-01-30', 0, NULL, NULL, 5, 2500000, NULL); INSERT INTO IMOBIL_LUX_VIEW VALUES (32, 'cerere', 2820420223201, '2007-01-30', 0, NULL, NULL, NULL,1000, NULL); Lista imobilelor de lux va fi actualizat cu nc un imobil i anume oferta din prima inserare de mai sus, n schimb, a doua inserare cererea nu va fi executat deoarece nu respect condiia impus n clauza WHERE a vederii imobil_lux_view, fiind un imobil evaluat la 1000 U.M. Eroarea generat este: ERROR: CHECK OPTION failed 'agentie_imobiliara_1.date_persoana_view'. Observaie: Dup cum s-a observat n exemplele de mai sus, simpla creare a unei vederi nu afieaz nimic, deoarece CREATE VIEW nu face dect s salveze vederea sub forma unei instruciuni SELECT. Pentru a putea vizualiza datele prin intermediul unei vederi, se interogheaz vederea utiliznd instruciunea SELECT, n acelai mod n care se interogheaz o relaie. Astfel, o vizualizare poate fi folosit n instruciunile SELECT, UPDATE, DELETE. Suprimarea unei vederi se face prin comanda DROP VIEW nume_vedere; Alte exemple 1. Vederile furnizeaz un mecanism de ascundere a anumitor informaii pentru anumii utilizatori. a (tupluri) Urmtoarea vedere nregistreaz doar ofertele sau cererile din Timioara. CREATE VIEW V1 AS SELECT * FROM CERERI_OFERTE WHERE cod_loc IN (SELECT cod_loc FROM LOCALITATI WHERE nume_loc=Timisoara); SELECT * FROM v1; b (atribute) Urmatoarea vedere ascunde cnp-ul clienilor din relaia CERERI_OFERTE a ageniei imobiliare. CREATE VIEW V2 AS SELECT ID_co, tipul, data_inreg, tip_solutionare, cod_loc, id_strada, nr_imobil, pret_min, pret_max FROM CERERI_OFERTE; SELECT * FROM V2; c (tupluri i atribute) Vederea V3 nregistreaz cererile i ofertele din Timioara, mai puin infromaia referitoare la cnp-ul clienilor solicitani sau ofertani. CREATE VIEW V3 AS SELECT id_co, tipul, data_inreg, tip_solutionare, cod_loc, id_strada, nr_imobil, pret_min, pret_max FROM CERERI_OFERTE WHERE cod_loc IN 15

(SELECT cod_loc FROM LOCALITATI WHERE nume_loc=TIMISOARA); SELECT * FROM V3; 2. Vederile selecteaz datele din mai multe relaii. Vederea urmtoare reine numele, adresa, cnp-ul clienilor care au ncheiat o factur, precum i numrul facturii i id-ul de nregistrare a cererii sau ofertei respective. CREATE VIEW V4 AS SELECT Dp.numele, Dp.adresa, DP.cnp, F.nr_factura, F.id_co FROM DATE_PERSOANE DP, facturi F WHERE DP.cnp=F.cnp; SELECT * FROM V4; 3. Interogrile sofisticate pot fi simplificate folosind vederile. SELECT * FROM V4 where numele LIKE 'P%'; 4. Modificarea unei vederi este asemntoare modificrii relaiilor. Modificarea vederii V4 aduce n plus atributul telefon_client. ALTER VIEW V4 AS SELECT Dp.numele AS nume_client, Dp.adresa, DP.cnp, F.nr_factura, F.id_co AS cerere_oferta, DP.nr_telefon AS telefon_client FROM DATE_PERSOANE DP, FACTURI F WHERE DP.cnp=F.cnp; 5. Asupra vederilor se pot efectua operaiile de inserare, modificare sau eliminare a tuplurilor. Unele constrngeri (cum ar fi CHECK) s-ar putea s nu permit modificarea datelor din vederi. (vezi exemplele anterioare).

16

IV.

Limbajul de control al bazelor de date (LCD)


IV.1. Tranzacii

Limbajul pentru controlul datelor (LCD) permite salvarea informaiei, realizarea fizic a modificrilor n baza de date, rezolvarea unor probleme de concuren. Controlul unei baze de date cu ajutorul SQL-ului se refer la: - asigurarea confidenialitii i securitii datelor; - organizarea fizic a datelor; - realizarea unor performane; - reluarea unor aciuni n cazul unei defeciuni; - garantarea coerenei datelor n cazul prelucrrii concurente. Sistemul de gestiune trebuie: - s pun la dispoziia unui numr mare de utilizatori o mulime coerent de date; - s garanteze coerena datelor n cazul manipulrii simultane de ctre diferii utilizatori. Tranzacii (TRANSACTION), permanentizare (COMMIT), derulare napoi (ROLLBACK)

Coerena este asigurat cu ajutorul conceptului de tranzacie. Tranzacia este unitatea logic de lucru constnd din una sau mai multe instruciuni SQL, care trebuie s fie executate atomic (ori se execut toate, ori nu se execut nici una!), asigurnd astfel trecerea BD dintr-o stare coerent n alt stare coerent. Importana tranzaciilor ntr-o baz de date este foarte mare. De exemplu, o tranzacie poate nsemna introducerea unei facturi n cazul BD AGENTIE_IMOBILIARA, ceea ce nseamn, de regul introducerea liniilor corespunztoare n relaia FACTURI urmat de actualizarea relaiei CERERI_OFERTE i de calculul valorii tva (n cazil n care acesta este fix) sau a toataluli facturii. Toat aceast secven de operaii are sens numai dac se deruleaz n totalitate, deoarece este nedorit cazul n care s-ar finaliza numai cu linia din FACTURI, neactualiznd i tuplul corespunztor imobilului facturat n tabelul CERERI_OFERTE (actualizarea const n modificarea tipului soluionrii tranzaciei: modificarea valorii 0, imobil disponibil, n valoarea 1, imobil vndut). Precizarea unei tranzacii se poate face n dou moduri: 1. preciznd nceputul i sfritul acesteia START TRANSACTION instruciuni de manipulare a datelor COMMIT / ROLLBACK sau SET AUTOCOMMIT=0 instruciuni de manipulare a datelor COMMIT / ROLLBACK 2. scriind direct instruciunile de manipulare a datelor, deoarece MySql permanentizez automat datele modificate (un COMMIT implicit), dar, 17

n acest caz, nu mai este posibil revnirea la starea anterioar modificrii datelor (adic utilizarea ROLLBACK-ului). Instruciunea COMMIT este folosit pentru permanentizarea modificrilor executate asupra bazei de date (modificrile sunt nregistrate i sunt vizibile tuturor utilizatorilor). Exemplul 1: Importana tranzaciilor poate fi ilustrat i prin exemplul urmtor: presupunnd c n timpul transferului unei sume de bani din contul de economii n contul de CEC a unei persoane fizice (sunt necesare dou instruciuni UPDATE) are loc o pan de curent, dac nu s-a folosit iniial tranzacia, atunci exist riscul ca CECul s nu mai fie actualizat cu suma respectiv. Astfel, tranzacia necesar este START TRANSACTION UPDATE tabel_economii SET depozit=depozit-suma WHERE id_client=203; UPDATE tabel_cec SET depozit=depozit+suma WHERE id_client=2435; COMMIT; Structura tabelelor este urmtoarea: TABEL_ECONOMII(id_client#,nume,depozit), TABEL_CEC(id_client#,nume,depozit). Execuia unei comenzi COMMIT implic anumite modificri: Toate schimbrile (INSERT, DELETE, UPDATE) din baza de date fcute dup anterioara comand COMMIT sau ROLLBACK sunt definitive. Comanda se refer numai la schimbrile fcute de utilizatorul care d comanda COMMIT. Toate punctele de salvare vor fi terse (vezi instruciunea SAVEPOINT). Starea anterioar a datelor este pierdut definitiv. Toi utilizatorii pot vizualiza rezultatele. Blocrile asupra liniilor afectate sunt eliberate; liniile pot fi folosite de ali utilizatori pentru a face schimbri n date.

Instruciunea ROLLBACK este folosit pentru refacerea strii anterioare a bazei de date (sunt anulate toate reactualizrile efectuate de la nceputul tranzaciei). Exemplul 2: Considernd acelai exemplu ca cel precedent, se presupune c suma din contul economii necesar transferrii n contul CEC depete suma existent n depozitul economii. n acest caz se dorete anularea operaiunii de extragere a sumei respective din depozitul economii, adic o revenire la strea anterioar, utiliznd comanda ROLLBACK. START TRANSACTION UPDATE tabel_economii SET depozit=depozit-suma_gresita; WHERE id_client=203; UPDATE tabel_cec SET depozit=depozit+suma 18

WHERE id_client=2435; ROLLBACK; Astfel depozitele nu vor suferi modificri, iar n continuare se reia tranzacia pentru a introduce datele corecte. START TRANSACTION UPDATE tabel_economii SET depozit=depozit-suma_corecta; WHERE id_client=203; UPDATE tabel_cec SET depozit=depozit+suma WHERE id_client=2435; COMMIT; Execuia unei comenzi ROLLBACK implic anumite modificri: Anuleaz tranzacia n curs i toate modificrile de date fcute dup ultima comand COMMIT. Sunt eliberate blocrile liniilor implicate. Nu terge un tabel creat prin CREATE TABLE. Eliminarea tabelului se poate realiza doar prin comanda DROP TABLE.

Instruciunea SAVEPOINT este folosit n conjuncie cu instruciunea ROLLBACK, pentru definirea unor puncte de salvare n fluxul programului. ROLLBACK [TO SAVEPOINT nume_identificator] Exemplul 3: Considernd acum cazul n care suma din contul CEC a fost introdus eronat, dar suma corespunztoare contului economii este corect, corectarea se poate face utiliznd instruciunea SAVEPOINT: START TRANSACTION; UPDATE tabel_economii SET depozit=depozit-suma WHERE id_client=203; SAVEPOINT economii; UPDATE tabel_cec SET depozit=depozit+suma_gresita WHERE id_client=2435; ROLLBACK TO SAVEPOINT economii; START TRANSACTION; UPDATE tabel_cec SET depozit=depozit+suma_corecta WHERE id_client=2435; COMMIT; Exemplul 4: Pentru o mai bun nelegere a mecanismului de utilizare a tranzaciilor, prezentm n exemplul de fa pseudocodul corespunztor tranzaciei din exemplele 1, 2 i 3. START TRANSACTION UPDATE tabel_economii SET depozit=depozit-suma WHERE id_client=203; IF a aprut vreo eroare THEN GO TO UNDO; END IF; 19

UPDATE tabel_cec SET depozit=depozit+suma id_client=2435; IF a aprut vreo eroare THEN GO TO UNDO; END IF; COMMIT; /*tranzacie reuit*/ GO TO FINISH;

WHERE

UNDO: ROLLBACK; /*terminare nereuit*/ FINISH: RETURN; Exemplul 5: Fie un sistem de rezervare a locurilor la CFR a crei baz de date conine trei relaii definite prin schemele: TREN (Cod_tren#, Sursa, Destinatia, Libere); CLIENTI (Cod_client#, Nume, Adresa); REZERVARE (Cod_tren#, Cod_client#, Obs); unde atributul Libere precizeaz numrul de locuri nevndute nc. Pentru a face o rezervare se introduce codul trenului i codul clientului. Se ia n considerare i situaia n care nu mai exist niciun loc disponibil pentru o curs dat. Tranzacia corespunztoare operaiei de rezervare poate fi implementat, folosind o interfa SQL implementat ntr-un mediu PASCAL, astfel: SATRT TRANSACTION; BEGIN INPUT(codul_trenului,codul_clientului); EXEC SQL SELECT Libere AS temp FROM TREN WHERE Cod_tren=Codul_trenului; IF temp=0 THEN BEGIN OUTPUT (Nu mai sunt locuri libere!); ROLLBACK END ELSE BEGIN EXEC SQL UPDATE TREN SET Libere=Libere-1 WHERE cod_tren=codul_trenului; EXEC SQL INSERT INTO REZERVARE VALUES (Codul_ternului, codul_clientului, NULL) COMMIT; OUTPUT (Rezervare efectuat!); END END. Numrul de locuri libere corespunztoare trenului solicitat este citit n variabila temp pentru a verifica dac mai sunt locuri libere. Dac nu mai sunt locuri, tranzacia se termin prin abortare, dup ce s-a semnalat printr-un mesaj lipsa de locuri. Dac mai 20

sunt locuri, atunci se face rezervarea i tranzacia se termin printr-o comand de validare COMMIT.

IV.2. Tranzacii i puncte de salvare


n cursul anterior s-a afirmat c tranzacia este o unitate de lucru logic ce implic mai multe operaii cu baza de date. Este limpede c utilizatorul trebuie s aib posibilitatea de a informa sistemul atunci cnd mai multe operaii distincte fac parte din aceeai tranzacie prin instruciunile START TRANSACTION, COMMIT, ROLLBACK. Pentru sintaxa utilizat n tranzacii sunt necesare i urmtoarele precizri: a) Tranzacia poate ncepe: - dup o comand COMMIT, - dup o comand ROLLBACK, - dup conectarea iniial la MySql, - cnd este executat prima instruciune SQL. b) Tranzacie const: - dintr-o singur instruciune LCD (COMMIT; ROLLBACK, SAVEPOINT); - din instruciuni LMD care fac schimbri consistente n date (INSERT, UPDATE, DELETE). c) Tranzacia se termin: - dac sistemul cade; - dac utilizatorul se deconecteaz; - dac se dau comenzile COMMIT sau ROLLBACK ; - dac se execut o comand LDD (DROP DATABASE, DROP TABLE, ALTER TABLE, RENAME TABLE, CREATE DATABASE, CREATE INDEX etc.) Dup ce se termin o tranzacie, prima instruciune SQL executabil va genera automat nceputul unei noi tranzacii. d) Un commit apare automat: - cnd este executat o comand LDD; - cnd este executat o comand LCD; - dup o ieire normal din MySql fr specificarea explicit a comenzilor COMMIT sau ROLLBACK. e) Un rollback apare automat dup o ieire anormal din MySql sau o cdere de sistem. f) Executarea unei instruciuni ROLLBACK presupune terminarea tranzaciei curente i nceperea unei noi tranzacii. g) Executarea unei instruciuni COMMIT presupune modificarea permanent a datelor din baza de date n conformitate cu instruciunile SQL executate n cadrul tranzaciei care tocmai s-a terminat. Din acest punct ncepe o nou tranzacie. h) Nu se pot derula napoi instruciunile SELECT, CREATE, ALTER sau DROP; dac aceste instruciuni sunt incluse n tranzacii, ele nu vor fi derulate napoi. Starea datelor nainte de COMMIT sau ROLLBACK este urmtoarea: - starea anterioar a datelor poate fi recuperat; - utilizatorul curent poate vizualiza rezultatele operaiilor LMD prin interogri asupra relaiilor; - ali utilizatori nu pot vizualiza rezultatele comenzilor LMD fcute de utilizatorul curent (read consistency); - nregistrrile (tuplurile) afectate sunt blocate i, prin urmare, ali utilizatori nu pot face schimbri n datele acestor nregistrri. 21

Este posibil ca o tranzacie s fie descompus n subtranzacii, atunci cnd este necesar s se anuleze doar parial unele operaii. Puncte de salvare (SAVEPOINT)

Dup cum s-a vzut anterior, punctele de salvare sunt marcaje intermediare unei tranzacii lungi, menite s mpart tranzacia n pri mai mici. Acestea permit derularea napoi a modificrilor efectute, derularea fcndu-se de la punctul curent din cadrul tranzaciei pn la un punct anterior din cadrul tranzaciei. Sintaxa pentru punctele de salvare este: SAVEPOINT identificator ROLLBACK TO SAVEPOINT identificator; Dac nu se specific nici un punct de salvare (savepoint), toate modificrile fcute n tranzacia curent sunt anulate, iar dac se specific un anumit punct de salvare, atunci doar modificrile de la acel punct pn n momentul respectiv sunt anulate. Dac este creat un punct de salvare avnd acelai nume cu unul creat anterior, cel definit anterior este ters automat. Toate punctele de salvare sunt terse dac se execut comanda COMMIT sau ROLLBACK care nu specific numele unui punct de salvare. Exemplu: Urmtoarea secven de instruciuni are doar ca efect inserarea clientului Popescu Denis i selectarea informaiilor din relaia DATE_PERSOANA. DELETE FROM DATE_PERSOANA; START TRANSACTION; SAVEPOINT nimic; INSERT INTO DATE_PERSOANA VALUES(1651020616623,'Rus Vasile','str.Rozelor,nr.5/3,Bucuresti', '0744675875',NULL); INSERT INTO DATE_PERSOANA VALUES(2390303132002,'PopescuAna,'str.Jiului,nr.22/12,Ploiesti', NULL,NULL); UPDATE DATE_PERSOANA SET nr_telefon='0222222222' WHERE numele='rus vasile'; ROLLBACK TO SAVEPOINT nimic; INSERT INTO DATE_PERSOANA VALUES (1460503440044,'Popescu Denis', 'str.Bdul. Decebal, nr. 54, Cluj', '0362405203', 'pd@personal.com'); SELECT * FROM DATE_PERSOANA; Proprietile tranzaciilor O tranzacie satisface un set de patru proprieti sintetizate sub denumirea de ACID: Atomicitate, Consisten, Izolare i Durabilitate. Proprietile ACID ale sistemului de gestiune a bazelor de date reprezint cheia tranzaciilor. Fr aceste proprieti nu este garantat integritatea bazei de date. n practic, aceste proprieti sunt des nerespectate (ntr-o oarecare msur) pentru a obine o performan mai bun. Atomicitatea se refer la abilitatea SGBD de a garanta executarea tuturor 22

cerinelor unei tranzacii sau a nici uneia. Efectul tranzaciei este total sau de loc. De exemplu, n cazul ntocmirii facturii din BD AGENTIE_IMOBILIARA, este necesar executarea ori a ambelor cerine din tranzacie, ori a nici uneia. Presupunem c id-ul imobilului vndut este 30 i c factura ce se ntocmete are ordinul de factur 6. START TRANSACTION; UPDATE CERERI_OFERTE SET tip_solutionare=1 WHERE id_co=30; INSERT INTO FACTURI SELECT 6 AS nr_factura, 30 AS id_co, '2007-01-25' AS data_factura, 2820420223201 AS cnp, COALESCE(pret_min,pret_max), COALESCE(pret_min,pret_max)*0.19 AS tva, COALESCE(pret_min,pret_max)*1.19 AS total FROM CERERI_OFERTE WHERE id_co=30; COMMIT; Funcia COALESCE returneaz ori valoarea diferit de NULL a celor dou atribute ori valoarea minim a lor. Consistena const n corectitudinea tranzaciei. Aceasta nseamn c o tranzacie nu poate nclca constrngerile de integritate ale BD. De exemplu, dac o constrngere de integritate stabilete c toate preuirle imobilelor trebuie s conin valori pozitive sau NULL, atunci orice tranzacie care ncalc aceast regul va fi anulat. Izolarea se refer la abilitatea aplicaiei de a izola operaiile fcute ntr-o tranzacie de operaiile altei tranzacii. Astfel tranzaciile sunt izolate una de alta, n sensul c actualizrile bazei de date efectuate printr-o anumit tranzacie T1 nu sunt vizibile pentru o tranzacie T2 numai dup ce tranzacia T1 execut cu succes operaia COMMIT. Durabilitatea garanteaz c, odat ce utilizatorul a efectuat tranzacia cu succes, rezultatele devin permanente. Chiar dac dup momentul validrii apare un defect care mpiedic nscrierea normal a rezultatelor tranzaciei n baza de date, acestea vor fi trecute n baza de date dup reluarea activitii. Macanismul prin care se realizeaz proprietatea de durabilitate are la baz conceptul de jurnal (log). Jurnalul este un fiier secvenial n care sunt nregistrate toate operaiile efectuate de tranzaciile din sistem. Aceste informaii se vizualizeaz prin comanda SHOW ENGINE DBD LOG. Consistena la citire (READ CONSISTENCY)

ntr-un sistem multi-user, sistemul MySql furnizeaz read consistency la nivel de instruciune SQL, adic o singur comand SQL nu poate da rezultate care sunt contradictorii sau inconsistente. Read consistency asigur c fiecare utilizator vede datele aa cum existau la ultimul commit, nainte s nceap o operaie LMD. Prin urmare, modificrile efectuate asupra unei baze de date nu sunt vizibile dect dup ce 23

operaia de actualizare a fost validat. Numai utilizatorul care a executat tranzacia poate vedea modificrile fcute de el n cursul acestei tranzacii. Exemplu: Se consider doi utilizatori (A i B) ai unei baze de date care opereaz asupra ei n acelai timp. Utilizatorul A vizualizeaz nregistrarea inserat de utilizatorul B abia dup ce B a executat comanda COMMIT i A a terminat i el, la rndul lui, de executat comanda COMMIT. Utilizatorul A SET AUTOCOMMIT=0; timpul | SELECT * FROM tabel; | ->nu exist nregistrri | | | v SELECT * FROM tabel; -> nu exist nregistrri SELECT * FROM t; -> nu exist nregistrri COMMIT; SELECT * FROM t;
--------------------| 1 | 2 | ---------------------

Utilizatorul B SET AUTOCOMMIT=0;

INSERT INTO tabel VALUES (1, 2);

COMMIT;

exist o nregistrare Fig.IV.2.1. Consistena la citire

Consistena la citire garanteaz c setul de date vzut de orice instruciune SQL este consistent i nu se schimb n timpul execuiei unei instruciuni. Operaiile de citire (SELECT) nu trebuie s vad datele care sunt n proces de schimbare, iar operaiile de scriere (INSERT, DELETE, UPDATE) nu trebuie s afecteze consistena datelor i s ntrerup sau s intre n conflict cu alte operaii de scriere concurente. Dac asupra bazei este executat o comand LMD, server-ul MYSql face o copie a datelor dinainte de modificare i o depune n segmentul rollback (UNDO). Toi utilizatorii (cu excepia celor care modific datele) vor vedea datele cum sunt nainte de modificare (vd coninutul segmentului UNDO). Dac comanda LMD este commit, atunci schimbrile din baza de date devin vizibile oricrui utilizator care folosete instruciunea SELECT. Cnd se termin tranzacia, spaiul ocupat n segmentul undo de vechea dat este liber pentru reutilizare. Server-ul MySql asigur astfel o vizualizare consistent a datelor n orice moment.

IV.3. Controlul concurenei


24

Sisitemele monoutilizator rspund unui numr redus de probleme practice care implic utilizarea bazelor de date. Cea mai mare parte a apliciilor trebuie concepute pentru a putea funciona n regim de lucru multiutilizator i implementate pe sisteme care prezint aceast caracteristic. Astfel apare necesitatea controlului accesului concurent la date. Prin conctrolul accesului cocnurent la date se urmrete pstrarea integritii bazei de date n condiiile execuiei concurente a tranzaciilor. Exemplu (execuia necontrolat a unei tranzacii): Se consider o actualizare a unui cont iniial la banc de 5000$. Presupunem c sunt iniiate dou tranzacii concurente: T1 nregistrarea retragerii sumei de 500$ din cont T2 nregistrarea depunerii sumei de 1000$ n cont i c aciunile acestor tranzacii se execut intercalat. t2 t0 t1 t3 t5 t4 timp cont T1 citeste T2 citeste Fig.IV.3.1. 5000 5000 5000 4500 4500 6000

cont=cont-500 scrie cont=cont+1000 scrie Execuia necontrolat a unei tranzacii

n final, baza de date va conine n cmpul cont valoarea 6000 n loc de 5500 ct ar fi corect. Se observ c actualizarea realizat de T1 s-a pierdut datorit intercalrii aciunilor tranzaciilor T1 i T2. ntr-un sistem multiuser, la dou procese care citesc i actualizeaz valoarea aceluiai obiect nu le este permis rularea cocnurent, deoarece acest lucru poate afecta coerena datelor din baza de date. Consistena bazei de date ar fi asigurat de execuia serial a tranzaciilor (una dup alta), ns aceasta minimzeaz eficiena sistemului n regim multiutilizator. SGBD ofer posibilitatea blocrii datelor utilizate la un moment dat de o tranzacie, nelegnd prin aceasta interzicerea accesului celorlalte tranzacii concurente la aceste date. Celelalate tranzacii care solicit aceleai date sunt puse n ateptare pn la deblocarea datelor. Blocri (LOCK TABLES). Deblocri (UNLOCK TABLES)

Blocrile sunt folosite n SQL pentru a asigura integritatea datelor, pentru a crete viteza de actualizare a datelor, permind n acelai timp accesul concurent la date de ctre un numr infinit de utilizatori. n cea mai simpl form, blocarea unor date de ctre o tranzacie interzice celorlalte tranzacii accesul la aceste date. Blocarea se poate aplica - la nivelul ntregii baze de date - al unui fiier - nregistrare sau grup de nregistrri 25

cmp Clasificarea blocrilor: a) Din punct de vedere a resursei blocate, blocrile pot fi: - la nivel de linie (blocarea afecteaz un tuplu); - nivel de tabel (blocarea afecteaz ntreaga relaie). La nivel de linie, blocrile se pot face numai n modul exclusiv (X exclusive), adic un utilizator nu poate modifica un tuplu pn ce tranzacia care l-a blocat nu s-a terminat (prin permanentizare sau prin derulare napoi). Blocrile la nivel de tabel pot fi fcute n mai multe feluri, n funcie de caracterul mai mult sau mai puin restrictiv al blocrii (WRITE, READ). 1) Modul WRITE (scriere) de blocare la nivel de relaie este obinut la executarea comenzii LOCK TABLE nume_tabel WRITE; O astfel de blocare permite firului de execuie s scrie n aceast relaie, dar nu permite nici vizualizarea, nici inserarea datelor n relaie celorlalte fire de execuie. 2) Modul de blocare READ (de citire) permite att firului de execuie care lanseaz comanda ct i celorlalte fire de execuie doar citirea din relaia blocat (relaiile blocate). LOCK TABLE nume_tabel READ; Dac o relaie trebuie blocat n ambele moduri de blocare, SCRIERE i CITIRE, atunci se precizeaz nti modul de blocare SCRIERE, apoi se menioneaz cel de CITIRE, deoarece modul SCRIERE are prioritate modului CITIRE. b) Din punct de vedere a modului de declanare a blocrii, blocrile pot fi: - implicite (blocarea este fcut automat de sistem n urma unei operaii INSERT, DELETE sau UPDATE i nu necesit o aciune din partea utilizatorului); - explicite (blocarea este declanat ca urmare a comenzilor LOCK TABLE sau SELECT cu clauza FOR UPDATE). Exemplu: Blocarea relaiei SALARIAT se realizeaz prin comanda explicit SELECt FOR UPDATE. SELECT salariu FROM SALARIAT WHERE cod_salariat = 1234 FOR UPDATE; UPDATE SALARIAT SET salariu = 23456 WHERE cod_salariat = 1234; COMMIT; Prima comand blocheaz explicit tuplul cu cod_salariat=1234. La executarea celei de a doua comezi, blocarea la nivel de tuplu se menine. La executarea comenzii COMMIT, tranzacia este permanentizat i toate blocrile sunt eliberate. Una sau mai multe relaii pot fi blocate n oricare din modurile prezentate mai sus folosind comanda LOCK TABLE, care are sintaxa: LOCK TABLES nume_tabel1 {READ | WRITE}, Nume_tabel2{READ | WRITE}, UNLOCK TABLES; Exemplu: Concurena tranzaciilor din figura Fig. IV.3.1. se poate remedia dac tranzacia T1 folosete blocrile. n acest mod, tranzacia T2, care la rndul ei este o blocare, va atepta pn cnd se deblocheaz datele. LOCK TABLE tabel_economii WRITE; 26

SELECT depozit FROM tabel_economii WHERE id_client=3; UPDATE tabel_economii SET depozit =depozit-500; UNLOCK TABLE; LOCK TABLE tabel_economii WRITE; SELECT depozit FROM tabel_economii WHERE id_client=3; UPDATE tabel_economii SET depozit =deposit+1000; UNLOCK TABLE; Observaie: Din punctul de vedere al timpului de execuie, execuia secvenial la care duce procesul de blocare este innaceptabil n cele mai multe cazuri. Astfel, se ncearc utilizarea blocrilor ct mai rar cu putin. Totui exist algoritmi care s realizeze ordonri secveniale legate de un grad de concuren al execuiei ct mai ridicat, dar i cu garania obinerii de rezultate corecte. ns aceast teorie a bazelor de datre depete scopul cursului de fa. (Detalii n Modelarea bzelor de date de Ileana Popescu, Ed. Tehnic, Bucureti, 2001 i Baze de date i gestionarea tranzaciilor de Robert Dellinger, Ed. Albastr, Cluj-Napoca, 2000).

27

V. Procedural n SGBD
V.1. Proceduri i funcii stocate

V.1.1. Noiuni preliminarii Aplicaiile de baze de date trebuie s realizeze pe de o parte interfaa cu SGBD pentru introducerea i extragerea datelor, iar pe de alt parte, interfaa cu utilizatorii asftel nct acetia s poat efectua diferite operaii. Pe lng aceste funcii de interfee, programul de aplicaii de BD trebuie s implementeze i algoritmii de calcul necesari. Sistemele de gestiune a bzelor de date relaionale prelucreaz instruciuni SQL. Limbajul SQL este un limbaj neprocedural care permite definirea datelor i manipularea lor, dar nu prevede instruciuni de manipulare. De aceea, pentru realizarea aplicaiilor de baze de date au fost rezolvate o multitudine de limbaje i biblioteci de programare: - limbaje procedurale de extensie a limbajului SQL; - limbajul SQL integrat; - biblioteci de funcii sau de clase pentru comunicarea cu bazele de date. Majoritatea SGBD sunt prevzute cu cel puin un limbaj procedural, cele mai cunoscute fiind: - PL-SQL pentru sisteme de gestiune Oracle; - Transact SQL pentru sisteme de gestiune Microsoft SQL Server; Pl/PG SQL i PL/Pearl pentru sisteme de gestiune PostgreSQL etc. O procedur stocat este o secven de programe (cod) care face parte integrant din baza de date. Avantajul utilizrii procedurilor stocate decurg din faptul c acestea sunt parte din structura (schema) bazei, fiind pstrate n dicionarul de date (catalogul sistem). Exist mai multe tipuri de proceduri stocate: a) funcii-utilizator pentru validarea relaiilor: b) funciile pentru caclulul unor valori implicite; c) proceduri/funcii de validare la nivel de tuplu sau relaie; d) funcii/proceduri de calul a unor expresii complexe etc. O procedur stocat este ori o funcie, ori o procedur. V.1.2. Crearea unei proceduri/funcii Comanda de creare a unei proceduri sau funcii este CREATE PROCEDURE, respectiv CREATE FUNCTION. Sintaxa pentru crearea procedurii stocate este: CREATE PROCEDURE nume_procedura () [caracteristici] corpul_rutinei CREATE FUNCTION nume_functie ([parametru_functie tip[,]]) 28

RETURNS tip corpul_rutinei Exemplu: S se costruiasc o procedur stocat care s calculeze suma tuturor ncasrilor curente. DELIMITER // CREATE PROCEDURE INCASARI_PROCEDURA () BEGIN SELECT SUM(total) FROM FACTURI; END; // DELIMITER; CALL INCASARI_PROCEDURA();

Fig.V.1.1. Suma tuturor ncasrilor din relaia FACTURI Observaii: 1. Pentru a putea folosi semnul punct i virgul ca delimitator pe msur ce sunt scrise comenzile din corpul procedurii stocate, trebuie modificat delimitarorul de sfrit de instruciune de la valoarea curent - adic punct i virgul - la un slash dublu //. Acest lucru se face prin comanda DELIMITER //. 2. Parametrul de ieire este ncasri i trebuie s fie de acelai tip ca i atributul total. 3. n corpul procedurii s-a folosit o singur instruciune scris n zona executabil BEGIN ... END, i anume instruciunea SELECT care include clauza INTO nume_parametru pentru a ncrca rezultatul interogrii n parametrul incasari. 4. La finalul procedurii se revine la delimitatorul punct i virgul prin linia DELIMITER ; 5. Penttru a apela procedura se folosete cuvntul cheie CALL, sintaxa fiind CALL nume_procedura (@variabila); Aceast instruciune apeleaz procedura stocat i transfer o variabil n care se va stoca rezultatul. Pentru a-l vedea trebuie sa apelm variabila: SELECT @variabila; 6. 7. O procedur poate returna una sau mai multe valori. O procedur de stocare poate s apeleze alte proceduri stocate.

O funcie se creaz n mod similar cu crearea unei proceduri. O funcie accept parametrii de intrare i returneaz o singur valoare. Exemplul1: S se construiasc o funcie stocat care s calculeze valoarea TVA a produselor cunoscnd preul fr TVA al produsului. DELIMITER // CREATE FUNCTION tva_functie (pret DECIMAL(10,2)) RETURNS DECIMAL(10,2) RETURN pret*0.09; 29

// DELIMITER ; SELECT tva_functie(100);

Fig.V.1.2. Valoarea TVA calculat pentru o anumit sum introdus de la tastaur Observaii: 1. Pentru ca funcia s returneze o valoare se folosete instruciunea RETURN. 2. Apelul unei funcii stocate se face prin SELECT . 3. Funciile returneaz ntotdeauna o valoare (pe cnd o procedur poate returna una sau mai multe valori). 4. O funcie poate fi apelat din interiorul unei comenzi, ca orice alt funcie (adic invocnd numele funciei) i returneaz o valore scalar. Exemplul2: CREATE FUNCTION SALUT(s CHAR(20)) RETURNS CHAR(50) RETURN CONCAT('O zi buna',' ',s,'!'); SELECT SALUT('tuturor');

Fig.V.1.3. Rezultatul returnat de funcia salut V.1.3. Corpul rutinei Corpul rutinei const dintr-o procedur valid SQL. Aceasta poate fi o comand simpl (SELECT sau INSERT) sau o comand complex scris ntre BEGIN i END. Sintaxa pentru comanda complex este [begin label:] BEGIN [lista comenzi] END [end label]; Aceasta poate conine mai multe comenzi, fiecare comand fiind delimitat de urmtoarea prin ;. Se observ c lista comsnzi este opional, deci este perimis comanda complex goal BEGIN END; De asemenea, o comand compus poate fi etichetat cu label. V.1.4. Clauza SELECT ... INTO Sintaxa de selectare a coloanelor direct n variabile este SELECT nume_coloana[,] INTO nume_variabila[,] expresie_tabel; Prin urmare, doar un singur rnd poate fi returnat. 30

V.1.5. Clauza RETURNS Clauza RETURNS specificat pentru funcii indic tipul de date pe care le returneaz funcia. Corpul funciei trebuie s conin o comand RETURN valoare. V.1.6. Vizualizarea procedurii/funciei Prin comanda SHOW CREATE PROCEDURE/ SHOW CREATE FUNCTION nume_procedura se vizualizeaz codul de definire a procedurii, respectiv a funciei. Exemplu: SHOW CREATE PROCEDURE incasari_procedura;

Fig.V.1.4. Afiarea informaiilor referitoare la crearea procedurii incasari_procedura SHOW CREATE FUNCTION tva_functie;

Fig.V.1.5. Afiarea informaiilor referitoare la crearea funciei tva_funcie V.1.7. tergerea procedurilor i a funciilor stocate Eliminarea procedurilor i a funciilor stocate se realizeaz prin comanda DROP PROCEDURE nume_procedura; DROP FUNCTION nume_functie;

V.2.

Variabile locale, cursoare

Procedurile stocate conin faciliti pentru utilizarea structurilor de control, a variabilelor i introduc un concept foarte improtant, numit cursor. Aceti itemi locali ai rutinei se declar cu ajutorul comenzii DECLARE. V.2.1. Variabile locale Comanda DECLARE este permis doar n interiorul blocului BEGIN...END, apel care se face la nceput, naintea altor comenzi. DECLARE nume_var[,...] TYPE [DEFAULT valoare]; Clauza DEFAULT se introduce dac se dorete o variabil default lips. Valoarea poate fi specificat ca o expresie; nu este obligatoriu s fie constant. Dac se omite scrierea clauzei DEFAULT; valoarea iniial este NULL. Comanda SET are rolul de a atribui variabilelor anumite expresii. SET nume_variabila=expresie [, nume_variabila=expresie] Exemplul1: 31

SET a=10, b=Volvo Exemplul2: DELIMITER // CREATE PROCEDURE dec_examp() BEGIN DECLARE a CHAR(12) DEFAULT 'Buna!'; DECLARE b CHAR(12); DECLARE x, y INT; SET b = ' World'; SELECT CONCAT(a, b); SET x = 1; SET y = 2; SELECT x + y; END; // DELIMITER ; CALL dec_examp();

Fig.V.2.1.

Rezultatul procedurii dec_examp

Exemplul3: S se construiasc o funcie tva_modificat_functie astfel nct s se foloseasc o variabil local ce reprezint noul TVA. DELIMITER // CREATE FUNCTION tva_modificat_functie (pret DECIMAL(10,2)) RETURNS DECIMAL(10,2) BEGIN DECLARE modi DECIMAL(10,2) DEFAULT 0.1; RETURN pret*modi; END // DELIMITER; SELECT tva_modificat_functie(100);

Fig.V.2.2.

Rezultatul funciei tva_modificat_functie

V.2.2. Cursori i structuri de control Un cursor este un obiect al bazei de date pe care l utilizeaz aplicaiile n manipularea datelor prin tupluri, i nu prin mulimi de date. Un cursor seamn cu un 32

tablou; acesta regsete un set de rezultate pentru o interogare i permite prelucrarea rezultatului tuplu cu tuplu. Cursorii sunt utilizai atunci cnd se dorete examinarea secvenial a tuturor tuplurilor dintr-o relaie. Cursorii se declar i se folosesc doar n cadrul unei proceduri i funcii stocate. Sintaxa pentru declararea unui cursor este DECLARE nume_cursor CURSOR FOR comenzi_SELECT; n cadrul unei rutine se pot decrara mai muli cursori, dar fiecare trebuie s aib nume unic. nainte de a folosi un cursor, acesta trebui deschis prin comanda OPEN nume_cursor; Comanda de OPEN ruleaz de fapt interogarea. Pentru a obine fiecare nregistrare din interogarea cursorului, trebuie rulat o instruciune FETCH. Numele variabilei este numele variabilei locale declarat la nceput. FETCH nume_cursor INTO nume_var [,nume_var]; Cursorul trebuie nchis la finalul comenzilor prin CLOSE nume_cursor; Astfel, operaiunile principale ale cursorului sunt: - declararea cursorului printr-o fraz SELECT (cursor_nume FROM SELECT); - declararea variabilei n care va fi stocat un tuplu al cursorului; - deschiderea cursorului (OPEN); - ncrcarea urmtorului tuplu din cursor (FETCH); - structura de ciclare, obligatoriu, o comand de ncrcare a urmtorului tuplu din cursor. Exemplu: (Vezi exemplul 3 din subapitolul Exemple de Proceduri i Funcii Stocate) V.2.3. Comenzi de programare Comenzile de programare sunt: IF, CASE, LOOP, LEAVE, ITERATE, REPEAT, WHILE. Comanda IF Comanda IF implementeaz o construcie condiionat. Sintaxa este IF conditie_de_cautare THEN lista_de_comenzi [ELSEIF conditie_de_cautare THEN lista_de_comezi] [ELSE lista_de_comnezi] END IF; Dac conditie_de_cautare este adevrat, atunci se execut lista_de_comenzi corespunztoare. Dac toate condiiile_de_cutare sunt false, atunci se execut lista_de_comenzi din comanda ELSE. Exemplu: (Vezi exemplele 3 i 4 din subapitolul Exemple de Proceduri i Funcii Stocate). Condiia CASE 33

Condiia CASE pentru proceduri stocate implementeaz o construcie condiional complex. Sintaxa este CASE valoare_case WHEN valoare_when THEN lista_de_comenzi [WHEN valoare_when THEN lista_de_comenzi] [ELSE list_de_comenzi] END CASE sau CASE WHEN valoare_de_cautare THEN lista_de_comenzi [WHEN valoare_de_cautare THEN lista_de_comenzi] [ELSE list_de_comenzi] END CASE Precizrile de la comanda IF sunt valabile i n acest caz. Exemplu: (Vezi exemplul 5 din subapitolul Exemple de Proceduri i Funcii Stocate). Comanda LOOP Comanda LOOP implementeaz o construcie loop care ruleaz o parte specificat a codului- numit corpul comenzii loop- de mai multe ori succesiv. Comanda loop este controlat de o codiie, la fel ca i comanda IF sau CASE. Corpul comenzii loop va continua s se repete pn cnd condiia devine fals. Sintaxa este [begin_eticheta:] LOOP lista_de_comenzi END LOOP [end_eticheta] Comenzile din lista_de_comenzi se repet pn cnd se d comanda de finisare a comenzii loop. De obicei, aceasta este finisat cu comanda LEAVE. Comanda LEAVE Comanda LEAVE este utilizat la ieirea din orice construcie de control. Sintaxa este LEAVE label; Poate fi utilizat n inetriorul BEGIN...END sau n construciile LOOP, REPEAT, WHILE. Comanda ITERATE Comanda ITERATE poate s apar doar mpreun cu LOOP, REPEAT i WHILE. Sintaxa este ITERATE label; Comanda REPEAT 34

Sintaxa pentru comanda REPEAT este [begin_eticheta:] REPEAT lista_de_conditii UNTIL conditie END REPEAT [end_eticheta] Lista de comenzi se execut atta timp ct condiia este adevrat. Comanda REPEAT introduce mereu o comand LOOP, mcar o dat. Exemplu: (Vezi exemplul 3 din subcapitolul Exemple de proceduri i funcii stocate). Comanda WHILE Sintaxa pentru comanda WHILE este [begin_eticheta:] WHILE lista_de_conditii DO lista_de_comenzi END WHILE [end_eticheta] Lista de comenzi se execut atta timp ct condiia este adevrat.

V.3. Exemple de proceduri stocate


Exemplul1: Creai o funcie care s primeasc drept parametru de intrare atributul cnp i s furnizeze numrul de telefon al clientului cu cnp-ul respectiv (utiliznd BD AGENTIE_IMOBLIARA). /* Functia afiseaza nr de telefon al clientului pe baza cnp-ului sau*/ DELIMITER // CREATE FUNCTION telefonul(cnpul DECIMAL(13,0)) RETURNS VARCHAR(15) BEGIN DECLARE telefon VARCHAR(15); SELECT nr_telefon INTO telefon FROM DATE_PERSOANE WHERE cnp=cnpul; RETURN TELEFON; END // DELIMITER; SELECT telefonul(2820420223201);

Fig.V.3.1.

Afiarea numrului de telefon al clientului cunoscnd cnp-ul su

Exemplul2: (Includerea altor funcii n funcie) S se scrie o funcie care s calculeze numrul de zile dintre data curent i data la care s-a introdus n baza de date o ofert sau o cerere. Funcia va calcula vechimea ofertei (cererii) pe baza id-ului de nregistrare a ofertei (cererii) respective. Observaii: 35

1. Parametrul de intrare va fi id-ul cererii (ofertei), id_co; 2. Se vor declara dou variabile locale data_1 i data_2 care semnific data curent, respectiv data la care a fost fcut nregistrarea cererii (ofertei) n baza de date; 3. Se vor utiliza dou funcii din dicionarul aplicaiei MySql: funcia CURRENT_DAY() care afieaz data curent i funcia DATEDIFF() care efectueaz diferena, n zile, dintre dou date calendaristice. /* Functia cacluleaza vechimea unei oferte*/ DELIMITER // CREATE FUNCTION vechime3(co SMALLINT(7)) RETURNS VARCHAR(10) BEGIN DECLARE data_1 date; DECLARE data_2 date; SELECT CURRENT_DATE() INTO data_1; SELECT data_inreg INTO data_2 FROM CERERI_OFERTE WHERE co = id_co; RETURN CONCAT(DATEDIFF(DATA_1,DATA_2),' ','zile'); END; // DELIMITER; SELECT vechime3(1);

Fig.V.3.2.

Numrul de zile de la data nregistrrii n baza de date pn la data curent

Exemplul3: S se construiasc un cursor prin care s se mreasc cu 1000 u.m. preurile minime la imobilele cu preul mai mare ca 40000 u.m. DELIMITER // CREATE PROCEDURE test_cursor () BEGIN DECLARE v_id_co SMALLINT; DECLARE pret_mic DECIMAL (10,2); DECLARE done INT DEFAULT 0; DECLARE cursor1 CURSOR FOR SELECT id_co, pret_min FROM CERERI_OFERTE; DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = 1; OPEN cursor1; REPEAT FETCH cursor1 INTO v_id_co, pret_mic; IF (pret_mic>40000) THEN UPDATE CERERI_OFERTE C SET pret_min = pret_mic + 1000 WHERE v_id_co=c.id_co; END IF; 36

UNTIL done END REPEAT; CLOSE cursor1; END // DELIMITER; CALL test_cursor(); Observaii: 1. Cursorul cursor1 este pointerul ctre zona de lucru n care a fost deschis setul activ de nregistrri; 2. La nceput codul declar mai multe variabile locale care vor fi utilizate n procedur. Variabilele v_id_co i pret_mic stocheaz valorile id_co i pret_min din nregistrarea curent. 3. Urmtoarea variabil declarat este done, iniializat cu zero (false). Aceast variabil este indicatorul pentru bucle. n momentul n care nu mai exist nregistrri de comparat, se va atribui acestei variabile valoarea 1 (true). 4. Linia DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = 1; se numete declaraie de handler. Are un rol similar cu o excepie pentru procedurile stocate. 5. Un cursor trebuie declarat (DECLARE), deschis(OPEN), ncrcat (FETCH) i nchis (CLOSE). Exemplul4: S se specifice dac un imobil este ieftin, mediu sau scump, dup cum preul minim al imobilelor este mai imic decat 30000u.m., cuprins ntre 30000u.m. i 50000u.m., respectiv mai mare dect 50000u.m. DELIMITER // CREATE FUNCTION categorie_functie(id_co_v SMALLINT(7)) RETURNS VARCHAR(30) BEGIN DECLARE mesaj VARCHAR(30); DECLARE val DECIMAL(10,2); SELECT pret_min INTO val FROM CERERI_OFERTE WHERE id_co=id_co_v; IF val IS NULL THEN SET mesaj='Pretul nu a fost stabilit!'; RETURN MESAJ; END IF; IF val<30000 THEN SET mesaj='imobil ieftin'; ELSEIF val BETWEEN 30000 AND 50000 THEN SET mesaj='Imobil cu pret mediu.'; ELSE SET mesaj='Imobil de lux.'; END IF; RETURN mesaj; END; // 37

Exemplul5: S se scrie o funcie care s returneze, la cerere, pentru un angajat valoarea unuia dintre atributele adresa, nr_telefon sau email. DELIMITER // CREATE FUNCTION inf_client (cnp_ DECIMAL(13,0), atribut VARCHAR(200)) RETURNS VARCHAR(200) BEGIN DECLARE var VARCHAR(200); CASE WHEN atribut='numele' THEN SELECT numele INTO var FROM DATE_PERSOANE WHERE cnp=cnp_; WHEN atribut='adresa' THEN SELECT adresa INTO var FROM DATE_PERSOANE WHERE cnp=cnp_; WHEN atribut='email' THEN SELECT email INTO var FROM DATE_PERSOANE WHERE cnp=cnp_; END CASE; RETURN var; END; // DELIMITER ; SELECT inf_client(1820320223201,'numele');

(a) SELECT inf_client(1820320223201,'adresa');

(b) Fig.V.3.3. Afiarea opiunii numele (a), respective adresa (b) pentru un client specificat prin cnp-ul su

V.4. Declanatoare
Declanatorul (trigger) este un tip special de procedur stocat care este executat automat cnd un eveniment predefinit (inserare, actualizare sau tergere) modific o relaie. Utilizarea declanatoarelor este evident la formularea unor restricii mai complexe dect suport comezile CREATE/ALTER TABLE, actualizarea automat a unor atribute calculate, jurnalizarea modificrilor suferite de baza de date, pstrarea integritii refereniale etc. La definirea declanatorului se poate stabili de cte ori este executat acesta: de fiecare dat cnd un tuplu este inserat/modificat/ter sau o singur dat pentru o comand de actualizare, indiferent de cte tupluri sunt afectate. Astfel exist dou clase de declanatoare: - declanatoare la nivel de tuplu prin care se poate defini o aciune pentru fiecare 38

tuplu al tabelului - declanatoare la nivel de comand apar doar o dat ntr-o comand INSERT, UPDATE sau DELETE. Exemplu: Pentru mrirea cu un anumit procent a preurilor la ultimele 30 de imobile oferite spre vnzare n relaia CERERI_OFERTE a bazei de date AGENTIE_IMOBILIARA, un declaator la nivel de tuplu se va executa de 30 de ori, pe cnd unul la nivel de comand, o singur dat. De asemenea declanataorele se mai impart n: - declanatoare de tip nainte de actualizare (BEFORE) - declanatoare de tip dup actalizare (AFTER). Un declanator de tip BEFORE intr n aciune nainte de modificarea propriuzis i este util la verificarea unui set de condiii care ar putea bloca de la bun nceput tranzacia respectiv. Declaatorul de tip AFTER se execut dup momentul procedurii actualizrii, verificnd astfel corectitudinea operaiunii (nu s-a vndut un imobil fr s se ntocmeasc factura). Declanatoarele de tip AFTER blocheaz liniile procesate, iar cel de tip BEFORE nu le blocheaz. Cele patru tipuri de declanatoare pot fi combinate ntre ele. Printre cele mai importante trsturi ale declanatoarelor se enumer - declanatoarele nu accept parametrii i argumente; - nu execut COMMIT sau ROLLBACK deoarece declanatoarele fac parte ele nsele din blocuri de comand; - pot genera erori mari asupra tabelelor dac nu sunt exprimate corect. Sintaxa petrnu crearea unui declanator este CREATE TRIGGER nume_declansator timp_declansator eveniment_declansator ON nume_tabel FOR EACH ROW comanda_pentru_declansator Comanda timp_declansator precizeaz timpul de execuie al declanatorului: BEFORE sau AFTER, iar prin comanda eveniment_declansator se menioneaz tipul de comand ce uremaz s activeze trigger-ul. Evenimentele unui declanator sunt: - INSERT : declanatorul este activat de fiecare dat cnd un nou tuplu este inserat n relaia specificat; - UPDATE: declanatorul este activat de fiecare dat cnd un tuplu este modificat; - DELETE: declanatorul este activat de fiecare dat cnd un tuplu este eliminat din relaie. Dac declanatorul conine mai multe comenzi, atunci acestea se trec n blocul BEGINEND. Exemplu: (Declanator BEFORE pentru INSERT) S se construiasc un declanator care calculeaz valoarea TVA din preul imobilului ce va aprea pe factur, precum i totalul facturii. Astfel, la fiecare nou inserare n relaia FACTURI, cmpul tva s fie automat completat prin itermediul acestui declanator. DELIMITER // 39

CREATE TRIGGER tva_total_triger BEFORE INSERT ON FACTURI FOR EACH ROW BEGIN SET new.tva=new.pret * 0.09; SET new.total=new.tva+new.pret; END; // DELIMITER ; INSERT INTO FACTURI (nr_factura,id_co,data_factura,cnp,pret) VALUES (6,14,'2007-02-03',1820320223201,10000); SELECT * FROM FACTURI;

Fig.V.4.1. Inserarea automat a valorii TVA i a valorii total prin intermediul declanatorului tva_total_triger Exemplul2: (Declanator AFTER pentru INSERT) S se construiasc un declanator care actualizeaz coloana tip_solutionare cu valoarea 1 (1 nseamn imobil vndut) odat cu inserarea unei noi facturi, pentru imobilul facturat. DELIMITER $ CREATE TRIGGER solutionare_triger AFTER INSERT ON FACTURI FOR EACH ROW BEGIN UPDATE CERERI_OFERTE SET tip_solutionare=1; END; $ DELIMITER ; Informaiile corespunztoare imobilului cu identifcatorul id_co=14 din relaia CERERI_OFERTE nainte ca acesta s fie vndut sunt:

Fig.V.4.2. Imobilul nainte de vnzare (tip_solutionare este 0) INSERT INTO FACTURI (nr_factura,id_co,data_factura,cnp,pret) VALUES (6,14,'2007-02-03',1820320223201,10000); Dup facturarea acestui imobil, informaiile legate de imobil devin: 40

Fig.V.4.3. Imobilul dup vnzare (tip_solutionare este 1) Exemplul3: (Declanator AFTER pentru DELETE) S se construiasc un declanator care controleaz integritatea n cazul eliminrii descrierii unui imobil din relaia copil DESCRIERE_IMOBIL, n sensul c el va elimina i tuplul corespunztor din relaia printe CERERI_OFERTE. DELIMITER $ CREATE TRIGGER eliminare_triger AFTER DELETE ON DESCRIERE_IMOBIL FOR EACH ROW BEGIN DELETE FROM CERERI_OFERTE WHERE ID_CO=OLD.ID_CO; END; $ DELIMITER ; DELETE FROM DESCRIERE_IMOBIL WHERE id_co=30; nregistrarea cu numrul 30 va fi eliminat din ambele relaii. n aceeai manier, exemplele pot continua.

41

B. Probleme propuse
99. Realizai urmtoarele inserri de date pentru baza de date AGENTIE_IMOBILIARA: a) Inserai 10 localiti n judee diferite, precum i cteva denumiri de strzi corespunztoare localitilor introduse. b) Inserai cte un client pentru fiecare dintre situaiile urmtoare: client cu toate datele personale cunoscute, client fr telefon, client fr adres de mail, client fr adres, client cu adres, dar fr numr de telefon i adres email. c) Inserai oferte, apoi cereri de imobile ale clienilor de mai sus, n diferite localiti, preciznd ct mai variate informaii despre aceste oferte. d) Realizai finalizri ale unora dintre aceste oferte i cereri, insernd date n facturi. Alegei rspunsurile corecte: 100. Instruciune INSERT cu o claz VALUES a) tebuie s aib o list de coloane; b) tebuie s aib o list de valori; c) poate insera tupluri multiple la o singur rulare; d) poate folosi cuvntul NULL pentru a atribui valori nule coloanelor; e) poate include o clauz WHERE. 101. instruciune INSERT cu o comand SELECT imbricat este util pentru a) gsirea urmtoarei valori pentru o cheie primar atribuit secvenial b) mutarea rndurilor dintr-un tabel n altul c) popularea unei relaii de test cu date dintr-oalt relaie d) eliminarea tuplurilor duplicat dintr-o relaie e) inserarea mai multor tupluri ntr-o relaie cu o singur instruciune. 102. Instruciunea SELECT intern a unei instruciuni INSERT poate include a) o clauz WHERE b) o clauz GROUP BY c) o uninue a mai multor tabele d) o clauz UNION. 103. S presupunem c avei o relaie denumit FRUCTE coninnd un id, un nume de fruct i starea fructului (copt sau putred). Creai relaia FRUCTE, inserai cteva date n aceast relaie, apoi actualizai starea fructului la copt. 104. Presupunnd c n relaia FRUCTE din problema anterioar, o nregistrare are o greeal de scriere (stugri n loc de struguri), s se corecteze aceast greeal. 105. Modificai preurile maxime cu o micorare cu 0.7% la ofertele de terenuri din localitatea Braov din baza de date AGENTIE_IMOBILIARA. 106. Actualizai cantitile de componente distribuite de furnizorii F1, F3, i F4 astfel: F1 are la toate componentele o mrire cu 270 de componente, F3 la componenta C2 are o mrire de 100 buci, iar F4, la C4,C5 cu cte 150 componente (se utilizeaz baza de date FRUNIZORI_COMPONENTE). 42

107. instruciune UPDATE fr o clauz WHERE a) actualizeaz toate tuplurile din relaie cu valori nule b) ncearc s actualizeze toate tuplurile din relaie c) eueaz i returneaz o eroare d) terge toate tuplurile din relaie e) are ca rezultat un produs cartezian. 108. Instruciunea UPDAT a) trebuie s includ o clauz SET b) trebuie s furnizeze o nou valoare pentru cel puin o clauz c) terbuie s includ o clauz WHERE d) poate atribui unui atribut valoarea unei alt atribut e) poate atribui unui atribut o list de valori dintr-o expresie. 109. Clauza SET dintr-o instruciune UPDATE poate atribui unui atribut o valoare care este a) o constant b) numele unei alte coloane c) o list de valori d) orice expresie din care rezult o singur valoare e) cuvntul cheie NULL. 110. Prin ce instruciune se realizeaz eliminarea unei nregistrri dintr-o relaie? Dar a unui atribut? 111. S se elimine toate nregistrrile corespunztore fructelor alterate din tabela FRUCTE. 112. S se elimine cea mai veche nregistrare de cerere din baza de date AGENTIE_IMOBILIARA. 113. S se elimine cea mai scump ofert din baza de date AGENTIE_IMOBILIARA. 114. O instruciune DELETE fr o clauz WHERE a) actualizeaz toate tuplurile din relaie cu valori nule b) eueaz i returneaz o eroare c) ncearc s terag toate tuplurile din relaie d) are ca rezultat un produs cartezian e) trebuie s includ o list de atribute. 115. instruciune DELETE a) poate include o list opional de atribute b) poate include o clauz WHERE opional c) nu poate nclca restricile refereniale ale relaiei d) poate avea instruciunea SELECT ca parte a clauzei WHERE. 116. Instruciunea CREATE INDEX a) poate fi folosit pentru crearea restriciilor de unicitate i cheie primar b) poate include cuvntul cheie UNIQUE c) trebuie s refere dou sau mai multe nume de atribute d) poate include cuvintele cheie ASC sau DESC pentru orice atribut e) poate specifica ordinea ascendent sau descendent pentru una sau mai multe atribute. 117. Instruciunea DROP poate fi folosit pentru a terge a) o restricie referenial b) un index c) o relaie d) un atribut dintr-o relaie e) o vizualizare. 43

118. Alegei indeci pentru baza de date AGENTIE_IMOBILIARA astfel nct acetia s optimizeze cele mai des utilizate interogri ale acestei baze de date. 119. Instruciunea CREATE VIEW a) stocheaz o interogare n baza de date b) poate include cuvntul cheie CASCADE c) poate include cuvntul cheie opional OR REPLACE d) trebuie s conin o comand DML valid e) trebuie s conin o instruciune SELECT valid. 120. Definii o vedere pentru furnizorii din Bucureti pentru baza de date FURNIZORI_COMPONENTE. 121. Definii o vedere format din furnizorii i componentele ce nu se afl n acelai ora. 122. S se creeze o vizualizare care conine numele clientului, numrul imobilelor oferite spre vnzare i valoarea medie a acestora. 123. S se creeze vizualizarea cereri ce va conine identificatorul cererii, data nregistrrii, cnp-ul clientului i tipul tranzaciei, adic cerere. 124. S se adauge o constrngere de cheie primar asupra vizualizrii cereri. 125. O tranzacie a) poate fi pocesat parial b) nu poate fi procesat parial c) schimb baza de date dintr-o stare consistent n alta d) are prorpieti descriese de acronimul ACID. 126. Procesul care anuleaz modificrile efectuate de o tranzacie euat este numit a) nregistrarea tranzaciei b) finalizare c) refacere d) recuperare e) crearea unui punct de salvare. 127. Procesul care permanentizeaz modificrile efectuate de o tranzacie euat este numit a) nregistrarea tranzaciei b) finalizare c) refacere d) crearea unui punct de salvare e) salvarea tranzaciei. 128. Suportul pentru tranzacii n baze de date relaionale include f) identificarea nceputului fiecrei tranzacii g) identificarea sfritului fiecrei tranzacii h) managementul bazei de date distributive i) slavri periodice ale bazei de date j) jurnalul de tranzacii. 129. Realizai o tranzacie care s introduc un nou client i datele despre cererea sa n baza de date AGENTIE_IMOBILIARA. 130. S se nregistreze (cu ajutorul tranzaciilor) n baza de date AGENTIE_IMOBILIARA procesul de facturare al unui imobil vndut i al unui imobil cumparat de aceeai persoan. 131. Cantitatea de date afectat de o blocare poate fi a) o baz de date b) o relaie c) un tuplu 44

d) un atribut e) un bloc sau o pagin. 132. Blocarea a) este un element de control ataat datelor pentu a le rezolva n scopul actualizrii de ctre utilizator b) etse anulat de obicei atunci cnd are loc o operaie COMMIT sau ROLLBACK c) poate provoca apariia unor conflicte atunci cnd ali utilizatori ncearc s actualizeze datele blocate. 132. S se realizeze cerea de la exerciiul 130, blocnd tabelele utilizate. 133. Creai proceduri stocate i funcii stocate pentru bazele de date: a) AGENTIE_IMOBILIARA b) COLECTIE_MUZICALA c) FURNIZORI_COMPONENTE. 134. Un cursor este a) colecia de tupluri returnate de o interogare la baza de date b) un pointer (indicator) ntr-un set de rezultate c) acelai lucru cu un set de rezultate d) un buffer care psreaz tuplurile extrase din baza de date e) o metod de analiz a performanei instruciunilor SQL. 135. nainte ca tuplurile s poat fi extrase dintr-un cursor, cursorul trebuie s fie a) declarat b) finalizat c) deschis d) inchis e) dezalocat. 136. Creai declanatoare de tip INSERT, UPDATE, DELETE n combinaie cu AFTER i BEFORE.

45

Cuprins
III.SQL (continuare)...................................................................................................................1 IV.Limbajul de control al bazelor de date (LCD).....................................................................17 V.Procedural n SGBD..............................................................................................................28 B.Probleme propuse..................................................................................................................42 Cuprins......................................................................................................................................46

46

Bibliografie
1. Baze de date-Organizare, proiectare i implementare- Ion Lungu, Constanta Bodea, Georgeta Bdescu, Crsitian Ioni, Ed. ALL Educational, Bucureti, 1995. 2. Proiectarea bazelor de date. Normalizare i postonormalizare. Implementri SQL i Oracle- Marin Fotache, Ed. Polirom. 3. Baze de date relaionale - proiectare i implementare- Ileana Popescu, Editura Universitii din Bucureti, 1996. 4. Transact SQL- tefan Ardeleanu, Ed. Niculescu. 5. SQL. Dialecte DB2, Oracle i Visual FoxPro- Marin Fotache, Polirom, 2001. 6. Oracle 9i2. Ghidul dezvoltrii aplicaiilor profesionale- Marin Fotache, Ctlin Strmbei, Liviu Creu, Polirom, 2003. 7. Ileana Popescu, Modelarea bazelor de date, Ed. Tehnic, Bucureti, 2001. 8. Paul DuBois, MySQL, Teora, 2001. 9. Grupul BDASEING, Baze de date. Fundamente teoretice i practice, Ed. Infomega, 2002. 10. Ken Henderson, Proceduri stocate n SQL Server XML, HTML, Teora, 2003. 11. Robert Dellinger , Baze de date i gestionarea tranzaciilor, Ed. Albastr, ClujNapoca, 2000.

47

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