Sunteți pe pagina 1din 98

Programarea sistemelor

de masura I
Note de curs
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

Cuprins
1 INTRODUCERE........................................................................................................................................................5
1.1 CE ESTE O BAZĂ DE DATE...................................................................................................................................5
1.2 AVANTAJELE UTILIZĂRII BAZELOR DE DATE.......................................................................................................6
1.3 INSTALAREA BAZEI DE DATE...............................................................................................................................7
1.3.1 Instalare Oracle 9i, 10g.............................................................................................................................8
1.3.2 Verificarea instalării bazei de date............................................................................................................9
1.3.3 Dezinstalarea bazei Oracle. Exportul informaţiilor din bază.................................................................10
1.3.3.1 Salvarea bazei de date.........................................................................................................................................10
1.4 CE ESTE LIMBAJUL SQL...................................................................................................................................11
2 NOŢIUNI DE BAZĂ DESPRE PROIECTAREA BAZELOR DE DATE........................................................12
2.1 DETERMINAREA SCOPULUI BAZEI DE DATE......................................................................................................12
2.2 MODELUL ENTITATE-ASOCIERE........................................................................................................................13
2.3 CONVERSIA ELEMENTELOR INFORMAŢIONALE ÎN COLOANE DE TABELE..........................................................15
2.4 SPECIFICAREA CHEILOR PRIMARE.....................................................................................................................17
2.5 CREAREA RELAŢIILOR DINTRE TABELE.............................................................................................................18
2.5.1 Crearea relaţiilor de tipul unu-la-mai-mulţi............................................................................................19
2.5.2 Crearea relaţiilor de tipul mai-mulţi-la-mai-mulţi..................................................................................19
2.5.3 Crearea relaţiilor de tipul unu-la-unu.....................................................................................................19
2.6 APLICAREA REGULILOR DE NORMALIZARE.......................................................................................................20
2.6.1 Prima formă normală...............................................................................................................................20
2.6.2 A doua formă normală.............................................................................................................................21
2.6.3 A treia formă normală..............................................................................................................................22
2.6.4 De ce trebuie adusă o bază de date la forma normală trei......................................................................23
2.7 RAFINAREA BAZEI DE DATE..............................................................................................................................24
3 CREAREA BAZEI DE LUCRU...........................................................................................................................26
3.1 CREAREA CONTULUI UTILIZATOR ÎN BAZA DE DATE........................................................................................26
3.2 CREAREA TABELELOR ÎN BAZA DE DATE..........................................................................................................26
3.3 TIPURI DE DATE DEFINITE ÎN BAZA DE DATE....................................................................................................27
4 CONSTRÂNGERI.................................................................................................................................................29
4.1 CONSTRÂNGERI DE TIP PRIMARY KEY (PK).....................................................................................................29
4.1.1 Completarea valorilor din cheile primare...............................................................................................29
4.1.2 Crearea și utilizarea indexilor.................................................................................................................30
4.1.3 Indexii accelerează căutarea, dar încetinesc modificările de date..........................................................30
4.2 CONSTRÂNGERI DE UNICITATE (UK)................................................................................................................30
4.2.1 Crearea constrângerilor de unicitate fără validarea datelor..................................................................31
4.2.2 Activarea și dezactivarea constrângerilor...............................................................................................31
4.3 CONSTRÂNGERI DE TIP "NOT NULL" (NN).......................................................................................................31
4.4 CONSTRÂNGERI DE TIP "FOREIGN KEY"...........................................................................................................32
4.5 CONSTRÂNGERI DE TIP "CHECK".......................................................................................................................32
4.6 DEFINIREA CONSTRÂNGERILOR ÎN BAZA DE DATE "STUD"...............................................................................32
5 INTRODUCEREA DATELOR ÎN TABELE......................................................................................................34
5.1 SINTAXA COMENZII INSERT...............................................................................................................................34
5.2 VALOAREA NULL............................................................................................................................................34

Page 2 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

5.3 INTRODUCEREA DATELOR ÎN TABELE...............................................................................................................35


6 EXTRAGEREA INFORMAŢIILOR DIN BAZA DE DATE............................................................................36
6.1 COMANDA SELECT.........................................................................................................................................36
6.1.1 Selectarea datelor dintr-un database link................................................................................................37
6.2 CERERI SELECT PE MAI MULTE TABELE. EQUI-JOIN.......................................................................................37
6.3 JOIN EXTERN.....................................................................................................................................................39
6.4 CLAUZA WHERE. OPERATORI LOGICI................................................................................................................41
6.4.1 Operatori de comparaţie..........................................................................................................................41
6.4.2 Operatori AND , OR, NOT.......................................................................................................................42
6.4.3 Operatorul "between"..............................................................................................................................43
6.4.4 Operatorul "in"........................................................................................................................................44
6.4.5 Operatorul "like"......................................................................................................................................44
6.4.6 Clauza distinct..........................................................................................................................................45
6.4.7 Operatorul "is null".................................................................................................................................46
6.5 CLAUZA ORDER BY.......................................................................................................................................46
7 FUNCŢII SQL........................................................................................................................................................49
7.1 FUNCŢII PENTRU PRELUCRAREA ŞIRURILOR DE CARACTERE............................................................................49
7.2 FUNCŢII PENTRU VALORI NUMERICE................................................................................................................50
7.3 FUNCŢII PENTRU DATE CALENDARISTICE.........................................................................................................51
7.4 FUNCŢII PENTRU CONVERSIA TIPULUI DE DATE...............................................................................................52
7.4.1 Conversia datelor de tip "date" în şiruri de caractere............................................................................52
7.4.2 Conversia numerelor în şiruri de caractere.............................................................................................53
7.4.3 Conversia datelor de tip text in format "date".........................................................................................54
7.4.4 Conversia textului in format numeric......................................................................................................54
7.5 FUNCŢIA DECODE...........................................................................................................................................55
7.6 FUNCŢII DE GRUP..............................................................................................................................................56
7.6.1 Funcţii matematice de grup.....................................................................................................................56
7.6.2 Clauza "group by"....................................................................................................................................57
8 SUBINTEROGĂRI................................................................................................................................................60
8.1 CONSTRUCŢIA CLAUZEI "WHERE" PRIN SUBINTEROGARE.................................................................................60
8.2 COLOANE OBŢINUTE PRIN SUBINTEROGĂRI......................................................................................................61
8.3 TABELE INTERMEDIARE....................................................................................................................................62
8.4 VIZUALIZĂRI.....................................................................................................................................................63
9 INSTRUCŢIUNI DML..........................................................................................................................................65
9.1 COMANDA INSERT..........................................................................................................................................65
9.1.1 Folosirea funcţiilor pentru completarea valorilor de insert....................................................................66
9.1.2 Utilizarea subinterogărilor în comanda insert........................................................................................66
9.2 COMANDA UPDATE........................................................................................................................................67
9.3 COMANDA DELETE.........................................................................................................................................67
9.3.1 Stergerea în cascadă................................................................................................................................68
10 TRANZACŢII ÎN BAZA DE DATE................................................................................................................70
10.1 COMANDA ROLLBACK......................................................................................................................................70
10.2 COMANDA COMMIT..........................................................................................................................................70
10.2.1 Commit implicit........................................................................................................................................71
10.2.2 Comanda Savepoint.................................................................................................................................71
11 PL/SQL................................................................................................................................................................73
11.1 STRUCTURA PROGRAMELOR PL/SQL...............................................................................................................73
11.2 FUNCŢIA DE CALCUL A MEDIEI PONDERATE.....................................................................................................74

Page 3 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

11.3 TRIGGERI...........................................................................................................................................................76
11.3.1 Completarea automată a coloanelor de tip PK.......................................................................................77
11.3.2 Verificarea notelor obţinute de studenţi..................................................................................................78
12 BIBLIOGRAFIE................................................................................................................................................80
13 ANEXE................................................................................................................................................................81
13.1 INSTRUCTIUNILE SQL PENTRU CREAREA OBIECTELOR ÎN BAZA DE DATE........................................................81
13.1.1 Creare tabele............................................................................................................................................81
13.1.2 Introducerea date în bază........................................................................................................................85
13.2 FRAZE SELECT ÎN BAZA DE DATE......................................................................................................................89
13.2.1 Studenti-grupe-discipline-note.................................................................................................................89
13.3 Creare useri, import, export..............................................................................................................................90

Page 4 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

1 Introducere
Prezentul indrumar de curs se adreseaza studentilor de la Facultatea de Inginerie Electrica, Energetica si
Informatica Aplicata ce studiaza disciplina " Programarea sistemelor de masura I".
Acest curs se vrea un îndrumar pentru cei care vor să se iniţieze în domeniul bazelor de date, ca o prima
componenta necesara in dezvoltarea unei aplicatii de programare majora. Este un curs introductiv destinat
în principal utilizatorilor bazelor de date, adică celor ce accesează baza pentru obţinerea de informaţii utile,
fără să cunoască în mod obligatoriu cum a fost proiectată baza de date sau alte tehnici de administrare a
bazei. Se axează în principal pe instrucţiunile SQL (Structured Query Language) cu care utilizatorul obișnuit
trebuie să lucreze pentru a introduce informaţii în bază, să modifice aceste informaţii în timp și să scoată
apoi rapoarte și analize complexe specifice domeniului de lucru.

Ca metodă de lucru, pe parcursul cursului se va proiecta o bază de date minimală care să stocheze
informaţiile specifice activităţii dintr-o unitate de învăţământ superior: studenţii înscriși în facultate, grupele
de care aparţin, specializările, disciplinele studiate și notele obţinute. Fiecare cursant va trebui să treacă
prin toate fazele necesare realizării acestui sistem de stocare și administrare a datelor: crearea tabelelor,
introducerea datelor în tabele, modificarea datelor, selectarea și filtrarea datelor, realizarea de situaţii
specifice activităţii didactice.

1.1 Ce este o bază de date


Baza de date reprezintă un sistem de stocare şi gestionare a informaţiei. Calculatorul s-a impus în toate
domeniile de activitate în primul rând datorită capacităţii sale extraordinare de administrare a informaţiei.
Cum informaţiile au devenit din ce în ce mai complexe şi mai numeroase, a apărut necesitatea unui
program care să poată ţine controlul atâtor date, să răspundă la cererile mai multor utilizatori simultan, să
facă backup şi să asigure consistenţa datelor.
De exemplu, pentru aplicaţia pe care dorim să o dezvoltăm, ar trebui să salvăm pe disc câte un fişier care
să conţină numele studenţilor, un fişier pentru disciplinele parcurse de aceştia, un fişier cu notele obţinute
etc. Problema sălvării şi citirii datelor din fişier trebuie să fie rezolvată de către programator care trebuie să
ştie în orice moment poziţia curentă din fişier pentru studentul vizat. Programatorul trebuie să-şi
implementeze o hartă a stocării informaţiei, astfel încât să fie capabil în orice moment să găsească
informaţiile necesare unui student specificat. Acest task presupune un efort imens din partea
programatorului şi este vulnerabil erorilor de programare. Problema se complică foarte mult dacă sunt mai
mulţi utilizatori care accesează simultan informaţia: un profesor încarcă notele de la examen, un alt profesor
trece absenţele în catalog şi mulţi alţi studenţi încearcă să vadă ce note au obţinut la ultimul examen.

Page 5 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

Este mult mai simplu să utilizăm un sistem de gestionare a informaţiei care să primească toate datele
referitoare la activitatea didactică din facultate şi apoi să ne dea informaţia de care avem nevoie pentru un
student anume. Acest sistem este baza de date.
Alt exemplu ce justifică necesitatea bazelor de date este dat de gestionarea activităţii într-o întreprindere.
Suntem într-o întreprindere de câteva mii de angajaţi. Activitatea întreprinderii este împărţită pe diverse
servicii: aprovizionare, desfacere, întreţinere a echipamentelor, producţie, serviciul financiar, contabilitate,
magazia, salarizare, personal , etc.
Să luăm magazia: aici trebuie ţinută evidenţa tuturor articolelor necesare în procesul de producţie. Sunt
sute de mii de articole: de la articole mărunte de tip şurub, pix, electrod sudură, la subansambluri,
semifabricate şi produse finite destinate desfacerii. Fiecare articol poate proveni de la mai mulţi furnizori
având preţuri şi calităţi diferite. Când se face o intrare în magazie a unui articol, se completează un
document care merge la serviciul financiar ce ţine evidenţa facturilor şi a clienţilor, documentul se contează
apoi la serviciul contabilitate ce ţine evidenţa pe conturi de cheltuieli şi aşa mai departe. În orice moment
trebuie ştiută situaţia cantitativă şi valorică a magaziei. Cei de la producţie lansează în fabricaţie un nou lot;
există piesele necesare în magazie? La ce preţ va rezulta noul produs ţinând cont că s-au utilizat şuruburi
din loturi diferite şi la preţuri diferite? Care este valoarea articolelor din magazie? Care este situaţia contului
de TVA? Câte produse sunt în magazie pentru desfacere? Aceste situaţii trebuie date în condiţiile în care
sunt mai multe magazii care suportă tranzacţii de intrare-ieşire în mod permanent.
Soluţia acestei probleme complexe este baza de date. O singură bază de date ce rulează pe server, toţi
utilizatorii lucrează simultan pe bază astfel încât să avem în orice moment situaţia cumulată a tuturor
tranzacţiilor. În orice moment persoanele din conducere pot vedea ce clienţi au datorii mai mari de o limită
sau mai vechi de un anumit termen, situaţia băncilor, situaţia salariilor, cash-flow-ul, etc şi pe baza acestor
informaţii să ia decizii în cunostinţă de cauză.
Este clar ca astăzi nu mai poate fi construită o aplicaţie serioasă care să nu aibă în spate o bază de date.
De aceea, la orice interviu de angajare la o firma din domeniul informatic se cer cunoștinţe minime de SQL
şi baze de date.

1.2 Avantajele utilizării bazelor de date

Baza de date reprezintă un depozit unic al tuturor datelor dintr-o organizaţie. Spre deosebire de stocarea
datelor în fișiere proprii, dispersate în formate diferite prin departamente diferite și de multe ori redundante,
baza de date stochează o singură dată o informaţie care este vizibilă și poate fi accesată de mai mulţi
utilizatori simultan.
Acest mod unic de stocare a datelor oferă posibilitatea implementării unor funcţionalităţi foarte avantajoase
și utile în procesarea informaţiilor:

Page 6 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

 Reducerea redundanţelor: datele stocate în fișiere dispersate conţin în foarte multe cazuri dubluri
ale datelor. De exemplu, în cadrul unei facultăţi, numele si prenumele unui student se regăsește în
fișierele pe care le ţine profesorul, apoi trebuie să fie și la secretariat, la serviciul social, etc.
Aceeași informaţie stocată de mai multe ori. Este mult mai avantajos să fie stocată o singură dată
în baza de date unică și accesată de toate departamentele.
 Evitarea inconsistenţelor: dacă un student își modifică adresa de exemplu, această modificare ar
trebui procesată în toate fișierele de la diverse departamente. Dacă un anumit departament nu
modifică adresa (din diverse motive: nu știe ca s-a schimbat adresa, sau uită pur și simplu, sau
introduce greșit noua adresă), atunci datele stocate în fișiere vor fi inconsistente: aceeași
informaţie va avea valori diferite la departamente diferite. In cazul utilizării bazei de date, acest
lucru nu este posibil deoarece acea informaţie este stocată o singură dată.
 Aplicarea restricţiilor de securitate a datelor: se pot defini reguli de securitate prin care se permite
accesul utilizatorilor pe bază de parolă, iar fiecare utilizator are acces doar la un set predefinit de
date. De exemplu, un student nu trebuie să aibă posibilitatea de a modifica o notă, sau un profesor
să pună note la discipline la care nu este repartizat.
 Aplicarea regulilor de validare a integrităţii datelor: se pot defini diverse constrângeri de validare a
datelor care să nu permită introducerea de date eronate în bază. De exemplu, baza de date nu
permite înscrierea unui student la grupa 6411, dacă această grupă nu există în structura
organizatorică a facultăţii.
 Independenţa între date și programele de aplicaţii: pot fi construite o mulţime de aplicaţii care să
lucreze cu aceeași bază de date: o pagina WEB de afișare a listelor de studenţi, o aplicaţie
desktop pentru profesor care să gestioneze notele la o disciplină, etc. Dezvoltatorul de aplicaţii nu
trebuie să se preocupe de modul de stocare a datelor, ci doar de modul de regăsire și modificare a
acestora. In plus, se poate schimba structura bazei de date fără a necesita modificarea aplicaţiilor.
Independenţa include două componente:
o Independenţa fizică: stocarea efectivă a datelor în fișiere pe disc este problema
sistemul de gestiune a bazei de date (SGBD), programatorul de aplicaţii nu trebuie să
aibă in grijă acest aspect. Se pot schimba locaţiile acestor fișiere fără a afecta în niciun
fel programele de aplicaţii.
o Independenţa logică: se poate modifica structura logică a bazei de date (creare de noi
tabele, modificarea relaţiilor, a structurii de tabele) fără a afecta programele de aplicaţii.
In acest mod, programatorul și administratorul bazei de date pot să-și întreţină
aplicaţiile în mod independent, atât timp cât se respectă interfaţa stabilită între aceste
aplicaţii.

Page 7 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

1.3 Instalarea bazei de date


Primul pas în dezvoltarea aplicaţiei este instalarea bazei de date în care să definim tabelele cu informaţii.
Ce bază de date alegem? Sunt mai multe soluţii, în funcţie de numărul de utilizatori care lucrează simultan
pe bază şi de resursele financiare disponibile.
Dacă banii reprezintă un criteriu serios, atunci putem opta pentru baza Microsoft Acces care este inclusă în
pachetul Microsoft Office la un preţ rezonabil (totuşi baza Acces nu rezistă la mai multe de 5-10 conexiuni
simultane, de aceea nici nu este considerată bază de date în adevaratul sens al cuvântului). Mai sunt
variantele free, care se pot utiliza în mod gratuit: MySQL, SQLite, SQLExpress, etc.
Totuși, bazele de date ce se remarcă prin stabilitate, capacitate de stocare, accesare simultană de către
mai mulţi useri, rapiditate în stocarea și selectia datelor sunt date de SQL Server sau Oracle.
SQL Server reprezintă soluţia propusă de Microsoft pentru aplicaţii cu baze de date şi care este integrată
cu pachetul Microsoft Visual Studio .NET de construire a aplicaţiilor.
Firma Oracle construieşte motorul de baze de date de câteva zeci de ani şi s-a impus ca lider mondial în
acest domeniu. Noi alegem serverul Oracle ca să putem beneficia de toate facilităţile unei baze de date:
secvenţe, triggeri, constrângeri, funcţii PL/SQL, proceduri stocate, instrucţiunea DECODE, etc.

Observaţie: din comoditate, s-a încetăţenit în limbajul curent formularea "bază de date" atât pentru baza de
date efectivă (cea care conţine datele), cât și pentru Sistemele de Gestiune a Bazelor de Date (SGBD)
(sistemul prin care comunic cu baza de date). De exemplu, Oracle reprezintă un SGBD în care se pot crea
și dezvolta diverse baze de date: pentru studenţi, pentru instituţii, etc, dar în practica curentă spunem "o
bază de date Oracle". In documentul curent folosim acest termen pentru ambele noţiuni, în speranţa că se
deduce din context termenul la care se face referire.

1.3.1Instalare Oracle 9i, 10g

Versiunea 9i a serverului Oracle Server include 3 CD-uri. Se introduce primul CD în unitate şi se parcurge
toţi paşii programului de instalare dând click pe butonul Next la toate ferestrele Wizard-ului de instalare.
Binenţeles, nu poţi scăpa peste tot cu Next, undeva te întreabă cum se va chema baza de date pe care vrei
s-o construieşti (noi punem "stud") , te mai întreabă parolele pentru utilizatorii "sys" şi "system". Aici daţi ce
parolă vreţi, dar e bine să nu intraţi cu aceste parole în bază. Vom crea un utilizator "stud" cu parola "stud"
în schema căruia vom construi toate tabelele de care avem nevoie.

Daca totul merge OK , la sfârşitul instalării vor apărea pe disc un folder "Oracle" şi mai multe servicii cu
denumirea Oracle (programul "Services" din Settings/Control Panel/Administrative Tools/Services pentru
sistemul de operare Win XP). După cum aţi presupus, baza de date lucrează ca un serviciu Windows.

Page 8 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

Serviciile Windows sunt programe care se lansează automat la pornirea calculatorului. Dintre toate
serviciile instalate de Oracle, ne interesează două: "OracleServiceStud" dacă am denumit baza de date
"stud" şi "OracleOraHome92TNSListener". Primul este baza de date, al doilea este serviciul ce se ocupă de
comunicaţii (ascultă la port comenzile către bază şi le transmite mai departe la baza de date).

Baza Oracle ocupă o bună parte din memoria RAM a calculatorului. De aceea, dacă nu avem treabă cu
baza la un moment dat, e bine s-o oprim ca să eliberăm din resursele hardware ale calculatorului.

Cum oprim baza? Mergem în Services , click dreapta pe serviciul "OracleServiceStud" şi selectăm "Stop".
Problema e ca baza porneşte din nou la următoarea startare a calculatorului. Ca să scăpăm de acest lucru,
mergem la acelaşi serviciu , click dreapta, şi selectăm "Properties". Selectăm la opţiunea "Startup Type"
valoarea "Manual". Din acest moment baza nu va porni decât atunci când mergem noi în Services şi dăm
"Start" pe acel serviciu. Binenţeles, dacă baza nu-i pornită, nu o putem utiliza.

1.3.2Verificarea instalării bazei de date

Primul lucru care-l facem după instalarea bazei este să verificăm funcţionarea acesteia. Există un program
în Start\Programs\Oracle-OraHome92\Enterprise Manager Console. Putem intra în acest program şi să
gestionăm baza de date. Ne întreabă un user şi o parolă unde introducem "system" cu parola
corespunzatoare.

Trebuie să ne obişnuim că orice acces la baza de date se face prin parolă. Baza conţine informaţii de
importanţă capitală pentru instituţia respectivă (întreprindere, bancă, ...). De aceea nu putem lăsa pe oricine
să acceseze şi să modifice informaţia.

Chiar daca Enterprise Manager Console este un program agreabil, ce ne poartă prin toată bucătăria bazei,
nu vom lucra cu acest program, tocmai că este prea puternic pentru noi şi putem strica ceva în mod
ireversibil. Acest program este pentru administratorii bazelor de date, cei care se asigură ca baza să
funcţioneze şi răspund pentru acest task.

Pentru un utilizator obișnuit al bazei de date, vom utiliza un editor de SQL prin care vom scrie comenzi
către baza de date. Un astfel de editor care vine cu baza este Start\Programs\Oracle-
OraHome92\Application development\SQL Plus. Ne întreabă iarăşi user, parola şi "Host String", adică
numele bazei de date pe care ne conectăm. Evident, aici tastăm "stud". Putem avea surpriza ca programul
să ne întoarcă o eroare de tipul "ERROR: TNS: could not resolve service name", adică nu a găsit baza pe
care noi am vrut să ne conectăm. Si asta din diverse motive: nu am tastat corect numele bazei sau, nu am

Page 9 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

realizat corect legătura la baza de date. Când lucrăm pe acelaşi calculator în care este instalată baza,
legătura se face automat şi este un fişier în "D:\oracle\ora92\network\admin\tnsnames.ora" care descrie
această legătură:
STUD =
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = TCP)(HOST = lucian)(PORT = 1521))
)
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = stud)
)
)
Dar când lucrăm pe alt calculator şi ne conectăm la baza de pe calculatorul server prin Oracle Client trebuie
să avem grijă ca fişierul tnsnames.ora de pe calculatorul local să aibă definiţia legăturii corectă. Fraza din
tnsnames.ora definește protocolul de comunicaţie între client şi bază (se foloseste TCP), numele
calculatorului server (HOST='....'), (aici se poate înlocui cu IP-ul acestuia sub forma: 192.161.2.3. Pentru a
afla IP-ul calculatorului intraţi într-o fereastra cmd (start\run... : cmd) şi daţi comanda:"ipconfig").

SQL Plus nu reprezintă o interfaţă grafică cu baza de date, este doar un editor text unde utilizatorul poate
scrie și executa comenzi SQL. Pentru o interfaţă mai agreabilă putem utiliza programul SQL Navigator
produs de firma Quest Software. Acest program pune la dispoziţie pe lângă editorul de SQL şi un Object
Navigator prin care putem vedea toate obiectele din baza de date, putem edita obiecte sau crea altele noi.

1.3.3Dezinstalarea bazei Oracle. Exportul informaţiilor din


bază

Dacă ceva s-a blocat la instalare, sau baza nu mai merge, sau efectiv vrem să facem curaţenie pe
calculator, trebuie să dezinstalăm baza Oracle şi s-o instalăm din nou. Atenţie: la dezinstalare se pierde
toată informaţia din bază. Când nu vrem să pierdem toate tabelele cu datele incluse, mai întâi trebuie dat
un export la bază, să salvăm într-un fişier conţinutul acesteia.

1.3.3.1 Salvarea bazei de date

La instalarea serverului Oracle s-a instalat şi un produs numit EXP în directorul " D:\oracle\ora92\bin" (dacă
baza s-a instalat pe D). Programul EXP este utilizat pentru salvarea bazei Oracle într-un fişier. Se deschide
o fereastră Command Dos (Start/Run... cmd) şi se introduce comanda:
 exp stud/stud@stud file=c:\stud.dmp log=c:\stud.log grants=N recordlength=8192
buffer=30000000
 sau: exp bd1/bd1@stud file=bd1.dmp

Page 10 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

Deci se exportă toate obiectele care ţin de user-ul stud (se intra cu parola "stud" pe baza "stud"). Fişierul
rezultat "stud.dmp" va fi pe discul C şi fişierul de mesaje "stud.log" va fi salvat pe acelaşi disc.
După instalarea unei noi baze de date şi crearea user-ului "stud" se pot importa informaţiile din
baza veche cu comanda:
 imp adm/adm@stud fromuser=adm touser=adm file=c:/adm.dmp log=c:/adm_imp.log grants=N
recordlength=8192 buffer=30000000 commit=y

Pentru dezinstalarea bazei Oracle se merge pe programul Start/Programs/Oracle Installation


Products/Universăl Installer şi se alege "Deinstall Products...". După ce se selectează toate produsele
pentru dezinstalare şi se dă comanda de dezinstalare ar trebui să fie curat pe disc. În realitate nu este aşa,
directorul Oracle rămâne în continuare pe disc, iar serviciile de asemenea.

Curaţenia totală se face după ce intrăm în regiştri şi stergem directoarele Oracle găsite acolo. Deci se intră
în regiştrii Windows (Start/Run... şi se tastează "regedit"). Intrăm în editorul de regiştri şi căutăm în folderul
"HKEY_LOCAL_MACHINE / SOFTWARE" directorul "ORACLE". Click dreapta pe acest director şi dăm
comanda delete. Mergem apoi în directorul "HKEY_LOCAL_MACHINE / SYSTEM / ControlSet001 /
Services" şi ştergem toate directoarele care încep cu secvenţa "Oracle". În sfârşit, mergem şi în
"HKEY_LOCAL_MACHINE / SYSTEM / ControlSet002 / Services" unde facem aceeaşi curăţenie şi putem
spune că am scăpat de serviciile Oracle.

Atenţie: nu modificaţi registrii Windows fără o bună înţelegere a celor ce doriţi sa schimbaţi, orice
modificare greşită aici poate duce la blocarea anumitor programe sau chiar a calculatorului. Singura
scăpare este reinstalarea sistemului de operare Windows cu o formatare prealabilă a discului, ceea ce
consumă timp, resurse și pierdere de informaţii.
După ştergerea serviciilor Oracle din Registry puteţi şterge în sfârşit directorul ORACLE de pe disc.
Dacă vă dă eroare "acces denied" daţi restart la calculator, să-şi recitească regiştrii şi să nu mai pornească
serviciile Oracle.

1.3.4Instalare Oracle 18c Express Edition


Pentru calculatoarele cu sistem de operare Windows 10 se poate instala versiunea 18c de la Oarcale.
Intrucat baza de date dezvoltata in cadrul cursului nu integreaza un numar mare de date, se instaleaza
versiunea Express Edition care nu necesita licenta pentru utilizare in scop didactic.

Kit-ul de instalare pentru procesoarele de 64 de biti este salvat in Google Drive:


https://drive.google.com/drive/folders/1SW2ttn0VXNdUEkz2NfGeoYb6By9N78ua?usp=sharing

Page 11 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

iar procesul de instalare este mult mai simplu:


 Se downloadeaza kit-ul arhivat („OracleXE184_Win64.zip”) din Google drive
 Se deschide arhiva si se copie kitul de intalare intr-un folder local

 Click dreapa pe fisierul „setup.exe” si se ruleaza cu optiunea „run as administrator”

 Se merge mai departe cu butonul „Next” si se accepta termenii si conditiile cerute de Oracle
 Oracle propune un folder default pentru instalare pe discul C:

Intrucat acest folder este relativ ascuns, putem alege un alt folder: C:\\Oracle, sau pe orice alt disc din
calculator.
 Implicit la instalare se creeaza trei conturi de administrare a bazei de date: SYS, SYSTEM,
PDBADMIN. Se cere parola pentru aceste conturi:

Page 12 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

ATENTIE: nu trebuie uitata aceasta parola pentru ca o vom utiliza pentru conectare la baza de date nou
creata.
 Click pe butonul „Next” si incepe procesul de instalare a bazei de date:

Dureaza cateva zeci de minute, depinde de puterea calculatorului, dupa instalarea cu succes a bazei de
date, este afisata fereastra:

 Baza de date se instaleaza sub forma de serviciu windows (fereastra Services):

Sunt doua servicii care intereseaza:


 OracleServiceXE: este baza de date
 OracleOra....Listener: serviciul care primeste comenzile SQL si le trimite catre baza de date.

Page 13 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

1.3.5Dezinstalare Oracle 18c Express Edition


Dezinstalarea bazei de date se face simplu, prin metoda clasica:
 Deschidem fereastra „Add or Remove Programs”
 Selectam „Oracle database” si click pe butonul „Uninstall”:

 Procesul de dezinstalare face curat pe calculator, opreste si elimina serviciile Oracle. Folderul
„Oracle” nu este sters automat, dar se poate sterge din Windows fara probleme deoarece nu mai
este blocat de serviciile din background.

1.3.6Instalare SLQ Developer


Pentru conectarea la baza de date si dezvoltarea comenzilor SQL vom folosi o aplicatie specializata in
acest scop: „SQL Developer”, kit-ul de instalare se regaseste in acelasi folder GoogleDrive:

https://drive.google.com/drive/folders/1SW2ttn0VXNdUEkz2NfGeoYb6By9N78ua?usp=sharing

Se deschide arhiva si se copie continutul intr-un folder local:

Aplicatia care trebuie rulata este „sqldeveloper.exe” si care deschide interfata pentru conectarea si lucrul cu
baza de date:

Page 14 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

 Primul pas este sa ne conectam la baza de date cu user-ul „sys” si sa cream un cont de lucru
pentru dezvoltarea bazei ce dorim s-o dezvoltam in cadrul cursului:

 Click dreapta pe „Oracle Connection”, selectam „New connection” si definim conexiunea pentru
userul sys (ATENTIE: conectarea pe user-ul sys se poate face doar ca „sysdba”, de aceea
trebuie selectata aceasta optiune din lista „Role”):

By default in locatia server-ului (Hostname) este trecut „localhost”, adica computerul curent. Daca butonul
„Test” afiseaza erori de tipul „network adapter could not establish the connection”:

Page 15 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

atunci „localhost” se inlocuieste cu IP-ul calculatorului:

 Nu se lucreaza in contul lui SYS, se creeaza un nou cont de lucru. Se ruleaza (butonul verde)
urmatoarele comenzi folosind sesiunea deschisa in SYS:

o alter session set "_ORACLE_SCRIPT" = true;


o create user luci1 identified by luci1;
o grant dba to luci1;
o connect luci1/luci1;

Page 16 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

Prima instructiune ne permite sa cream useri fara restrictii referitoare la prefixul acestor nume. Apoi se
creeaza user-ului si i se acorda drepturi de tip DBA (Data Base Adminstrator), drepturi depline asupra bazei
de date. Ultima instructiune este de test, se verifica daca noul user se poate conecta la baza de date.

 Se creeaza o noua conexiune in SQL Developer pentru noul user:

Din acest moment, oricand se poate deschide SQL Developer, selecta conexiunea de lucru si apoi
introduce comenzi SQL pe acest cont.

1.4 Ce este limbajul SQL

SQL (Structured Query Language) este un limbaj prin care comunicăm cu baza de date. Vrem să
introducem un student în tabela studenţi: scriem o comandă SQL care va fi înţeleasă şi executată de bază:
 insert into studenti (nume) values ('Popescu Ionel').
Dacă dorim să vedem studenţii din baza de date, atunci trebuie să execut o altă instrucţiune SQL:
 select nume_student from studenti;

Page 17 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

1 Noţiuni elementare despre proiectarea bazelor de date


Proiectarea unei baze de date reprezintă un proces complex ce necesită experienţă și o bună înţelegere a
mecanismelor de funcţionare a acestora. Capitolul curent nu-și propune să facă o analiză complexă a
acestui proces, ci doar să prezinte câteva noţiuni elementare de care trebuie să se ţină seama în momentul
proiectării unei baze de date de uz curent.

Sunt câţiva pași ce trebuie parcurși in vederea proiectării corecte a unei baze de date:
 Determinarea scopului bazei de date ce trebuie proiectată
 Găsirea informaţiilor ce trebuie stocate în baza de date și împărţirea lor pe tabele
 Specificarea cheilor primare și a relaţiilor între tabele
 Aplicarea regulilor de normalizare

In continuare vom descrie acești pași prin proiectarea unei baze de date minimale ce gestionează
informaţiile specifice studenţilor dintr-o facultate: nume, prenume, grupă, discipline studiate, note obţinute,
etc.

1.5 Determinarea scopului bazei de date

Foarte multe probleme ce apar între clienţi și dezvoltatorii bazelor de date se datorează unei analize
defectuoase a scopului pentru care se creează o bază de date. In principiu, clientul este cel care știe ce
activitate se desfășoară în instituţia respectivă, dar nu știe cum s-o explice în termenii unei baze de date.
Abia după ce s-a implementat baza de date, încep să apară probleme în sensul că clientul cere situaţii și
rapoarte care nu pot fi realizate pentru că nu există informaţia necesară în bază.
De aceea trebuie acordată o atenţie corespunzătoare acestei etape, pentru a defini foarte clar ce informaţii
trebuie să conţină baza de date și ce situaţii se cer a fi realizate.

La o prima analiză a structurii organizatorice a facultăţii putem nota următoarele concluzii:


 Toate activităţile din facultate sunt asociate unui an universitar care începe în octombrie şi
se termină în septembrie anul viitor.
 Pentru a obţine licenţa de absolvire, studentul trebuie sa treacă printr-un ciclu de studii ce
presupune un număr de ani de studiu : anul 1, anul 2, anul 3 şi anul 4.
 La începutul fiecarui an universitar studenţii se înscriu la facultate, fiind repartizaţi într-o
grupă de studiu.

Page 18 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

 Nu toţi studenţii parcurg acelaşi domeniu, facultatea având mai multe specializări de studiu,
(Maşini Electrice, Metrologie, Informatică Aplicată, etc), fiecare specializare fiind formată
din una sau mai multe grupe de studenţi.
 In fiecare semestru dintr-un an de studiu studenţii trebuie să studieze un număr de
discipline specifice specializării la care s-au înscris. Fiecare disciplină se predă la o
anumită specializare şi într-un anumit an de studiu.
 Semestrele se încheie cu o sesiune de examinare unde studenţii primesc note la
disciplinele studiate.
Scopul bazei de date este de a stoca aceste informaţii astfel încât să fie capabilă să furnizeze următoarele
rapoarte:
 Lista studentilor din facultate
 Lista studentilor pe grupe şi ani de studiu dintr-un anumit an universitar
 Lista disciplinelor grupate pe specializările din facultate
 Lista disciplinelor ataşate unui student într-un an universitar împreună cu notele obţinute de acesta
 Mediile generale ale studenţilor, media pe grupe şi discipline de studiu
 Studenţii cu rezultate bune la învăţătură, având media superioară grupei din care fac parte
 Studenţii care repetă un anumit an de studiu
 Etc

1.6 Modelul entitate-asociere


Toate informatiile culese în timpul analizei se transpun într-o diagrama care va fi analizată împreună cu
clientul. De cele mai multe ori, clientul nu are noţiuni de baze de date, de aceea, diagrama trebuie
construită folosind simboluri care să fie înţelese de toată lumea. Un model larg utilizat în astfel de cazuri
este cel numit "entitate-asociere" (EA).
Acest model lucrează cu două concepte:
 "entitate" - este un concept ce modelează clasele de obiecte pentru care se colectează informaţiile:
student, grupă, notă, disciplină, specializare, etc. O entitate conţine mai multe atribute, atributul
fiind o informaţie atomică ce se dorește a fi salvată în baza de date relativ la acea entitate. De
exemplu, pentru un student, se dorește a se salva în bază următoarele atribute: nume, prenume,
adresă, data nașterii.
 "asociere" - modelează relaţiile, interdependenţele dintre entităţi. De exemplu, între studenţi și
grupe se poate stabili asocierea "înscris la" care stabilește modul de asociere a studenţilor la
grupele de studiu.

Page 19 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

Entităţile se reprezintă prin dreptunghiuri la care se atașează atributele reprezentate prin cercuri, iar
asocierile prin romburi sau poligoane regulate.
Figura următoare prezintă diagrama EA pentru baza de date pe care dorim s-o implementăm:

La o primă analiză s-au identificat următoarele entităţi de informaţie:


 "Studenti" stochează informaţiile despre studenţii din facultate
 "Grupe": grupele de studiu ce se formează în fiecare an cu studenţii înscriși. Intre cele două entităţi
există o asociere: la inceput de an universitar studenţii se inscriu într-o grupă de studii. O grupă de
studii include mai mulţi studenţi, dar același student aparţine de mai multe grupe pe perioada
facultăţii.
 "AniStudiu": an 1, 2,… reprezintă anii de studiu pe care îi parcurge studentul în decursul facultăţii.
Fiecare grupă aparţine unui an de studiu.
 "Specializari": facultatea conţine mai multe direcţii de specializare, grupele de studii sunt împărţite
pe aceste specializări
 "Discipline": materiile ce se studiază în facultate, o materie este atașată la o specializare și un an
de studiu
 "Note": reprezintă notele obţinute de studenţi la disciplinele studiate. O notă este asociată unui
student și unei discipline.

Page 20 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

Pentru simplitate, nu s-au trecut și atributele entităţilor, dar acestea vor fi descrise în cadrul tabelelor.

Pot exista asocieri cu atribute: de exemplu asocierea dintre studenţi și grupe se face prin intermediul anilor
universitari. Un an universitar nu ţine nici de entitatea "Studenti", nici de entitatea "Grupe", deci va fi un
atribut al asocierii. Atributele se trec în dreptul asocierii și vor fi implementate prin entităţi independente în
pasul următor.

1.7 Conversia elementelor informaţionale în coloane de tabele

In baza de date, informaţia este stocată sub formă de tabele, pentru fiecare entitate din modelul EA se
creează un tabel având câte o coloană pentru fiecare atribut al entităţii.
Conform observaţiilor de mai sus, ar rezulta următoarea structură de tabele necesară pentru stocarea
informaţiilor specifice activităţii didactice :

1. Tabela "Specializari": este tabela ce conţine specializările din facultate. Este o tabelă
independentă, structura specializărilor nu depinde de studenţi sau grupe, ci este dată de profilul
facultăţii.
Include următoarele coloane:
 Cod_specializare: (ex: "IAD", "IA", ...) un text ce descrie simplu specializarea
 Descriere_specializare: (ex: "Instrumentatie si Achizitii de Date"), reprezintă denumirea
completă a specializarii
 Cod_domeniu: codul domeniului de care aparţine specializarea (Inginerie Electrică,
Electromecanică, etc)
 Nume_domeniu

Page 21 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

2. "AniStudiu": este tabela ce conţine anii de studiu pe care îi parcurge un student în decursul
facultăţii.
Include următoarele coloane:
 Cod_an_studiu: (ex: "1", "2", ...) un text ce reprezintă anul de studiu
 Descriere_an_studiu: (ex: "Anul I", "Anul II", ...), reprezintă descrierea anului de studiu
3. "Discipline": este tabela ce conţine disciplinele studiate în facultate.
 Cod_disciplina: (ex: "BD", "ME", ...) un text ce descrie simplu disciplina
 Descriere_disciplina: reprezintă denumirea completă a disciplinei
4. "Grupe": este tabela ce conţine grupele de studenţi care se formează în facultate. Grupele depind
de specializare şi de anul de studiu: la specializarea "IA", anul 3 este o singură grupă: "6309".
Include următoarele coloane:
 Cod_grupa: (ex: "6102", "6301", ...)
 Descriere_grupa: (ex: "Grupa 6301")
5. "Studenti": este tabela cu toti studenţii din facultate, conţine informaţiile statice ale unui student.
Include următoarele coloane:
 Nume_student
 Prenume_student
 Adresa
6. Tabela "Note": ţine evidenţa notelor obţinute de studenţi în timpul examinărilor.
 Nota: un număr cuprins între 1 şi 10 reprezentând nota luată de student
 Data: data examinării, de tipul "date"
7. "AniUniversitari": reprezintă lista anilor universitari (2010/2011, 2011/2012, etc). Toate informaţiile
dinamice ale facultaţii trebuie legate de un anumit an universitar, astfel încât să se poată merge în
istoricul facultăţii pe un anumit an universitar și să se obţină informaţiile specifice pentru acel an. De
exemplu, legatura dintre studenţi și grupe se face prin intermediul anilor universitari, plecând de la
un an universitar, putem afla în ce grupă a fost înscris un anumit student.
 Cod_AnUniversitar: (ex: "2011/2012", "2012/2013", ...)
 Descriere_AnUniversitar: (ex: "Anul Universitar 2011/2012")

Sunt anumite reguli ce trebuie respectate în crearea coloanelor de tabele:


 Informaţia dintr-o coloană trebuie să fie atomică, în sensul că nu mai poate fi despărţită în alte
elemente componente. De exemplu:
o Nu se face o coloană "NumePrenume" care să conţină cele două componente ale numelui
unui student. Vor fi două coloane: "Nume" și "Prenume" astfel încât să putem găsi foarte
repede prenumele studenţilor, fără a fi nevoiţi să facem prelucrări de șiruri de caractere.

Page 22 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

o Adresa nu se pune într-o singură coloană: indicat ar fi să avem câte o coloană pentru
stradă, numărul străzii, bloc, scara, etaj. Chiar dacă momentan nu este evidentă această
separare, este posibil în viitor să se ceară o situaţie cu toţi studenţii de pe o anumită stradă,
sau studenţii care domiciliază la parter, etc. Cum baza noastră de date are un scop pur
demonstrativ, punem pentru simplitate informaţia "Adresa" într-o singură coloană.
 Nu se pun coloane pentru valori calculate: de exemplu, nu este indicat să fie o coloană cu media
studentului. Aceasta se calculează printr-un apel de funcţie în momentul când este necesar, în caz
contrar, ar trebui recalculată la orice modificare a tabelului note, ceea ce poate constitui o sursă de
erori (dacă se uită de exemplu să se recalculeze la un moment dat, sau se termină calculul printr-o
eroare).

1.8 Specificarea cheilor primare

Orice tabel trebuie să conţină un identificator unic al liniilor cu informaţii. Numai în acest fel se poate regăsi
în mod unic și corect o anumită linie conform unor criterii de căutare. Acest identificator unic se numește
cheie primară și poate fi formată din una sau mai multe coloane a căror combinaţie este unică.

De exemplu, pentru tabela Studenţi am putea alege ca identificator unic numărul matricol al studentului.
Chiar dacă am fi tentaţi să folosim ca cheie primară numele studentului, această opţiune nu este bună,
deoarece oricând se pot găsi doi studenţi cu același nume sau mai mult, nume și prenume identice.

O altă opţiune simplă dar greșită ar fi să alegem ca identificator pentru tabela Grupe coloana "Cod_Grupa".
In fond, există o singură grupă cu acest cod în facultate, deci nu ar fi probleme de identificare. Totuși,
trebuie să privim lucrurile și pe axa timpului: este posibil ca peste doi ani grupa 6302 să nu mai aparţină de
specializarea "IAD", ci datorită numărului de studenţi mai mic din acea generaţie, grupa 6302 să trecă la
specializarea "Informatică Aplicată". Este același cod de grupă, dar vorbim de grupe diferite în decursul
anilor.
Soluţia cea mai sigură din acest punct de vedere este să adăugăm câte o coloană distinctă la fiecare tabel
care să conţină valori numerice unice pentru fiecare linie din tabel. Cunoscând acel număr , putem identifica
în mod unic linia din tabela de interes. Bazele de date pun la dispoziţie mecanisme de generare a
numerelor unice, astfel încât, aceste coloane să se completeze automat de către baza de date la inserarea
unei linii noi în tabelă (vom studia aceste mecanisme în cadrul capitolului "Constrangeri de tip
primary_key").

Ne conformăm acestor reguli de identificare a liniilor din tabele și adăugăm la toate tabelele câte o coloană
numită "pk_...", unde punctele din denumire vor fi înlocuite cu numele tabelului în cauză. In acest fel,
schema logică a tabelelor bazei de date evoluează spre următoarea configuraţie:

Page 23 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

1.9 Crearea relaţiilor dintre tabele

Dacă între tabelele bazei de date nu există asocieri, nu vom putea niciodată sa legăm informaţiile dintr-o
tabelă cu cele din altă tabelă. De exemplu, grupa '6403' de care specializare aparţine? Sau nota 7 din
tabela note, de care student și disciplină aparţine?

Toate asocierile definite în diagrama EA trebuie să se regăsească în structura tabelelor, deci următorul pas
în crearea bazei de date îl reprezintă definirea relaţiilor dintre tabele. Relaţiile de legătură între tabele se
creează prin folosirea de coloane comune, de joncţiune. Cele două tabele asociate au fiecare câte o
coloană ce conţin date identice. Plecând de la valoarea dată într-un tabel, se face joncţiunea cu cel de-al
doilea tabel prin selectarea liniilor care au aceeași valoare în coloana comună. De exemplu, în tabela
"Grupe" se introduce o coloană numită "pk_specializare" ca va conţine identificatorul specializării de care
aparţine acea grupă. Având o grupă dată, se regăsește valoarea "pk_specializare" pentru acea grupă și cu
acea valoare se merge în tabela "Specializări" unde vom găsi mai multe informaţii specifice specializării.

De reţinut că asocierile pot fi de mai multe feluri:


 Unu la unu: o instanţă din prima entitate este asociată la o singură instanţă din a doua entitate și
reciproc
 Unu la mai multi: o linie dintr-o entitate este asociată cu mai multe linii din cealaltă entitate.
Exemplu: o specializare include mai multe grupe de studenţi și mai multe discipline de studiu
 Mai mulţi la mai mulţi: o grupă conţine mai mulţi studenţi, iar un student aparţine mai multor grupe
în decursul anilor de studiu
Convenţie: in diagramele EA ramurile asocierilor de tip "unu" vor fi reprezentate sub formă de săgeată.

Page 24 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

1.9.1Crearea relaţiilor de tipul unu-la-mai-mulţi

Este relaţia întâlnită cel mai des, exprimă în general apartenenţa unei entităţi la o clasificare mai largă. Din
analiza diagramei EA, observăm că trebuie create următoarele relaţii:
 Grupe - AniStudiu: fiecare grupă aparţine de un an de studiu. Se introduce în tabela "Grupe" o
coloană numită "pk_AniStudiu" care va face legătura spre anul de studiu asociat grupei respective.
O grupă aparţine de un singur an de studiu, în timp ce un an include mai multe grupe (relaţie unu-
la-mai-mulţi".
 Grupe - Specializări: o grupă ţine de o singură specializare, o specializare poate include mai multe
grupe
 Discipline - AniStudiu, Discipline - Specializari: o disciplină se predă la un an de studiu și la o
anumită specializare
 Note - Discipline, Note - Studenti: o notă se acordă unui student la o anumită disciplină. Studenţii
au mai multe note la diverse discipline, dar o singură notă la o disciplină dată.
Observaţie: în realitate, un student poate primi mai multe note la aceeași disciplină, conform cu cele trei
sesiuni de examinare permise de regulament. In acest caz, relaţia ar fi de tipul "mai-mulţi-la-mai-mulţi". Din
motive de simplitate, considerăm doar nota finală a studentului, deci ne limităm la relaţia "unu-la-mai-mulţi".

1.9.2Crearea relaţiilor de tipul mai-mulţi-la-mai-mulţi

Relaţia între studenţi și grupe este mai complexă deoarece un student aparţine de o grupă într-un anumit
an universitar, dar în următorul an studentul îsi schimbă grupa. Vom introduce două coloane în tabela
Studenti, una care să identifice anul universitar (pk_AniUniversitari), și una pentru grupa (pk_Grupe) din
care face parte studentul în acel an universitar. In fiecare an universitar se va adăuga o linie nouă în tabela
Studenti prin care se va specifica grupa la care este înscris studentul în acel an.

1.9.3Crearea relaţiilor de tipul unu-la-unu

Această relaţie se creează atunci când sunt coloane cu puţine linii completate în cazul unor tabele de mari
dimensiuni. Nu este indicat să se rezerve o coloană într-un astfel de tabel, coloană care să aibă informaţii
utile doar foarte rar, în rest având valoarea "null", adică nimic. Se face risipă de spaţiu în zona de
memorare a informaţiilor. Este mai util să se creeze o nouă tabelă cu acele coloane speciale și care să se

Page 25 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

lege la tabela principală prin relaţii de tip "unu-la-unu": la o linie din tabela principală corespunde (sau nu) o
singură linie din tabela copil.
De exemplu, să presupunem că în facultate sunt și studenţi străini, la care trebuie stocate informaţii
speciale legate de pașaport, viză, etc. Aceste informaţii sunt foarte rare și nu are sens să punem coloane în
tabela Studenti numai pentru câteva linii utile. Ele se pun într-o tabelă separată "DetaliiStudenti" care va
include doar o singură linie pentru fiecare student străin înscris în facultate. Relaţia dintre tabelele
"Studenti" și "DetaliiStudenti" va fi de tip unu-la-unu.

In urma etapei de implementare a relaţiilor dintre tabele, rezultă următoarea structură logică a bazei de
date:

1.10 Aplicarea regulilor de normalizare

Sunt câteva reguli numite "de normalizare" prin care se poate verifica dacă o bază de date este sau nu
structurată corect. Normalizarea bazei de date reprezintă procesul prin care se verifică dacă structura bazei
este conformă cu regulile de normalizare și ajustarea acesteia în cazul identificării unor neconcordanţe.
Sunt definite cinci reguli de normalizare, dar în majoritatea cazurilor ne oprim doar la verificarea primelor
trei forme normale.

Page 26 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

1.10.1 Prima formă normală

Prima formă normală verifică ca la intersecţia dintre o linie și o coloană dintr-un tabel să fie o singură
informaţie, nu o listă. De exemplu, nu pot fi mai multe note într-o singură celulă a tabelului Note. Această
regulă este destul de evidentă și simplu de implementat. Toate tabelele din baza noastră verifică prima
formă normală.

1.10.2 A doua formă normală

A doua formă normală se aplică tabelelor care au cheia primară formată din mai multe coloane. Ea
specifică că în acest caz, toate coloanele din tabel trebuie să fie dependente de întreaga cheie primară, nu
numai de o coloană din această cheie.
Ce este cheia primară? Reprezintă coloana sau asocierile de coloane prin care se identifică în mod unic o
linie din tabel: pk_specializari, pk_grupe, pk_AniStudiu, etc.

Totuși, coloana pk_studenti nu este cheie unică în tabela Studenti. Chiar dacă această cheie identifică în
mod unic studentul, nu poate identifica și grupa din care face parte studentul la un moment dat. Analizând
tabela Studenti putem identifica cheia primară prin asocierea coloanelor pk_Studenti și pk_AniUniversitari.
Această combinaţie identifică în mod unic studentul și grupa din care face parte pentru un anumit an
universitar.

Verificăm a doua formă normală pentru tabela Studenti: sunt toate coloanele din această tabelă complet
dependente de combinaţia pk_studenti, pkAniUniversitari? Nu este respectată regula, numai coloana
pk_Grupe depinde de întreaga cheie primară, restul coloanelor (nume, prenume, adresă) fiind dependente
numai de coloana pk_Studenţi. Rezolvarea acestei situaţii se face prin crerea unui nou tabel de legătură
între cele trei tabele de lucru: Studenti, AniUniversitari, Grupe. In această tabelă se introduc acele coloane
dependente de cheia primară, restul rămânand în tabela Studenti. Noua tabelă se numește "StudentiGrupe"
și are următoarea structură:

Page 27 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

Coloana Pk_StudentiGrupe reprezintă noul identificator al situaţiei didactice pentru un student. Toate
informaţiile dinamice din baza de date (grupele de studenţi, notele obţinute) trebuie legate de acest
identificator. Relaţia dintre tabela Note și tabela Studenti va fi înlocuită de relaţia între StudentiGrupe și
Note. In acest fel vom putea regăsi notele unui student pe fiecare an universitar. Chiar dacă un student
repetă anul, fiind înscris în aceeași grupă de două ori, vom regăsi două linii distincte în tabela
StudentiGrupe, având pk-uri diferite care să identifice această situaţie.

Observaţie: problema formei normale numărul doi a apărut prin implementarea incorectă a relaţiilor de tipul
mai-multi-la-mai-multi. Intotdeauna aceast tip de relaţie se rezolvă prin adăugarea unui tabel suplimentar
de legătură între cele două entităţi legate multiplu. Dacă aceste relaţii sunt corect implementate, atunci
forma normală doi se verifică implicit.

1.10.3 A treia formă normală

Forma normală trei verifică dependenţele tranzitive. Spunem că o coloană este dependentă tranzitiv de
cheia primară dacă în această dependenţă se interpune o alta coloană. De exemplu, în cazul tabelei
Specializări coloana "Nume_Domeniu" depinde de coloana "Cod_Domeniu" care la rândul ei este
identificabilă prin cheia primară "pk_specializari". Dependenţa "pk_specializari" -> "nume_domeniu" se
realizează prin intermediul coloanei "cod_domeniu".

Forma normală trei nu admite dependenţe tranzitive, adică o coloană dintr-o tabelă trebuie să fie
dependentă numai de cheia primară, nu și de alte coloane din tabelă. In cazul nostru, problema se rezolvă
prin crearea tabelei "Domenii" având coloanele: pk_domenii, cod_domeniu, descriere_domeniu. Legătura
cu tabela specializări se face prin coloana "pk_domenii" adăugată în structura tabelei Specializari.

După toate aceste corecţii, am ajuns la o structură logică a bazei de date care este relativ corectă și
respectă regulile de bază privind proiectarea bazelor de date.

Page 28 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

1.10.4 De ce trebuie adusă o bază de date la forma normală


trei

Formele normale nu garantează ca datele din bază sunt corecte, în schimb ne ajută să minimizăm
redundanţa datelor și să eliminăm anomaliile de reactualizare.

Se observă în mod logic, că salvarea numelui de domeniu în tabela Specializari este redundantă. De ce
trebuie să scriem numele domeniului pentru fiecare specializare în parte, când îl putem scrie o singură dată
într-un tabel separat și doar accesat din tabela Specializari în caz de nevoie.

In același timp, rezolvăm și anomaliile de reactualizare:


 Anomalii de inserare: când se introduce o specializare nouă, trebuie inserat corespunzător și
numele domeniului care trebuie să coincidă cu celelalte linii pentru același cod de domeniu, altfel
am avea domenii cu același cod, dar nume diferite. In plus, dacă există un domeniu nou, fără nici o
specializare, linia respectivă ar avea null în coloana pk_specializare, ceea nu este admis.

Page 29 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

 Anomalii de ștergere: dacă ștergem toate specializările din tabel, se pierd de asemenea toate
domeniile, ceea ce nu era în intenţiile noastre.
 Anomalii la modificare: să presupunem că se modifică numele unui domeniu: din "Inginerie
Electrica" în categoria mai largă numită "Inginerie Electromecanică". Dacă baza de date nu s-ar afla
în forma normală trei, atunci ar trebui ca toate specializările din domeniul "Inginerie Electrica" să fie
modificate în coloana "Nume_Domeniu". Prin crearea tabelei suplimentare "Domenii", modificarea
s-ar face o singură dată, păstrând neschimbată valoarea "pk_domenii" prin care se face legătura
între tabele.

1.11 Rafinarea bazei de date


Chiar dacă baza de date este relativ simplă, totuşi se impun anumite discuţii referitoare la modul de
proiectare și arhitectura aleasă:
 In principiu, majoritatea tabelelor trebuie să conţină o serie de trei coloane relativ obligatorii:
o Coloana primary_key, avand prefixul "pk_", este coloana ce conţine o valoare unică pentru
fiecare rând din tabelă. Orice tabelă trebuie să aibă o coloană care să identifice în mod
unic o linie din cadrul tabelei şi care ne dă siguranţa că baza de date va reuşi să stocheze
şi să furnizeze informaţia în mod corect.
o Coloana de cod, având prefixul "cod_", reprezintă codul atribuit liniei respective. De cele
mai multe ori acest cod este unic dar nu în mod obligatoriu.
o Coloana pentru descrierea informaţiei din rând, are prefixul "descriere_", şi conţine un text
descriptiv despre linia respectivă.
 Relaţia studenţi-grupe: este o relaţie clasică de tipul "mai-multi-la-mai-multi". Dacă analiza era
limitată doar la un singur an universitar, atunci se putea pune foarte simplu coloana "pk_grupa" în
tabela studenti. Intr-un an universitar un student nu poate fi decât într-o grupă (mai sunt şi cazuri
când se permite ca un student să efectueze doi ani într-un an). Dar dacă lucrăm cu mai mulţi ani
universitari, atunci eram nevoiţi să inserăm acelaşi student în baza de date dar avand un alt
pk_grupa. Rezultă astfel mai multe linii în tabela studenti pentru acelaşi student, fiecare având pk-
uri diferite, ceea ce nu este absolut deloc corect. Nu se mai poate deloc identifica în mod unic un
student în baza de date, deoarece numele studenţilor nu este unic în mod absolut. Soluţia a venit
prin crearea tabelului "StudentiGrupe".
 Relaţia discipline-specializări: există posibilitatea ca o disciplină mai generală să se predea la mai
multe specializări (relaţia " unu-la-mai-mulţi" se transformă la tipul "mai-mulţi-la-mai-mulţi"). Soluţia
este similară cu relaţia Studenti -> Grupe și se rezolvă printr-o nouă tabelă de legatură între
discipline şi specializări care să includă şi anul universitar curent.

Page 30 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

 Schimbarea denumirii de disciplină: este posibil ca o disciplină să se reformuleze la un moment dat,


nu se mai cheamă "BD" ci "BDR" (baze de date relaţionale) şi atunci trebuie adaugată o nouă
disciplină. Nu poate fi modificată cea veche deoarece studenţii care deja au absolvit, au studiat
disciplina veche şi ea trebuie să rămână în baza de date pentru tipărirea foii matricole în mod
corect. Deci, la începutul fiecărui an universitar ar trebui completată tabela de legatură între
discipline şi specializări astfel încât, să se poată specifica clar ce discipline s-au studiat în decursul
anilor şi în ce ani universitari.
Singura problema ar fi ca este necesar un volum de muncă suplimentar pentru a ataşa disciplinele la
specializări în fiecare an, munca destul de plictisitoare ţinând cont că aceste schimbări apar foarte rar în
timp.
Mai există o soluţie când se schimbă programa unei specializări: se se creeze o nou specializare,
având acelaşi cod, aceeaşi descriere (dar pk diferit) şi noile grupe formate să se ataşeze la noua
specializare. Totuşi, două specializări cu acelaşi cod şi aceeaşi descriere pot crea confuzie, dacă le
punem într-un combo-box (lista de selecţie), apar două linii identice din care utilizatorul nu ştie pe care
să o aleagă. Atunci se mai introduce o coloana numită "Inactiv" cu variantele "DA" sau "NU". Odată ce
o specializare se modifică, atunci se creează una nouă după noua curiculă şi cea veche se trece în
starea inactiv. In felul acesta avem un criteriu de filtrare a specializărilor ce se afişează la un moment
dat.
 De ce nu pot folosi cod_grupa sau cod_specializare ca coloană de tip pk? Este mai util să vedem în
tabela grupe la coloana "pk_specializare" un text de tipul "IAD" decât un număr abstract. S-ar
vedea de la prima vedere la ce specializare este ataşată această grupă, fără să mai merg prin
tabela specializări. Dar, aşa cum am discutat la punctul anterior, pot adăuga o nouă specializare cu
acelaşi cod, deci s-ar încălca regula ce spune că fiecare linie trebuie identificată în mod unic prin
valoarea din coloana de tip pk.
Aceeaşi regulă se aplică şi la cod_grupa, pot avea grupe cu acelasi cod, dar care să aparţină de
specializări diferite în funcţie de numărul de studenţi din fiecare an universitar.

Page 31 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

Page 32 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

2 Crearea bazei de lucru

2.1 Crearea contului utilizator în baza de date

Ca să putem lucra pe baza de date trebuie mai intâi să introducem un utilizator de care se aparţină toate
obiectele necesare implementării programului. Acest utilizator se va denumi "stud" şi va avea parola "stud",
sau fiecare user îşi creează propriul cont folosind numele propriu.
Comanda SQL care creează un nou utilizator este următoarea:
 create user stud identified by stud;
Dacă dorim să ştergem user-ul creat avem la dispoziţie comanda "drop":
 drop user stud;
Atenţie: ştergerea unui user implică pierderea tuturor informaţiilor care aparţin acelui user: tabele, triggeri,
funcţii, proceduri, biblioteci etc, de aceea trebuie realizat un export mai întâi pe acel user, export ce
salvează informaţia într-un fişier pe disc (vezi comanda de export în capitolul "Dezinstalarea bazei Oracle").
Deci, intrăm in SQL Plus cu user-ul system şi dăm comanda de creare a userului "stud". Orice
instrucţiune SQL se termină cu semnul ";". Odată creat, user-ul trebuie să primească şi nişte drepturi care
să-i permită să întreprindă anumite acţiuni pe baza de date. Vom vorbi mai târziu despre drepturi, acum ne
vom mărgini să-i dăm user-ului "stud" un rol de "data base administrator" (dba), rol suficient de puternic ca
să realizăm ceea ce ne-am propus:
 grant dba to stud;
Dupa crearea user-ului "stud" se iese din SQL Plus si se reintră cu noul user sau, se poate reconecta direct
cu noua identitate:
 connect stud/stud@stud;

Din acest moment vom lucra numai sub user-ul "stud", deci la începutul fiecărei sesiuni se va da user-ul
stud şi parola corespunzătoare. Primul lucru ce-l avem de rezolvat este crearea tabelelor în care vom ţine
informaţia. Baza de date creată este minimală, acoperind doar câteva aspecte din activitatea şcolară a
studenţilor.

2.2 Crearea tabelelor în baza de date

Având structura tabelelor definită, putem trece la crearea efectivă a tabelelor în baza de date. In acest
capitol vom învăţa sintaxa comenzii SQL de creare a tabelelor cu care vom dezvolta toate tabelele
proiectate.

Page 33 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

Dacă lucrăm în programul SQL Navigator crearea unui tabel este simplă: click dreapta pe subdirectorul
"Tables" din "My Schema" şi comanda "Create" din submeniul apărut. Se creează tabela "ani_universitari"
având următoarele coloane:
- pk_an_universitar de tip number (în coloana se vor introduce numai numere care să identifice în
mod unic anul şcolar);
- cod_an_universitar: varchar2(50)
- descriere_an_universitar: varchar2(50)

După ce am completat cele două coloane se dă click pe butonul "Apply Changes to DB" ( ).

Cine nu are o asemenea interfaţă grafică, este nevoit să scrie comanda SQL pentru crearea unei tabele:
create table ani_universitari
(
pk_an_universitar number,
cod_an_universitar varchar2(15),
descriere_an_universitar varchar2(50)
);
Dacă am greşit ceva, putem şterge tabela (drop table ani_universitari;) şi apoi crea din nou, în forma
corectă. Sau, mai avem varianta de modificare a tabelei direct, prin comanda SQL "alter table" :
ALTER TABLE ani_universitari MODIFY ( DESCRIERE_AN_UNIVERSITAR VARCHAR2 (50));

Există comenzi pentru adăugare de coloane, ştergere, modificare tip, modificare nume coloane. Comanda
DESCRIBE face o descriere a coloanelor unui tabel cu tipurile aferente.
 modificare coloană:
o alter table studenti modify (nume_stud not null);
o alter table studenti modify (nr_matricol number);
 Adăugare coloană:
o alter table ani_universitari add (observatii varchar2(100));
 Stergere coloană:
o alter table studenti drop column nr_matricol;
 Redenumire coloană:
o Alter table student rename column nr_matricol to numar_matricol
 Descriere arhitectură tabel "student":
o Describe studenti;

2.3 Tipuri de date definite în baza de date

Page 34 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

In momentul când se defineşte o nouă coloană în tabel trebuie specificat şi tipul de date care vor fi stocate
în acea coloană. Intr-o coloană poate fi stocat doar un singur tip de date, nu pot fi amestecate tipuri diferite
(numere, texte, date calendaristice).

In continuare se dau principalele tipuri de date ce pot fi stocate în baza de date:


 Siruri de caractere:
 Varchar2(n): şir de caractere cu lungime variabilă, numărul maxim de caractere fiind dat de
numărul n. Textul poate avea sub cele 50 de caractere şi atunci spaţiul alocat câmpului se
restrânge la dimensiunea textului. Se poate stoca într-un astfel de câmp maxim 4000 de octeţi.
o Exemplu: varchar2(50): un text de maxim 50 de caractere.
 Nvarchar2(n): similar cu varchar2, dar în acest caz se pot introduce caractere naţionale
specifice (ş, ţ, ă,...)
 Char(n): tot şiruri de caractere, dar de lungime fixă, maxim 2000 de octeţi.
 Long raw: şiruri de caractere de până la 2 GB

 Numere:
 Number(p,s): un număr cu p cifre din care s la partea zecimală.
o Exemplu: number (7,2) stochează numere de maxim 5 cifre la partea întreagă şi 2 la
partea zecimală

 Date calendaristice:
 Date: o dată calendaristică ce poate conţine orice dată în perioada 4712 î.e.n – 9999. Aceste
date se păstrează în bază sub forma unor numere cu virgulă, o unitate reprezentând o zi.
Pentru afişarea datelor calendaristice se folosesc diverse funcţii ce formatează acea data într-
un text corespunzător.
 Timestamp(s): tot o dată calendaristică, dar memeorează şi fracţiuni de secundă. Numarul s
reprezintă câte zecimale se păstrează dintr-o secundă (implicit se pătrează 5 zecimale, maxim
sunt 9 zecimale). Acest timestamp e util când ne interesează intervale foarte scurte de timp ce
pot fi sub o secundă, deci pot fi calculate doar prin compararea unor date de tip timestamp.

 Obiecte mari:
 Blob (bynary large objects): pentru obiecte foarte mari de date (cum ar fi imagini, obiecte
binare) Oracle pune la dispoziţie tipul BLOB. In acest câmp se pot stoca până la 4 GB de date
binare, fără nici o formatare prealabilă (ele sunt tratate ca un şir de octeţi oarecare).

Page 35 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

Page 36 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

3 Constrângeri

3.1 Constrângeri de tip Primary Key (PK)

Am văzut ca putem afla grupa din care face parte un student ştiind numărul liniei din tabela "grupe"
care este asociat studentului. Dar, ce se întâmplă dacă s-a şters o grupă din baza de date? Toate liniile vor
fi decalate cu un pas, deci toti studenţii vor fi trecuţi automat în grupa anterioară. Este mult mai bine dacă
am defini o coloană în tabela "grupe" care să aibă ca valoare un număr întreg pentru fiecare linie și să fie
unic în tabelă, indiferent de câte linii are tabela, câte linii s-au şters sau modificat. Putem defini o asemenea
coloană prin constrângerea "primary key".

Constrângerile reprezintă un set de reguli pe care noi le definim şi apoi baza de date se asigură că sunt
respectate. De exemplu, din experienţa noastră de toate zilele, putem trage concluzia destul de utilă că nu
este bine să bagi mâna în foc. De aceea definim o regula : "nu este voie să se bage mâna în foc". Cu toate
că regula este clară, e greu să fie respectată. De multe ori omul uită că focul arde, sau din greşeală trece
cu mâna prin foc, sau introduce mâna într-o incintă în care nu ştie că arde focul. Deci, ne putem frige ori din
neatenţie, ori din neştiinţă. N-ar fi mai bine dacă cineva ar supraveghea tot timpul la respectarea acestei
reguli şi, la fiecare încalcare să ne blocheze să băgăm mâna în foc?
Exact asta face bază de date: noi definim o constrângere de tip "primary key" pe o coloană şi baza
are grijă ca niciodată să nu se repete o valoare pe acea coloană.
Comanda SQL de adăugare a unei constrângeri de tip "primary key" este următoarea:
 alter table studenti add constraint studenti_pk primary key (pk_student);

3.1.1Completarea valorilor din cheile primare

Dar cum ştim să introducem valori unice în coloana de tip primary key? Cine stă să verifice ce valori s-au
introdus până acum şi ce valori putem introduce în continuare? Din fericire, baza de date iarăşi ne ajută.
Bazele de tip Oracle conţin un obiect numit "Sequence" care este un generator de numere crescătoare
unice. Odată definit, obiectul ne furnizează la apel un număr mai mare decât cel furnizat anterior. Nimeni nu
poate da secvenţa înapoi, deci nu este posibil să se repete un număr de mai multe ori. Prin urmare,
completarea unei coloane de tip "primary key" (pk) se face cu ajutorul secvenţelor.
Crearea unei secvenţe se face prin comanda:
 create sequence seq_pk_stud increment by 1 start with 21 minvalue 10 maxvalue 9999999999
nocycle noorder ;

Page 37 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

3.1.2Crearea și utilizarea indexilor

Indexul reprezintă un instrument de căutare rapidă a unei informaţii în baza de date. Acestea funcţionează
similar cu indexurile dintr-o carte: memorează o listă de valori (cuvinte cheie) și pagina la care se gasește
acea valoare în carte. Este mai rapid să căutăm un cuvânt cheie în lista din Index, decât să parcurgem
cartea pagină cu pagină.

Indexul în baza de date memorează valoarea cheii primare dintr-o tabelă și locaţia în care se regăsește
linia corespunzătoare acelei chei primare. Indexul are dimensiunea mult mai mică ca tabela, deci căutarea
în index este mult mai rapidă.
Indexii se definesc pe o coloană sau mai multe coloane asociate. In mod automat, Oracle definește un
index pentru fiecare cheie primară a unei tabele. In afară de cheile primare, indexii se definesc pe acele
coloane care sunt utilizate în mod frecvent pentru căutarea și filtrarea datelor.
Comanda SQL de creare index este următoarea:
 CREATE INDEX cod_spec_ix ON specializari (cod_specializare);
S-a creat indexul "cod_spec_ix" care face căutarea după coloana "cod_specializare" mult mai rapidă.
Stergerea unui index se face prin comanda:
 drop index cod_spec_ix ;

3.1.3Indexii accelerează căutarea, dar încetinesc modificările


de date

Indexii sunt creaţi pentru o căutare mai rapidă a informaţiilor din baza de date și sunt foarte utili în cazul
tabelelor cu un număr mare de linii. In același timp, scrierea sau modificarea informaţiilor din acea tabelă
este mai lentă deoarece, orice modificare în structura datelor din tabelă trebuie operată și-n structura index-
ului. Ca regulă, nu trebuie făcut abuz prin crearea unor mulţimi de indexi dacă acest lucru nu se impune.
Indexii sunt avantajoși acolo unde sunt tabele mari, cu citiri frecvente și modificări rare.

3.2 Constrângeri de unicitate (UK)

Sunt situaţii când mai multe coloane din tabelă trebuie să conţină valori unice, dar nu putem defini decât o
coloană ca fiind de tip PK. Pentru celelalte coloane avem la dispoziţie constrângerea de unicitate care
odată definită, nu permite repetarea valorilor pe acea coloană.
 alter table grupe add constraint grupe_uk unique(cod_grupa, desc grupa);
 alter table grupe drop constraint grupe_uk;

Page 38 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

3.2.1Crearea constrângerilor de unicitate fără validarea


datelor

Dacă vreau să creez o constrângere de unicitate dar datele existente în tabelă nu respectă condiţia impusă
de constrângere, se foloseşte clauza NOVALIDATE (baza deja este pornită, avem date, dar s-a constatat la
un moment dat că unele date nu sunt corecte. Nu putem şterge datele, dar din acest moment definim
constrângerea care să nu mai permită introducerea de noi date greşite):
 alter table studenti add constraint discipline_uk unique (cod_disciplina, nume_disciplina)
enable novalidate;
OBSERVATIE: novalidate merge numai daca s-a creat un index pe acele coloane:
 create index discipline_ix_cod on discipline (cod_disciplina, nume_disciplina);

3.2.2Activarea și dezactivarea constrângerilor

Constrângerile pot încetini la un moment dat activităţile din baza de date, de aceea există posibilitatea să le
dezactivăm temporar și apoi reactiva:
o alter table enable (novalidate) constraint studenti_uk;
o alter table disable constraint studenti_uk; (asta face automat novalidate)

Când este util să dezactivăm constrângerile?


 Importăm în bază date care nu respectă ordinea: mai întâi datele din tabelele părinte şi apoi cele
din tabelele copil. Prin dezactivarea constrângerilor, pot introduce datele în ordine aleatoare şi apoi
constrângerile sunt validate la loc. Condiţia este ca datele importate să respecte regulile impuse de
constrângeri.
 Import date într-o tabelă care se autoreferă (am date parinte şi copil in aceeaşi tabelă).
 Sterg date din tabelă, dar datorită constrângerilor de tip foreign key, ştergerea durează foarte mult
(baza trebuie sa verifice că nu ştergem date de tip părinte ce au date copii în alte tabele). Trebuie
să dezactivez toate constrângerile de tip foreign key care fac referire la tabela din care şterg.
Aceste constrângeri se află printr-un select din tabela user_constraints.

3.3 Constrângeri de tip "Not Null" (NN)

Page 39 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

Ce se întâmplă dacă introducem un student în bază, dar uităm să-i completăm numele? Programul
salvează linia şi apoi vine profesorul să pună note în catalog. Când ajunge la studentul cu pricina găseşte o
linie goală la care nu ştie ce notă să treacă.
De aceea, trebuie să ne asigurăm că, coloana "nume" nu are voie să conţină valori de tip null.
Această problemă se rezolvă prin constrângerea "Not Null" pe care o aplicăm coloanei "nume".
 alter table studenti modify (nume_student varchar2(50) not null);

3.4 Constrângeri de tip "Foreign Key"

O altă sursă de erori este dată de legătura între tabele. De exemplu, în tabela "studenti_grupe"
ataşăm un student la grupa cu pk-ul 31 în loc de 3 cum ar fi corect. Grupa 31 nu există în bază, deci acel
student nu va apărea în catalog, deoarece catalogul afişează studenţii dintr-o grupă.
Soluţia este dată de constrângerea de tip "Foreign Key", adică stabilim regula ca toate valorile
introduse în coloana "pk_grupa" să facă parte din mulţimea valorilor din coloana "pk" a tabelei "grupe". În
acest fel, când se introduce studentul din grupa 31, baza imediat se sesizează şi întoarce eroare.
 alter table StudentiGrupe add constraint stud_grupe_fk foreign key (pk_grupa) references
grupe(pk_grupa);
Observaţie: coloana pk_grupa din tabela grupe trebuie să fie declarată într-o constrângere de tip PK sau
UK, altfel obţinem eroarea: 'no matching unique or primary key for column-list';

3.5 Constrângeri de tip "check"

Mai există o posibilitate de limitare a surselor de eroare: constrângerile generale de tip "check".
Acestea reprezintă expresii logice ce returnează adevărat sau fals. Dacă rezultatul este fals, linia respectivă
nu va fi modificată în baza de date și se va emite o eroare de validare.
De exemplu, nu putem introduce note în afara intervalului [1-10]:
 Alter table note add constraint ck_nota CHECK (nota between 1 and 10);

3.6 Definirea constrângerilor în baza de date "stud"


Constrângerile trebuie definite înainte de introducerea datelor, altfel riscăm să avem date incoerente în
bază. Conform discuţiilor din capitolul anterior, pe fiecare tabel din bază trebuie definite cel putin următorul
set de constrângeri:
1. Ani_Universitari:

Page 40 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

- pk_an_universitar (pk_an_universitar)
2. Ani_studiu:
- pk_an_studiu (cod_an_studiu)
3. Specializari:
- Pk_specializari (cod_specializare)
4. Discipline:
- Pk_discipline (cod_disciplina)
- Fk_disc_spec : discipline.cod_specializare -> specializari.cod_specializare
- Fk_disc_ani_studiu: discipline.cod_an_studiu - > ani_studiu.cod_an_studiu
- Unique: denumire_disciplina + cod_specializare (combinatia discipline, spec sa fie unica)
5. Grupe:
- Pk_grupa (cod_grupa)
6. Studenti:
- Pk_student (pk_student)
- Nn_nume_stud (nume_student) not null
7. Studenti_grupe:
- Pk_studenti_grupe
- Fk_studenti_grupe_grupe: student_grupe.pk_grupa -> grupe.pk_grupa
- Fk_studenti_grupe_studenti: student_grupe.pk_student -> studenti.pk_student
8. Note:
- Pk_nota(pk_nota)
- Fk_note_stud : note.pk_student -> studenti.pk_student
- Fk_note_discipline : note.pk_disciplina -> discipline.pk_disciplina
- Ck_nota : nota > 1 şi nota <= 10

Page 41 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

4 Introducerea datelor în tabele

4.1 Sintaxa comenzii Insert

Odată create tabelele, putem introduce date în ele. Comanda SQL de introducere a datelor în tabele este
INSERT ce are sintaxa dată în continuare:
 insert into ani_universitari (pk_an_universitar, cod_an_universitar, descriere_an_universitar)
values (-1, '2010-2011', 'an universitar 2010-2011');
După comanda "insert into" se pune numele tabelei în care se introduc datele, între paranteze se trec
denumirile coloanelor care se completează cu informaţii, apoi după cuvântul "values" se pun valorile noilor
date ale tabelei. Observăm că valorile numerice se scriu ca atare pe când câmpurile de tip text se scriu cu
apostrof ('an universitar 2010-2011' ).
Aceeaşi comandă poate fi dată şi prin sintaxa:
 insert into ani_universitari values (-1, '2010-2011', 'an universitar 2010-2011');
când se renunţă la specificarea coloanelor completate. In acest caz paranteza "values" trebuie să conţină
valori pentru toate coloanele tabelei. Prima variantă este de preferat deoarece se vede foarte clar ce
coloane se completează (sunt tabele care au zeci de coloane şi doar câteva primesc valori la o inserare) şi
în al doilea rând nu se ştie niciodată dacă nu cumva mai trebuie adăugată o coloană la o tabelă după
conceperea bazei de date. O coloană în plus necesită modificarea tuturor insert-urilor scrise sub a doua
variantă.
Notă: trebuie verificat dacă studentul primeşte notă doar la o disciplină pe care el o studiază.
Constrângerea fk_note_discipline verifică că disciplina la care se pune nota există în baza de date, dar nu
poate verifica dacă studentul ce primeşte nota studiază sau nu acea disciplină. Această verificare trebuie
făcuta printr-un trigger, concept ce se va studia în alt capitol.

4.2 Valoarea NULL

Ce se întâmplă cu acele coloane care nu sunt specificate în comanda insert?


 insert into studenti (pk_student, nume_student) values(20,'Ionescu');
In comanda precedentă nu s-a completat prenumele studentului introdus în bază. Dacă ne uităm la
informaţiile din tabela studenţi:
 select * from studenti;
vom vedea că la studentul cu pk-ul 20 coloana "prenume_student" nu are nimic. La omiterea unei coloane
în comanda insert, baza de date introduce automat valoarea NULL în acea coloană. NULL înseamnă
"nimic" şi dă multe bătăi de cap programatorilor. Deoarece un singur NULL pus într-o relaţie sau într-o

Page 42 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

ecuaţie dă peste cap toată ecuaţia care va returna întotdeauna NULL, indiferent de celelalţi membri ai
ecuaţiei (nimic adunat, împartit, testat, etc., cu ceva dă întotdeauna nimic).

Este foarte greu să ţinem evidenţa valorilor care sunt NULL în baza de date, de aceea, pentru a nu bloca
procesarea informaţiei în cazul întâlnirii unei valori NULL se foloseşte funcţia NVL care să furnizeze o
valoarea implicită pentru coloanele ce nu au valori:
 select nvl(prenume_student,'prenume student') from studenti;
Dacă coloana "prenume_student" are valori diferite de NULL atunci funcţia "nvl" returnează acea valoare, în
caz contrar returnează şirul 'prenume student'.

4.3 Introducerea datelor în tabele

Folosind comanda insert prezentată mai sus, se introduc date de lucru în tabele astfel încât să obţinem o
bază de date funcţională (grupe, studenţi, specializări, discipline, note, etc).
Prezentăm în continuare câteva tabele:
 select * from specializari;

 select * from grupe;

 select * from discipline;

Pentru o introducere mai rapidă a datelor se pot utiliza frazele insert listate în anexa "Introducerea date în
bază".

Page 43 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

5 Extragerea informaţiilor din baza de date


5.1 Comanda SELECT

Orice informaţie din bază trebuie la un moment dat extrasă şi vizualizată. In acest scop folosim comanda
SQL SELECT, comandă cu care ne confruntăm cel mai des în lucrul cu baza de date.

Mă interesează să văd studenţii înscrişi in facultate:


 select * from studenti;

Dar nu vreau să văd toate coloanele, nu mă interesează pk-ul studentului, sau alt pk, vreau să ştiu numele
şi prenumele studentului:
 select nume_student, prenume_student from studenti;

Sunt prea mulţi, nu vreau să văd toţi studenţii care au trecut prin facultate, vreau să văd numai studenţii
care sunt la litera 'B':
 select nume_student, prenume_student from studenti
where nume_student like 'B%';

Din cele prezentate până acum putem reţine sintaxa de bază a instrucţiunii SELECT:
 select nume_coloane from nume_tabel where condiţii de selecţie.
După cuvântul "select" se introduc numele coloanelor din tabela care vrem sa fie afişate. Dacă sunt mai
multe coloane, se despart prin virgulă, după ultima coloană nu se pune virgulă. Dorim toate coloanele din
tabelă? punem direct * (select *). Urmează clauza "from" după care punem numele tabelei din care

Page 44 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

extragem acele informaţii. Nu dorim toate liniile din tabel? atunci trebuie să adăugăm clauza "where" unde
introducem condiţiile pe care trebuie să le îndeplinească liniile din tabel ce se doresc afişate.

5.1.1Selectarea datelor dintr-un database link


Dacă sunt mai multe baze de date instalate în sistem, există posibilitatea să se creeze legături între
acestea, astfel încât, printr-o sesiune deschisă pe o bază, să pot accesa informaţii din baza vecină.

In acest scop se creează o legătură (database link) între baza curentă şi altă bază din sistem:
 CREATE DATABASE LINK adina_link CONNECT TO adina IDENTIFIED BY adina USING 'stud'

Selectul dintr-un tabel aparţinând unei baze de date vecine se face prin intermediul legăturii create:
 select * from studenti@adina_link;

In felul acesta pot trece date dintr-o bază în alta, sau pot face un select care să afişeze datele cumulate din
cele două baze (folosim clauza Union):
 select studenti.nume_student || ' '|| studenti.prenume_student "Nume prenume student",
'baza db3' "baza de origine"
from studenti
union
select studenti.nume_student || ' '|| studenti.prenume_student "Nume prenume student",
'baza db1' "baza de origine"
from studenti@db1_link
order by "baza de origine" desc ;

5.2 Cereri SELECT pe mai multe tabele. Equi-join

De cele mai multe ori informaţiile necesare nu sunt stocate într-un singur tabel, ci sunt dispersate în mai
multe tabele. De exemplu, un caz tipic apare când vreau să văd studenţii pe fiecare grupă dintr-un anumit
an universitar. In acest caz datele se regăsesc în tabele diferite: tabela studenti conţine numele studenţilor,
iar tabela studenti_grupe conţine legătura între studenţi și grupe, iar tabela ani_universitari păstrează anii
universitari:
 select st.nume_student, st.prenume_student, g.cod_grupa,
au.cod_an_universitar
from studenti st, grupe g, studenti_grupe stg, ani_universitari au
where st.pk_student = stg.pk_student

Page 45 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

and stg.pk_grupa = g.pk_grupa


and stg.pk_an_universitar = au.pk_an_universitar
order by au.cod_an_universitar, g.cod_grupa;

Instrucţiunea select permite extragerea informaţiilor din mai multe tabele simultan. Pot vizualiza atât numele
studentului, cât şi specializarea acestuia, chiar dacă cele două informaţii sunt în tabele diferite. Important
este să existe o legătură (join) între cele două tabele astfel încât unei linii dintr-o tabelă să-i corespundă una
sau mai multe linii din cealaltă tabelă. Legătura între tabele se face prin coloane ce au aceleași valori (equi-
join). Când fraza select lucrează cu două tabele (sau mai multe), întotdeauna trebuie să existe clauza
where în care se specifică legătura între tabele. In selectul de mai sus legătura dintre tabela student si
tabela student_grupe se realizează prin coloana "pk_student" comună celor două tabele, în timp ce mai
departe se merge pe legătura "pk_an_universitar" pentru a lega anul universitar de selectul nostru.

Cum lucrează selectul în acest caz? Se aduce numele studentului şi pk-ul din tabela "studenti" şi apoi se
caută toate liniile din tabela "student_grupe" ce corespund acelui pk. Pentru fiecare din aceste linii se
testează dacă respectă cealaltă condiţie dată de pk_grupă (stg.pk_grupa = g.pk_grupa), cele care
nu respectă condiţia sunt eliminate din select. Se merge în continuare pe condiţia "pk_an_universitar" până
sunt eliminate toate liniile nedorite.

Ce se întâmplă dacă uit pur şi simplu să pun în clauza "where" legătura dintre tabele? Atunci e grav, se
umple ecranul cu zeci de rânduri fără nici o noimă. Fraza select face produsul cartezian între cele două
tabele şi afişează rezultatul (adică pentru fiecare linie din tabela "studenti" parcurge toate liniile din tabela
"studenti_grupe").
Concluzie: să nu uităm niciodată să punem în clauza "where" condiţia de legătură dintre tabele atunci când
selectăm coloane din mai multe tabele simultan.

Tema: să se construiască un select care să afişeze toţi studentii din facultate, împreună cu grupa,
disciplinele şi notele obţinute la examene:

Page 46 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

 select st.nume_student, st.prenume_student, g.cod_grupa,


d.cod_disciplina, n.nota, au.cod_an_universitar
from studenti st, grupe g, studenti_grupe stg, ani_universitari au, note
n, discipline d
where st.pk_student = stg.pk_student
and stg.pk_grupa = g.pk_grupa
and stg.pk_an_universitar = au.pk_an_universitar
and stg.pk_student_grupa = n.pk_student_grupa
and n.pk_disciplina = d.pk_disciplina
order by nume_student,au.cod_an_universitar, g.cod_grupa
;

5.3 Join extern

Să presupunem că este un student care nu este ataşat la nicio grupă, deci nu are nici o linie inserată în
tabela "studenti_grupe".
 insert into studenti values(null,'Chirila', 'C-tin',null);

Nu atașez nicio grupă la acest student şi facem un select care să-mi afişeze studenţii şi grupele ataşate:
 select st.nume_student, st.prenume_student, stg.pk_grupa
from studenti st, studenti_grupe stg
where st.pk_student = stg.pk_student
order by nume_student asc ;

Studentul Chirila nu apare în selectul precedent, chiar dacă el există în baza de date, deoarece linia
respectivă cade în clauza st.pk_student = stg.pk_student.
Totuşi, dacă vreau să vad toţi studenţii, indiferent dacă au grupe asociate sau nu, cei care au grupe
asociate să li se afişeze grupa, cei care nu au, să apară fără grupă, dar să apară, atunci trebuie folosit
operatorul Outer-join (sau operator '+' pentru bazele Oracle) de unire a tabelelor:
 select st.nume_student, st.prenume_student, stg.pk_grupa
from studenti st, studenti_grupe stg
where st.pk_student = stg.pk_student (+)
order by nume_student asc ;

Page 47 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

Operatorul (+) pus în dreapta tabelului ce nu are corespondent pentru fiecare linie din primul tabel, are ca
efect afişarea tuturor liniilor selectate din primul tabel, indiferent dacă au sau nu legătură cu cel de-al doilea.
Afişez şi codul grupei din care face parte studentul. In acest caz trebuie sa folosesc de două ori operatorul
"outer join" (+):
 select st.nume_student, st.prenume_student, stg.pk_grupa, g.cod_grupa
from studenti st, studenti_grupe stg, grupe g
where st.pk_student = stg.pk_student (+)
and stg.pk_grupa = g.pk_grupa (+)
order by nume_student asc
;

Alt exemplu este dat de afișarea studenţilor și notelor obţinute: dacă un student nu are notă, atunci prin
folosirea joncţiunii de tip "equi-join", studentul respectiv nu apare în rezultatul selectului:

 select st.nume_student, st.prenume_student, g.cod_grupa,


d.cod_disciplina, n.nota, au.cod_an_universitar
from studenti st, grupe g, studenti_grupe stg, ani_universitari au, note n,
discipline d
where st.pk_student = stg.pk_student
and stg.pk_grupa = g.pk_grupa
and stg.pk_an_universitar = au.pk_an_universitar
and n.pk_student_grupa = stg.pk_student_grupa
and n.pk_disciplina = d.pk_disciplina
order by nume_student,au.cod_an_universitar, g.cod_grupa
;

Page 48 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

Dar dacă se folosește joinul extern, atunci toţi studenţii din acel an universitar sunt afișaţi:

 select st.nume_student, st.prenume_student, g.cod_grupa,


d.cod_disciplina, n.nota, au.cod_an_universitar
from studenti st, grupe g, studenti_grupe stg, ani_universitari au, note n,
discipline d
where st.pk_student = stg.pk_student
and stg.pk_grupa = g.pk_grupa
and stg.pk_an_universitar = au.pk_an_universitar
and n.pk_student_grupa (+) = stg.pk_student_grupa
and n.pk_disciplina = d.pk_disciplina (+)
order by nume_student,au.cod_an_universitar, g.cod_grupa
;

Tabela "studenti_grupe" a fost unită cu tabela "note" prin intermediul unui join extern ce afișează liniile din
"student_grupe" care nu au în mod obligatoriu correspondent în tabela "note".

5.4 Clauza where. Operatori logici

5.4.1Operatori de comparaţie

In general, tabelele au mii de linii, milioane chiar, clauza where este cea care ne ajută să sortăm aceste linii
şi să scoatem numai informaţia de care avem nevoie. In această clauză sunt scrise expresii logice ce
returnează doar două valori: valoarea "adevărat" (true) sau valoarea "fals" (false). Expresiile logice sunt
construite cu ajutorul operatorilor de comparaţie:

Operator Explicaţie
= Egal cu
> Mai mare decât
>= Mai mare sau egal
< Mai mic decât
<= Mai mic sau egal
<> != Diferit de

Exemple:
1. Să se listeze toţi studenţii care au note mai mari de 8:
 select st.nume_student, st.prenume_student, g.cod_grupa,
d.cod_disciplina, n.nota, au.cod_an_universitar
from studenti st, grupe g, studenti_grupe stg, ani_universitari au, note
n, discipline d
where st.pk_student = stg.pk_student

Page 49 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

and stg.pk_grupa = g.pk_grupa


and stg.pk_an_universitar = au.pk_an_universitar
and stg.pk_student_grupa = n.pk_student_grupa
and n.pk_disciplina = d.pk_disciplina
and n.nota >8
order by nume_student,au.cod_an_universitar, g.cod_grupa
;

2. Să se listeze toţi studenţii care au luat nota 7:


 select st.nume_student, st.prenume_student, g.cod_grupa,
d.cod_disciplina, n.nota, au.cod_an_universitar
from studenti st, grupe g, studenti_grupe stg, ani_universitari au, note
n, discipline d
where st.pk_student = stg.pk_student
and stg.pk_grupa = g.pk_grupa
and stg.pk_an_universitar = au.pk_an_universitar
and stg.pk_student_grupa = n.pk_student_grupa
and n.pk_disciplina = d.pk_disciplina
and n.nota = 7
order by nume_student,au.cod_an_universitar, g.cod_grupa
;

3. Studenţii, disciplinele şi notele obţinute dar exceptând disciplina 'PSM1':

 select st.nume_student, st.prenume_student, g.cod_grupa,


d.cod_disciplina, n.nota, au.cod_an_universitar
from studenti st, grupe g, studenti_grupe stg, ani_universitari au, note
n, discipline d
where st.pk_student = stg.pk_student
and stg.pk_grupa = g.pk_grupa
and stg.pk_an_universitar = au.pk_an_universitar
and stg.pk_student_grupa = n.pk_student_grupa
and n.pk_disciplina = d.pk_disciplina
and d.cod_disciplina <> 'PSM1'
order by nume_student,au.cod_an_universitar, g.cod_grupa
;

5.4.2Operatori AND , OR, NOT

Clauza "where" poate conţine mai multe fraze care împreună să construiască valoarea de adevăr finală.
Frazele sunt legate prin trei termeni cheie:
 "and" : returnează "true" numai dacă toate frazele din compoziţie sunt "true"
 "or" : returneaza "true" dacă cel puţin o frază este "true".
 "not" : inversează valoarea de adevăr a frazei la care se aplică
Exemple:
1. Afişează studenţii care au obţinut la disciplina ME nota 7 şi nota 8:
 select st.nume_student, st.prenume_student, g.cod_grupa,
d.cod_disciplina, n.nota, au.cod_an_universitar

Page 50 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

from studenti st, grupe g, studenti_grupe stg, ani_universitari au, note


n, discipline d
where st.pk_student = stg.pk_student
and stg.pk_grupa = g.pk_grupa
and stg.pk_an_universitar = au.pk_an_universitar
and stg.pk_student_grupa = n.pk_student_grupa
and n.pk_disciplina = d.pk_disciplina
and d.cod_disciplina = 'ME'
and (n.nota=7 and n.nota=8 )
order by nume_student
;
Evident, selectul nu aduce nicio linie, nu există nici un student care să aibă în acelaşi timp nota 7 şi nota 8
la aceeaşi disciplină. Corect este:
 select st.nume_student, st.prenume_student, g.cod_grupa,
d.cod_disciplina, n.nota, au.cod_an_universitar
from studenti st, grupe g, studenti_grupe stg, ani_universitari au, note
n, discipline d
where st.pk_student = stg.pk_student
and stg.pk_grupa = g.pk_grupa
and stg.pk_an_universitar = au.pk_an_universitar
and stg.pk_student_grupa = n.pk_student_grupa
and n.pk_disciplina = d.pk_disciplina
and d.cod_disciplina = 'ME'
and (n.nota=7 or n.nota=8 )
order by nume_student
;

2. Să nu uităm să punem parantezele rotunde:


select st.nume_student, st.prenume_student, g.cod_grupa, d.cod_disciplina,
n.nota, au.cod_an_universitar
from studenti st, grupe g, studenti_grupe stg, ani_universitari au, note n,
discipline d
where st.pk_student = stg.pk_student
and stg.pk_grupa = g.pk_grupa
and stg.pk_an_universitar = au.pk_an_universitar
and stg.pk_student_grupa = n.pk_student_grupa
and n.pk_disciplina = d.pk_disciplina
and d.cod_disciplina = 'ME'
and n.nota=7 or n.nota=8
order by nume_student
;

Dacă uităm de paranteze, atunci obţinem sute de mii de linii cu informaţii eronate, deoarece pentru fiecare
notă de 8 din tabela note se repetă selectul iniţial.

Mai sunt disponibili şi alţi operatori de relaţie care ne ajută la construirea clauzei "where":

Page 51 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

5.4.3Operatorul "between"

Acest operator stabileşte un interval în care se află informaţia selectată:


Exemplu: afişează studenţii cu notele cuprinse în intervalul [5, 8]:
 select st.nume_student, st.prenume_student, g.cod_grupa,
d.cod_disciplina, n.nota, au.cod_an_universitar
from studenti st, grupe g, studenti_grupe stg, ani_universitari au, note
n, discipline d
where st.pk_student = stg.pk_student
and stg.pk_grupa = g.pk_grupa
and stg.pk_an_universitar = au.pk_an_universitar
and stg.pk_student_grupa = n.pk_student_grupa
and n.pk_disciplina = d.pk_disciplina
and d.cod_disciplina = 'ME'
and n.nota between 5 and 8
order by nume_student
;

5.4.4Operatorul "in"

Stabileşte o listă de valori în care se află informaţia selectată:


Ex: afişează studenţii cu notele incluse în mulţimea { 3, 4, 6, 8} :
 select st.nume_student, st.prenume_student, g.cod_grupa,
d.cod_disciplina, n.nota, au.cod_an_universitar
from studenti st, grupe g, studenti_grupe stg, ani_universitari au, note
n, discipline d
where st.pk_student = stg.pk_student
and stg.pk_grupa = g.pk_grupa
and stg.pk_an_universitar = au.pk_an_universitar
and stg.pk_student_grupa = n.pk_student_grupa
and n.pk_disciplina = d.pk_disciplina
and d.cod_disciplina = 'ME'
and n.nota in (4,6,8)
order by nume_student
;

5.4.5Operatorul "like"

Este operatorul care ne scoate din încurcătură când nu ştim ce căutăm, ci doar bănuim. Dacă nu ştiu
numele complet al unui student, ci doar câteva caractere, atunci folosesc clauza like pentru filtrarea liniilor:
1. Ex: caut studenţii de la litera A:
 select * from studenti
where studenti.nume_student like 'A%';

Page 52 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

Deci scriem în clauza where caracterele pe care le ştim sigur ("A") şi pentru restul caracterelor punem
simbolul "%". Fraza select anterioară se traduce: adu-mi toţi studenţii al căror nume începe cu litera "A".
2. Toate fetele din facultate (prenumele se termina cu litera 'a' sau 'A')
 select * from studenti
where (prenume_student like '%a' or prenume_student like '%A');

Ca să nu căutăm în zadar, utilizăm funcţia "upper" ce transformă toate literele în majuscule:


 select st.nume_student, st.prenume_student, upper(st.prenume_student)
from studenti st
where upper(prenume_student) like '%A';

3. Mă mai pot juca cu operatorul "like": vreau toţi studentii care au în componenţa numelui şirul de
caractere "ut":
 select st.nume_student, st.prenume_student, upper(st.prenume_student)
from studenti st
where upper(prenume_student) like '%UT%';

5.4.6Clauza distinct

Să afişăm studenţii şi grupele din care fac parte:


 select st.nume_student, st.prenume_student, g.cod_grupa
from studenti st, grupe g, studenti_grupe stg
where st.pk_student = stg.pk_student
and stg.pk_grupa = g.pk_grupa
order by nume_student, g.cod_grupa
;

In rezultat Iacob Adelina apare de două ori pentru ca a repetat anul şcolar, deci a fost de două ori în
aceeaşi grupă (chiar dacă în ani universitari diferiţi).

Daca vreau să afişez doar liniile distincte, ce nu repetă informaţia afişată de alte linii, folosesc clauza
"distinct":
 select distinct st.nume_student, st.prenume_student, g.cod_grupa
from studenti st, grupe g, studenti_grupe stg
where st.pk_student = stg.pk_student

Page 53 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

and stg.pk_grupa = g.pk_grupa


order by nume_student, g.cod_grupa
;

Directiva "distinct" înlătură informaţia care se repetă în rezultatul frazei select. In acest fel, studenţii vor fi
afişaţi o singură dată, indiferent de numărul de înregistrări găsite în tabela studenti.

Dar dacă se afişează şi pk_an_universitar, atunci Iacob Adelina apare iarăşi de două ori, pentru că, în acest
caz, liniile nu mai sunt identice.
 select distinct st.nume_student, st.prenume_student, g.cod_grupa,
stg.pk_an_universitar
from studenti st, grupe g, studenti_grupe stg
where st.pk_student = stg.pk_student
and stg.pk_grupa = g.pk_grupa
order by nume_student, g.cod_grupa
;

5.4.7Operatorul "is null"

O valoare nulă e o valoare care nu e disponibilă, neatribuită, necunoscută şi neaplicabilă. Adică, oriunde
folosim null într-o expresie, toată expresia devine null (false). Nu pot folosi expresii de tipul =null, sau
<>null.
De exemplu, mă interesează studenţii care nu au număr matricol; încercăm fraza următoare:
 select * from studenti where nr_matricol = null;

Evident, nu aduce nici o linie, am făcut o greşeală evidentă, am pus null într-o expresie logică.
Corect ar fi în felul următor:
 select * from studenti where nr_matricol is null;

Si viceversa, vrem să vedem studenţii care au număr matricol:


 select * from studenti where nr_matricol is not null;

5.5 Clauza ORDER BY

Clauza "order by" se foloseşte pentru a ordona liniile aduse de fraza select. Intotdeauna această clauză se
pune ultima într-o frază select. Liniile aduse de select nu sunt ordonate, de aceea e posibil ca acelaşi select

Page 54 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

rulat de mai multe ori să aducă liniile în ordine diferite. Order by rezolvă această problemă, prin ordonare,
aceeaşi linie va fi tot timpul la locul ei.
Să vedem studenţii în ordinea alfabetică:
 select st.nume_student, st.prenume_student
from studenti st
where st.nr_matricol is null
order by st.nume_student, st.prenume_student;

Implicit "order by" lucrează ascendent, adică de la valoare mică spre valoare mare. Dar dacă vreau să-i
afişez în ordine inversă, folosesc clauza "desc":
 select st.nume_student, st.prenume_student
from studenti st
where st.nr_matricol is null
order by st.nume_student desc, st.prenume_student desc;

Deci folosesc clauza "desc" (de la descendent) şi schimb ordinea de listare. Pentru ordinea ascendentă
folosesc cuvântul "asc" (dar acesta este implicit, nu trebuie scris neapărat).

Pot face ordonarea după mai multe coloane, îi pun în ordinea notelor, dar la aceeaşi notă, să fie în ordinea
alfabetică:
 select st.nume_student, st.prenume_student, g.cod_grupa,
d.cod_disciplina, n.nota, au.cod_an_universitar
from studenti_grupe stg, studenti st, ani_universitari au, grupe g,
specializari s,
discipline d, note n
where stg.pk_student = st.pk_student
and stg.pk_an_universitar = au.pk_an_universitar
and stg.pk_grupa = g.pk_grupa
and g.pk_specializare = s.pk_specializare
and s.pk_specializare = d.pk_specializare
and g.pk_an_studiu = d.pk_an_studiu
and n.pk_student_grupa = stg.pk_student_grupa
and n.pk_disciplina = d.pk_disciplina
order by n.nota desc, st.nume_student
;

La prima vedere pare ilogic să pun order by după nume_stud, deoarece această coloană nu este de tip
number, ca s-o poţi ordona. Dar să ne amintim că, toată informaţia din calculator este sub formă de
numere, deci are sens ordonarea. Literele din cadrul numelui studentului sunt memorate sub forma unor
numere ce corespund codurilor ASCII ale acelor litere. Nu întâmplător, codurile ASCII ale literelor
corespund ordinii din alfabet (litera "a" are codul ASCII mai mic decât litera "b").

Exerciţii:
1. Să se afişeze disciplinele studiate de grupele 6403 şi 6404:

Page 55 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

 select g.cod_grupa, d.cod_disciplina


from grupe g, specializari s,discipline d
where g.pk_specializare = s.pk_specializare
and s.pk_specializare = d.pk_specializare
and g.cod_grupa in ('6403','6404')
order by g.cod_grupa
;

Page 56 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

6 Funcţii SQL

Adesea avem nevoie ca informaţia adusă de fraza select să fie prelucrată înainte de afişare. Vreau să mă
asigur că toţi studenţii vor fi afişaţi cu litere mari. In acest caz folosesc funcţia "upper" ce prelucrează
informaţia de pe fiecare rând al rezultatului adus de fraza select:
 select upper(nume_student) from studenti;

Nu-mi place titlul coloanei adusă de fraza select, aş dori să se numească "nume student":
 select upper(nume_student) "nume student" from studenti ;

SQL permite definirea de alias-uri pentru nume de coloane astfel încât acestea să fie cât mai explicite.
Aceste alias-uri trebuie să urmeze imediat după numele coloanei în fraza select şi trebuie scrise folosind
ghilimele.

Funcţiile SQL se împart în două tipuri: funcţii de un singur rând , care întorc câte un rezultat pentru fiecare
linie adusă de fraza select, şi funcţii de grup ce prelucrează informaţia de pe mai multe linii şi returnează o
valoare pentru întreg grupul de linii.
In continuare sunt listate câteva funcţii de rând care se întâlnesc în mod frecvent în practica SQL:

6.1 Funcţii pentru prelucrarea şirurilor de caractere

1. Funcţie 2. Rezultat
LOWER Face conversia caracterelor alfabetice în litere mici
UPPER Face conversia caracterelor alfabetice in litere mari
INITCAP Face conversia pentru primul caracter din fiecare cuvânt în litera
mare iar pentru restul caracterelor conversia se face în litere mici
CONCAT(exp1,exp2) Concatenează cele două expresii
SUBSTR(expresie, Intoarce n caractere din cadrul expresiei începînd cu pozitia m.
m/,n/) Daca m este negativ atunci poziţia de început a numărării este
ultimul caracter din şir. Dacă n este omis atunci funcţia întoarce
toate caracterele de la poziţia m pîna la sfârşitul şirului.
LENGTH(expresie ) Intoarce numarul de caractere din expresie
INSTR(expresie ,"sir") Caută şirul de caractere "sir" în expresie şi întoarce poziţia unde a
fost găsit.
Exemple:

Page 57 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

 vrem sa facem un raport simplu in care fiecare student sa apară numai cu primele 3 litere
din nume (facem o prescurtare):
 select substr(nume_student,1,3) from studenti where rownum < 4;

Am pus condiţia rownum < 4 ca să aducă numai 3 linii din rezultatul selectului. Rownum este o coloană
implicită construită de motorul SQL în care se păstrează numărul liniei curente.

6.2 Funcţii pentru valori numerice

 funcţia round (numar, n): rotunjeşte numărul la n zecimale. Dacă n lipseşte, se rotunjeşte
la partea întreagă. Rotunjirea se face prin adaos (dacă numărul zecimal se apropie mai
mult de întregul superior, sau prin lipsă).
 funcţia trunc (numar, n): similar cu round numai că se face trunchiere, adică rotunjire prin
lipsă întotdeauna
 funcţia mod(n,m): întoarce restul împărţirii lui n la m

 select round(2.55) , round(2.49), trunc(2.55), mod(5,4) from dual;

 select round(2.55,1) , round(2.49,1), trunc(2.55,2), mod(8.2,3.3) from dual;

Tabela "dual" este o tabelă creată automat sub user-ul "sys" şi este accesibilă tuturor utilizatorilor. Are o
singură coloană "dummy" cu o singură linie "X":
 select * from dual;

Se utilizează când vrem să afişăm diverse informaţii care nu sunt în tabele din baza de date. Vreau să
afişez rezultatul împărţirii lui 3 la 2:
 select 3/2 from dual;

Page 58 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

Nu există altă posibilitate de a afişa informaţie decât prin fraza select, care are o sintaxă fixată: select ...
from nume_tabel, de aceea am nevoie de tabela "dual".

6.3 Funcţii pentru date calendaristice

Datele calendaristice ocupă un capitol important în cadrul SQL deoarece foarte multe informaţii sunt legate
de date calendaristice. Oracle memorează data calendaristică sub forma unui număr ce reţine următoarele
valori: secol, an, luna, zi, ora, minute, secunde. Coloanele din tabele care conţin date calendaristice sunt
definite cu tipul "date", similar cu "number" pentru numere sau "varchar2" pentru caractere.
 funcţia sysdate: returnează data curentă (citită din memoria CMOS a calculatorului):
 select sysdate "data curenta" from dual;

 select trunc(sysdate ,'mm') from dual;

 select sysdate + 1 from dual;

Un întreg adunat (sau scăzut) la o dată calendaristică creşte acea dată cu 1 zi. Vreau să cresc cu 7 ore de
exemplu, adun la data respectivă 7/24:
 select sysdate + 7/24 from dual;

 funcţia months_between(data1, data2): returnează numărul de luni între cele două date,
număr ce poate fi negativ dacă data2 e mai mica decât data1.
 add_month(data,n): adună n luni la data, n poate fi şi negativ
 next_day(data,'nume_zi'): găseşte data când cade prima dată ziua 'nume_zi' ce urmează
după data:
 select next_day(sysdate,'monday') from dual;

 last_day(data): aduce ultima zi din luna în care se află data:


 select last_day('23-sep-05') from dual;

Page 59 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

Exerciţii:
1. Să se găsească prima zi din luna următoare lunii curente:
 select last_day(sysdate) + 1 from dual;

2. Să se găsească când cade prima zi de vineri din luna viitoare:


 select next_day(last_day(sysdate),'friday') from dual;

3. Să se calculeze vârsta unui student pornind de la data lui de naştere

6.4 Funcţii pentru conversia tipului de date

Sunt funcţii ce permit conversia unui şir de caractere într-un număr sau într-o dată calendaristică sau
invers: din număr în şir de caractere.

6.4.1Conversia datelor de tip "date" în şiruri de caractere


 funcţia to_char(expresie, format): converteşte valoarea expresiei într-un şir de caractere
conform specificaţiilor date în câmpul format.
Vrem să afişăm data curentă (sysdate), dar într-un format specific: zi-luna-an:
 select to_char(sysdate,'dd-mon-yy') from dual;

Sunt permise o mulţime de formate pentru afişarea unei date calendaristice. Prezentăm în continuare doar
câteva mai semnificative:
YYYY sau YY sau Y Ultimele 4,2 sau 1 cifră din an
MM Luna scrisă cu două cifre
MONTH Numele întreg al lunii scris pe 9 caractere
MON Luna scrisă pe 3 caractere
WW sau W Saptamâna din an sau luna
DDD sau DD sau D Ziua din an ,luna sau saptamâna.
DAY Denumirea completă a zilei completată eventual
cu spaţii până la 9 caractere.
DY O abreviaţie a denumirii unei zile formată din trei

Page 60 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

litere
AM sau PM indicator de meridian
A.M. sau P.M. indicator de meridian cu puncte
HH sau HH12 sau HH24 ora
MI minute (0-59)
SS secunde (0-59)
SSSSS Numarul de secunde începînd cu miezul noptii

Exemplu:
 select to_char(sysdate,'ww') nr_saptamana_an, to_char(sysdate,'day-mon-yy') zi_luna_an
from dual;

 select to_char(sysdate,'day -> hh24:mm:ss') from dual;

6.4.2Conversia numerelor în şiruri de caractere

Funcţia to_char este utilizată şi pentru conversia numerelor în şiruri de caractere:


 select to_char(21.4) from dual;

Avem diverse formate sub care putem afişa valorile numerice:


 select to_char(234567.1,'999,999,999.00')format_suficient ,
to_char(234567,'9,999.00') format_prea_mic,
to_char(234567,'$999,999,999.00') cu_dolar, to_char(23.48,'999,999.0') rotunjire_zecimale,
to_char(23.67,'999,999') fara_zecimale
from dual;

Dacă nu specificăm un format funcţia to_char afişează numărul aşa cum este, fără separatoare sau
rotunjiri. Prin câmpul de formatare scris între apostrofuri sunt definite numărul de cifre pentru afişare, poziţia
virgulei de separare, numărul de zecimale, afişare cu monedă, etc. Observăm că dacă numărul de cifre
specificat în câmpul de formatare este prea mic, atunci to_char afişează semnul (#) în locul valorii
numerice.

Page 61 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

6.4.3Conversia datelor de tip text in format "date"

 funcţia to_date(expresie, format):


Funcţia to_date (expresie, format) returnează o valoare de tip dată calendaristică calculată pe baza
expresiei ce se interpretează conform şirului din câmpul format.
 select to_date('01/02/05','dd/mm/yy') "zi/luna/an" ,
to_date('01/02/05','mm/dd/yy') "luna/zi/an",
to_date('01-feb-05','dd-mon-yy') "zi-luna-an",
to_char(to_date('01-feb-05','dd-mon-yy'),'dd-mon-yy') "zi-luna-an cu to_char"
from dual;

Prin funcţia to_date transformăm un şir de caractere într-o dată. Intotdeauna avem probleme cu
interpretarea unui şir de caractere ce reprezintă o dată calendaristică. Să luăm de exemplu textul
"01/02/05"; poate fi interpretat ca fiind 1 februarie 2005 dacă lucrăm după modelul românesc, sau foarte
bine, poate fi 2 ianuarie 2005 interpretat după modelul american: mm/dd/yy (ei pun luna în faţa zilei). De
aceea, când transformăm un şir de caractere în dată trebuie să specificăm formatul. Mai rău este pentru cel
care utilizează programul, vede data 01/02/2005 şi nu ştie cum s-o interpreteze. In acest caz, data se
afişează prin funcţia to_char în care putem specifica exact cum trebuie să apară data la utilizator. Indicat
este să se utilizeze formatul cu litere pentru afişarea lunii, astfel încât să dispară orice dubii în citirea datei
calendaristice.
In coloana 3 din exemplul precedent, chiar dacă am utilizat formatul de citire a date sub forma 'dd-mon-yy',
ea a fost afişată tot cu cifre : 1/02/2005. Această afişare depinde de modul cum a fost setat programul SQL
Navigator, sau, dacă se utilizează SQL Plus de setările din regiştrii Windows: run ->regedit
->hkey_local_machine -> software ->oracle -> nls_date_format. Ca să nu mai depind de aceste setări ce
pot diferi de la un calculator la altul, am folosit funcţie to_char (coloana 4 din exemplul de mai sus).

6.4.4Conversia textului in format numeric


 funcţia to_number(sir_caractere, format):

Page 62 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

Prin to_number se returnează un număr pornind de la un şir de caractere. Acest şir este interpretat conform
formatului specificat şi tradus într-un număr. Dacă cele două câmpuri nu corespund, funcţia to_number dă
eroare.
 select TO_NUMBER('100.00', '9G999D99'), TO_NUMBER('5,342', '9G999D99'),
TO_NUMBER('5,342.14', '9G999D99') from dual;

6.5 Funcţia DECODE

Decode este o funcţie foarte puternică ce permite implementarea unei structuri de programare în codul
SQL. Funcţia nu este standard SQL, ea fiind specifică motorului Oracle. Prin funcţia decode putem simula
structura if - else specifică oricărui limbaj de programare în sensul că putem selecta informaţie diferită în
funcţie de anumite rezultate obţinute în procesul rulării.
Formatul funcţiei este:
decode (expresie, prima_varianta , rezultat1,
a_doua_varianta, rezultat2,
.............. ,
rezultat_default
);
Se evaluează expresia şi se compară valoarea acesteia cu variantele scrise în partea a doua a funcţiei. In
caz că valoarea expresiei coincide cu o variantă, se întoarce rezultatul corespunzător acelei variante, în caz
contrar se întoarce "rezultat_default".
Exemplu: să zicem că profesorul de la disciplina IB (Instrumentatie de Bord) vrea să mărească la
toţi studenţii nota cu 1 punct, iar profesorul de ME vrea să micşoreze notele cu 1 punct. Deci trebuie să
facem un select din tabela note, dar acest select să se comporte diferit, în funcţie de valoarea rândului
"cod_disciplina".
select stg.pk_student_grupa, st.nume_student, st.prenume_student, g.cod_grupa,
d.cod_disciplina, n.nota,
decode(d.cod_disciplina, 'IB', decode(n.nota, 10, 10, n.nota +1),
'ME',n.nota - 1,
n.nota) Nota_Modificata,

ast.cod_an_studiu, au.cod_an_universitar
from studenti_grupe stg, studenti st, ani_universitari au, grupe g,
specializari s,
discipline d, ani_studiu ast, note n
where stg.pk_student = st.pk_student

Page 63 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

and stg.pk_an_universitar = au.pk_an_universitar


and stg.pk_grupa = g.pk_grupa
and g.pk_specializare = s.pk_specializare
and s.pk_specializare = d.pk_specializare
-- and g.cod_grupa = '6303'
and g.pk_an_studiu = d.pk_an_studiu
and g.pk_an_studiu = ast.pk_an_studiu
and n.pk_student_grupa = stg.pk_student_grupa
and n.pk_disciplina = d.pk_disciplina
order by d.cod_disciplina
;

Se observă că la acelaşi student nota de la IB a crescut cu 1 punct în timp ce la ME a scăzut cu aceeaşi


valoare.

6.6 Funcţii de grup

6.6.1Funcţii matematice de grup

Aceste funcţii nu se aplică unei singure linii, ele calculează informaţii caracteristice unui grup de rânduri:
max, min, avg, count(*), sum.
 select max(nota),round(avg(nota),2), min(nota), sum(nota),
count(*), round(sum(nota)/count(*),2) from note;

In exemplul de mai sus am extras câteva informaţii globale ale tabelei "note":
 max(nota_finala) : calculează cea mai mare valoare din coloana "nota_finala". Chiar dacă
sunt mai multe note de 9, funcţia max returnează o singură valoare
 min(nota_finala) : returnează cea mai mica valoare din coloana "nota_finala";
 avg (nota_finala): calculează media aritmetică a notelor obţinute de studenţi;

Page 64 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

 sum(nota_finala) : calculează suma tuturor notelor;


 count(*) : returnează numarul de linii din tabela sit_finală.
Un avantaj al acestor funcţii e că nu prea sunt încurcate de valoarea null găsită pe anumite linii. Acea linie
care are valoarea null este ignorată pur şi simplu în calcularea valorilor cumulate. Putem verifica acest
lucru printr-un mic experiment. Hai să introducem o nouă linie în tabela note dar fără notă :
 update note set nota = null where pk_nota = 68;
şi acum ne uităm dacă s-a introdus linia:
 select * from note;

şi să calculăm din nou valorile min, max....

Suma a rămas aceeaşi, count(*) s-a schimbat şi are dreptate, count(*) returnează numărul de linii ale
tabelei "note". Din această cauză nu a mai ieşit corect nici media aritmetică calculată de noi sub forma
sum(nota)/count(*). Să observăm totuşi că media calculată cu avg(nota_finala) este corectă, deci funcţia
ştie să trateze valoarea null în mod corect.
Putem şi noi să calculăm corect media dacă numărăm numai liniile care au nota_finala diferită de
null: count(nota):
 select max(nota),round(avg(nota),2), min(nota), sum(nota),
count(*), round(sum(nota)/count(nota),2) from note;

Funcţiile min, max pot fi folosite şi pentru coloane care nu sunt în mod necesar de tip numeric. Aceste
funcţii au sens şi pentru şiruri de caractere sau date calendaristice:
 select min(nume_student), max(nume_student) from studenti ;

Evident, min(nume_stud) nu aduce studentul cu cel mai mic nume (adică format din cel mai mic număr de
caractere), ci primul student în ordinea alfabetică din grupul selectat.
Dacă vreau să văd câte caractere are cel mai mic nume (fără prenume) scriu următorul select:
 select min(length(substr(nume_student,1,instr(nume_student,' ')-1)))
from studenti;

Page 65 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

6.6.2Clauza "group by"

Până acum am calculat max,min, medie pentru tot tabelul "note". Dar aceste valori nu-mi spun mare lucru,
degeaba calculez eu media notelor pentru toţi anii de studii, la toate materiile şi-n toţi anii şcolari.

Mă interesează de exemplu să ştiu care a fost media pentru disciplina ME, media pentru AE, min, max pe
aceste discipline să pot face comparaţii, să trag eventual semnale de alarmă în caz că apar nişte situaţii
catastrofale.
Să afişăm notele obţinute pe discipline:
 select d.cod_disciplina, n.nota
from discipline d, note n
where n.pk_disciplina = d.pk_disciplina
order by d.cod_disciplina
;
Să calculăm media notelor la fiecare disciplină:
 select d.cod_disciplina, round(avg(n.nota),2)
from discipline d, note n
where n.pk_disciplina = d.pk_disciplina
order by d.cod_disciplina
;

 select d.cod_disciplina, round(avg(n.nota),2)


from discipline d, note n
where n.pk_disciplina = d.pk_disciplina
group by d.cod_disciplina
order by d.cod_disciplina
;

Evident că Oracle a dat eroare, ca să calculeze media, trebuie sa-i spui cum să grupeze liniile; media
înseamnă că există un grup, deci trebuie precizat cum se formează grupul. Când se afişează doar rezultatul
funcţiei pe un întreg tabel, nu avem nevoie de clauza "group by", funcţia face media pentru tot tabelul. In
cazul că dorim să vedem şi codul disciplinei, atunci trebuie să grupez liniile după acest cod. Grupurile se
formează cu clauza "group_by":
Deci, prima regulă: dacă vrem să afişăm o coloană într-un select ce foloseşte o funcţie de grup, acea
coloană trebuie să fie inclusă în clauza "group by", altfel Oracle dă eroare.

 Să încercăm o altă situaţie: care sunt disciplionele de la care s-au obţinut medii sub 8?

 select d.cod_disciplina, round(avg(n.nota),2)


from discipline d, note n
where n.pk_disciplina = d.pk_disciplina

Page 66 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

and round(avg(n.nota),2) < 8


group by d.cod_disciplina
order by d.cod_disciplina
;

Nu-i bun, nu pot folosi funcţiile de grup în clauza where. Pentru a face filtrări cu ajutorul funcţiilor de grup
folosim clauza "having":
 select d.cod_disciplina, round(avg(n.nota),2)
from discipline d, note n
where n.pk_disciplina = d.pk_disciplina
group by d.cod_disciplina
having round(avg(n.nota),2) < 8
order by d.cod_disciplina
;

Funcţiile de grup sunt foarte utile când sunt necesare statistici şi rapoarte finale. Cu ajutorul lor putem
sintetiza informaţia care să reflecte aspecte globale ale tabelelor.

Exerciţii:
- Care este cel mai bun student din grupa sa?
- Studenţii care repetă anul şcolar (se regăsesc de două ori în acelaşi an de studiu pe ani
universitari diferiţi)
- Studenţii care sunt peste media din grupa lor

Page 67 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

7 Subinterogări

7.1 Construcţia clauzei "where" prin subinterogare

De multe ori se întâmplă să nu putem scrie exact valorile care ne interesează în clauza where. De exemplu,
trebuie să dau un raport cu studenţii care au obţinut cea mai mare notă la o sesiune de examene. Problema
e că eu nu ştiu care este acea notă, poate fi 10, sau 9, sau 8 sau..... Ar trebui să aflu mai întâi care este cea
mai mare notă în sesiunea respectivă, iar această valoare se află în mod dinamic printr-un select interior:

 select st.nume_student, st.prenume_student, d.cod_disciplina, n.nota


from studenti st, studenti_grupe stg, note n, discipline d, ani_universitari
ani
where st.pk_student = stg.pk_student
and stg.pk_an_universitar = ani.pk_an_universitar
and stg.pk_student_grupa = n.pk_student_grupa
and n.pk_disciplina = d.pk_disciplina
and d.cod_disciplina = 'PSM1'
and ani.cod_an_universitar = '2011-2012'
and n.nota = (
select max(n.nota)
from studenti_grupe stg, ani_universitari ani, note n, discipline d
where n.pk_disciplina = d.pk_disciplina
and n.pk_student_grupa = stg.pk_student_grupa
and stg.pk_an_universitar = ani.pk_an_universitar
and d.cod_disciplina = 'PSM1'
and ani.cod_an_universitar = '2011-2012'
)
;

Dacă uneori se întâmplă ca subinterogarea să aducă mai mult de o linie, ceea ce duce la eroare Oracle,
este foarte posibil ca subinterogarea să nu aducă nici o linie, ceea ce propagă null-ul şi la interogarea
principală şi nu se afişează nimic.
De exemplu, dacă în seelctul inferior greşim codul disciplinei, atunci tot selectul principal dă greş:
 select st.nume_student, st.prenume_student, d.cod_disciplina, n.nota
from studenti st, studenti_grupe stg, note n, discipline d, ani_universitari
ani
where st.pk_student = stg.pk_student
and stg.pk_an_universitar = ani.pk_an_universitar
and stg.pk_student_grupa = n.pk_student_grupa
and n.pk_disciplina = d.pk_disciplina
and d.cod_disciplina = 'PSM1'
and ani.cod_an_universitar = '2011-2012'
and n.nota = (
select max(n.nota)
from studenti_grupe stg, ani_universitari ani, note n, discipline d
where n.pk_disciplina = d.pk_disciplina

Page 68 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

and n.pk_student_grupa = stg.pk_student_grupa


and stg.pk_an_universitar = ani.pk_an_universitar
and d.cod_disciplina = 'Psm1'
and ani.cod_an_universitar = '2011-2012'
)
;

 Să mai rezolvăm o problemă: toţi studenţii a căror medie pe un an universitar este mai mare decât
media notelor pe acel an universitar:

 select st.nume_student, st.prenume_student, avg(n.nota)


from studenti st, studenti_grupe stg, note n, ani_universitari ani
where st.pk_student = stg.pk_student
and stg.pk_an_universitar = ani.pk_an_universitar
and stg.pk_student_grupa = n.pk_student_grupa
and ani.cod_an_universitar = '2011-2012'
group by st.nume_student, st.prenume_student
having avg(n.nota) > (
select avg(n.nota) from note n, studenti_grupe stg, ani_universitari ani
where stg.pk_student_grupa = n.pk_student_grupa
and stg.pk_an_universitar = ani.pk_an_universitar
and ani.cod_an_universitar = '2011-2012'
)
;

7.2 Coloane obţinute prin subinterogări


O facilitate importantă a sintaxei SQL este că putem scrie subinterogări chiar în câmpul destinat coloanelor
dintr-o frază select. Am văzut că o coloană din fraza select trebuie să fie un câmp dintr-un tabel inclus în
clauza "from". Dar nu-i obligatoriu, putem construi coloane distincte printr-o subinterogare ce se leagă la
interogarea principală. Trebuie să fim atenţi doar ca această subinterogare să nu aducă mai mult de o
valoare, pentru că atunci am obţine eroare. Nu se pot afișa mai multe valori în aceeași linie și aceeași
coloană.

De exemplu, aș dori să afișez intr-un select numele studenţilor, disciplinele studiate, notele obţinute, dar și
media notelor obţinute la acea disciplină de ceilalţi studenţi. In felul acesta, aș putea face o evaluare mai
corectă a notei obţinute de student, dacă pot s-o compar cu media celorlalţi (nota 9 nu reprezintă o
realizare de exemplu, când media pe disciplină este 9.50).

 select st.nume_student, st.prenume_student, d.cod_disciplina, n.nota,


(select round(avg(nota),2)
from note where note.pk_disciplina = n.pk_disciplina
) medie_disciplina
from studenti st, studenti_grupe stg, note n, discipline d,
ani_universitari ani

Page 69 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

where st.pk_student = stg.pk_student


and stg.pk_an_universitar = ani.pk_an_universitar
and stg.pk_student_grupa = n.pk_student_grupa
and n.pk_disciplina = d.pk_disciplina
and ani.cod_an_universitar = '2011-2012'
;

In selectul de mai sus, s-a calculat media pe disciplină printr-un subselect care se leagă la valoarea
"pk_disciplina" din selectul principal.

7.3 Tabele intermediare

Complicăm puţin lucrurile: care sunt studenţii ce au media notelor peste media grupei din care face parte
fiecare (cei mai buni studenţi din grupa lor) ?
Deja problema s-a complicat: trebuie să găsim media fiecărui student şi să comparăm acea medie cu
media grupei din care face parte studentul. Selectul ar fi mai simplu dacă aş avea în bază două tabele:
- Un tabel care să dea studentul, grupa din care face parte şi media obţinută de student
- Un tabel ce conţine grupa şi media pe acea grupă
Dacă aş avea acele tabele, atunci selectul se construieşte mult mai simplu. Oracle permite definirea unor
tabele temporare, bazate pe un select şi care pot fi utilizate în acel select specific:

 select st.nume_student, st.prenume_student, medie_studenti.medie_stud


, medie_grupe.cod_grupa, medie_grupe.medie_grupa
from studenti st, studenti_grupe stg,
(
select g.pk_grupa , g.cod_grupa, round(avg(nota),2) medie_grupa
from grupe g, studenti_grupe stg, note n
where g.pk_grupa = stg.pk_grupa
and stg.pk_student_grupa = n.pk_student_grupa
group by g.pk_grupa, g.cod_grupa
)medie_grupe,

(select st.pk_student, round(avg(nota),2) medie_stud


from studenti st, studenti_grupe stg, note n
where st.pk_student = stg.pk_student
and stg.pk_student_grupa = n.pk_student_grupa
group by st.pk_student
) medie_studenti

where st.pk_student = stg.pk_student


and stg.pk_grupa = medie_grupe.pk_grupa
and st.pk_student = medie_studenti.pk_student
and medie_stud > medie_grupa
order by cod_grupa
;

Page 70 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

In clauza "from" am adăugat cele două selecturi, le-am dat denumire de tabele şi am putut să le utilizăm în
selectul superior.

Am văzut în acest capitol cât de puternică poate deveni instrucţiunea SELECT. In afara selectării clasice a
informaţiilor din tabelele bazei de date, selectul permite utilizarea subselecturilor în clauza where (care în
plus, pot face referire la tabelele din selectul superior) şi, de asemenea, permite construirea de tabele
temporare în clauza from (select din select).

7.4 Vizualizări

Vizualizările sunt tabele virtuale create printr-un select din alte tabele. Am văzut în subcapitolul anterior ce
util a fost să creez tabele intermediare cu mediile studenţilor, sau mediile grupelor. Alt exemplu, mi-ar fi
foarte util să am un tabel în care să găsesc numele studentului, specializarea, codul grupei din care face
parte, notele obţinute şi disciplinele la care a obţinut note. Cu un asemenea tabel aş putea lucra mult mai
uşor când fac selecturile.
De ce nu se creează asemenea tabele? Una din regulile proiectării bazei de date spune că un tabel nu
trebuie să conţină informaţii amestecate, cu identităţi şi funcţii diferite. Ce facem dacă se modifică o
denumire de specializare? Modificăm toate liniile tabelului?

Oracle îmi vine în ajutor şi mă lasă să-mi fac un tabel virtual care să conţină aceste câmpuri. Dar nu este un
tabel propriu-zis, ci o imagine ce oglindeşte informaţia din tabelele de bază. In felul acesta, orice modificare
într-un tabel de bază apare în mod automat şi în imaginea sa din tabela virtuală. Aceste tabele se numesc
vizualizări ( VIEW ) şi se construiesc cu ajutorul instrucţiunii select:

 Creez un view numit "medie_grupe" care să conţină toate grupele și media notelor pe acea grupă
în fiecare an universitar:
 create or replace view medie_grupe as
select g.pk_grupa , g.cod_grupa, round(avg(nota),2) medie_grupa,
ani.pk_an_universitar
from grupe g, studenti_grupe stg, note n, ani_universitari ani
where g.pk_grupa = stg.pk_grupa
and stg.pk_student_grupa = n.pk_student_grupa
and stg.pk_an_universitar = ani.pk_an_universitar
group by g.pk_grupa, g.cod_grupa, ani.pk_an_universitar
;
 Alt view numit "student_grupe_note" ce conţine studenţii cu grupele din care fac parte, disciplinele
studiate și notele obţinute:

 create or replace view studenti_grupe_note as

Page 71 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

select stg.pk_student_grupa, st.nume_student, st.prenume_student,


g.cod_grupa, d.cod_disciplina, n.nota, ani.pk_an_universitar
from studenti st, studenti_grupe stg, grupe g, note n, discipline
d, ani_universitari ani
where st.pk_student = stg.pk_student
and stg.pk_an_universitar = ani.pk_an_universitar
and stg.pk_grupa = g.pk_grupa
and stg.pk_student_grupa = n.pk_student_grupa
and n.pk_disciplina = d.pk_disciplina
;

In acest moment am un nou tabel în bază (chiar dacă este virtual) din care pot să fac select :
 select * from studenti_grupe_note;

Numai că acesta nu este un tabel obişnuit, este un tabel logic în care nu pot face modificări, inserări, etc.
Este o oglindă unde am grupat în mod avantajos informaţia din tabelele de bază astfel încât să am acces
mai uşor asupra datelor de interes.

Recapitulare:
In acest capitol am văzut cât de performantă poate fi o frază select, ce facilităţi extraordinare ne oferă
pentru căutarea și filtrarea datelor. Dacă facem acum o comparaţie cu modul de stocare a datelor în fișiere,
unde în afară de un suport de stocare aceste fișiere nu-mi oferă nimic, observăm că stocarea datelor în
baza de date este de departe mult mai avantajoasă.

Binenţeles, informaţia introdusă și analizată în tabelele de lucru din acest curs este ultraminimală, ca să nu
ocupăm spaţiul inutil afişând rezultatele selecturilor şi să putem urmări firul rezultatelor. In practică însă, pe
acelaşi principiu se pot stoca informaţii mult mai ample, cu zeci sau sute de mii de studenţi. Un întreg
centru universitar se introduce în aceeaşi bază de date ce rulează pe un singur calculator şi fiecare
profesor, student, secretară de la diverse facultăţi sau universităţi intră cu parola sa prin intermediul
internetului şi introduce sau vizualizează datele la care are dreptul. Putem gândi mai departe să creăm o
bază unică cu toţi studenţii din ţară ș.a.m.d. Să ne gândim ce bază de date uriașă reprezintă Google în
momentul de faţă și totuși ce repede se deschide o pagină Google care în ultimă instanţă, se bazează pe
un select dintr-o bază cu miliarde de linii.

Page 72 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

8 Instrucţiuni DML

Până acum ne-am ocupat de modul de extragere a informaţiilor din baza de date. Acum trebuie să acordăm
un timp special pentru tehnicile de introducere, modificare şi ştergere a datelor. Aceste instrucţiuni, care
modifică baza de date, se numesc instrucţiuni DML (Data Manipulation Language).

8.1 Comanda INSERT

Introducerea datelor în bază se face cu ajutorul comenzii INSERT prezentată în prima parte a cursului, fiind
necesară pentru completarea tabelelor iniţiale. Acum, când ştim mai multe despre baze de date, să facem
câteva precizări suplimentare.
Am văzut că formatul acestei comenzi este de forma:
 INSERT INTO nume_tabel (nume_coloana_1, nume_coloana_2,....,nume_coloana_n) VALUES
(val_1, val_2, ....., val_n);
Ca să introducem un student în tabela studenti, avem mai multe variante:
 insert into studenti(nume_student, prenume_student, nr_matricol)
values('Ionescu','Pavel', 1275);

 insert into studenti values(null,'Ionescu','Pavel', 1275);

In al doilea caz nu am mai specificat numele coloanelor, ceea ce înseamnă că le completăm pe toate. Dar
dacă uităm o coloană?
 insert into studenti values('Ionescu','Pavel', 1275);

Apare eroare: valori insuficiente. Nu știu ce valoare va primi prin trigger coloana pk_student, dar ea trebuie
pusă în câmpul values. In acest caz pot utiliza valoarea NULL.

Binenţeles, nu pot pune NULL peste tot unde nu ştiu valoarea coloanei.
 insert into studenti values(null, null,'Pavel', 1275);
deoarece se sesizează constrângerile definite pe tabela "studenti".

Aceste constrângeri trebuie definite chiar la început, înainte de introducerea datelor, tocmai ca să mă
protejeze împotriva datelor incoerente. Dacă am introdus câteva linii ce nu respectă condiţia de unicitate şi
de "not null", şi încercăm apoi să definim constrângerea, aceasta va eşua. Deoarece, la definire,

Page 73 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

constrângerea verifică dacă sunt date în bază ce nu respectă condiţiile impuse de ea. In caz că găseşte
date incorecte, dă eroare şi anulează definiţia.

Putem avea surpriza ca insert-ul să dea eroare, chiar dacă nu folosim NULL:
 insert into studenti_grupe(pk_student) values(100);

In acest caz a fost violată altă constrângere, cea de tip "foreign key" între tabela "studenti_grupe" şi
"studenti". Această constrângere specifică faptul că orice linie introdusă în tabela "studenti_grupe" trebuie
să aibă corespondent în mulţimea valorilor "pk_student" din tabela "studenti".

8.1.1Folosirea funcţiilor pentru completarea valorilor de insert

In momentul când introducem nota în catalog, trebuie să punem şi data examinării. De obicei, punem nota
în catalog în ziua examenului, de aceea, e bine ca sistemul să-mi propună automat ziua curentă pentru
coloana "data" din tabela "note". Pentru aceasta folosim funcţia "sysdate":
 insert into note(pk_student_grupa, pk_disciplina, nota, data)
values(26,2,9,sysdate);

8.1.2Utilizarea subinterogărilor în comanda insert

Anumite valori introduse de insert pot fi aduse în momentul execuţiei prin comanda select dintr-un alt tabel.
De exemplu, vreau să-i pun notă studentului Ionescu, dar nu ştiu ce pk are (îmi trebuie pk_student la
introducerea datelor în tabela note). Eu ştiu doar că-l cheamă Ionescu şi vreau să-i pun nota 8 la disciplina
'ME':
insert into note(pk_student_grupa, pk_disciplina, nota, data) values(
(select stg.pk_student_grupa from studenti st, studenti_grupe stg,
ani_universitari ani
where st.pk_student = stg.pk_student
and stg.pk_an_universitar = ani.pk_an_universitar
and st.nume_student = 'Ionescu'
and ani.cod_an_universitar = '2011-2012')
,(select pk_disciplina from discipline where cod_disciplina = 'ME')
,8,sysdate);

In acest caz, am adus pk-ul printr-un select din tabela "studenti". Trebuie respectate câteva condiţii ca să
meargă subinterogarea în insert: comanda select trebuie pusă în paranteze, să fie tratată ca un bloc unitar
şi ea trebuie să aducă numărul şi tipul de valori specificate în comanda insert.

Page 74 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

8.2 Comanda UPDATE

Ionescu nu este mulţumit cu nota 8, a venit a doua zi la mărire și a obţinut 10. Dar nu pot să mai pun o notă
în catalog deoarece el primește doar o notă pe sesiune, de aceea ar trebui să modific nota obţinută în ziua
precedentă:
 update note set nota=10 where pk_nota =
(select n.pk_nota
from studenti st, studenti_grupe stg, note n, discipline d
where st.pk_student = stg.pk_student
and stg.pk_student_grupa = n.pk_student_grupa
and n.pk_disciplina = d.pk_disciplina
and d.cod_disciplina = 'ME'
and st.nume_student = 'Ionescu');

Ce-am învăţat mărind nota lui Ionescu?


 sintaxa comenzii UPDATE:
 update nume_tabel
set nume_col_1 = val_1, nume_col_2=val_2, .... , nume_col_n=val_n
where conditie ;
După update si nume tabel urmează comanda set după care se scriu numele coloanelor şi valoarea
acestora. Dacă sunt mai multe coloane, se despart prin virgulă. Urmează clauza where care-i foarte
importantă în acest context.

De ce este importantă clauza where la update? Dacă la select am uitat sau am greşit această clauză, nu-i
nimic, eventual aduce prea multe date sau deloc. Ne uităm prin ele şi ne dăm seama imediat că ceva nu-i
în regulă. Dar dacă uităm să punem clauza "where" la "update"? Atunci e dezastru, modificăm notele la toţi
studenţii din tabela "note". Lipsind clauza "where", comanda "update" nu se mai opreşte la o singură linie
cum am fi dorit, ci parcurge toată tabela de date modificând nota. Iar ca dezastrul să fie complet, Oracle nu
se sesizează ca noi am făcut o greșeală imensă, el nu are de unde să știe că de fapt noi am dorit să
modificăm nota la un singur student.
 noile valori pe care le setăm în bază pot veni şi dintr-un alt tabel, aduse prin comanda
"select". Aceste subinterogări trebuie să respecte aceleaşi condiţii de la comanda "insert".

8.3 Comanda DELETE

Vreau să șterg nota pusă studentului Ionescu, el zice că preferă să aibă absent în loc de o notă mică.
 delete from note where pk_nota in
(select n.pk_nota
from studenti st, studenti_grupe stg, note n, discipline d

Page 75 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

where st.pk_student = stg.pk_student


and stg.pk_student_grupa = n.pk_student_grupa
and n.pk_disciplina = d.pk_disciplina
and d.cod_disciplina = 'ME'
and st.nume_student = 'Ionescu');

Sintaxa comenzii "Delete" respectă acelaşi tipar ca la celelalte comenzi DML:


 delete from nume_tabel where conditie.

ATENTIE: comanda delete nu şterge doar o valoare dintr-o coloană pe o anumită linie, această comandă
lucrează pe linii, ea şterge toată linia. Rămâne valabilă discuţia pentru clauza "where" de la comanda
"update": dacă clauza "where" este uitată sau greşit scrisă, atunci dezastrul este mai mare decât la
comanda "update". In acest caz se şterg toate liniile din tabel, sau, într-un caz mai fericit, mult mai multe
decât am fi dorit.

 Vreau să şterg toate liniile din tabel:


 delete from note;

Comanda delete şterge liniile din tabel, dar nu şi tabelul ca obiect al bazei de date. Obiectul se șterge prin
comanda DDL (Data Definition Language) "drop":
 drop table note;
Comanda DDL "drop" șterge complet tabela și nu se mai poate recupera nimic. Dacă de la delete se mai
pot recupera datele (în anumite condiţii ), după drop nu se mai poate face nimic.

8.3.1Stergerea în cascadă

Presupunem că vrem să ștergem un student din baza de date:


 delete from studenti where nume_student = 'Iacob';

Imediat obţinem o eroare de integritate:

Am definit o constrângere de tip "foreign key" între tabelele studenti și studenti_grupe bazată pe coloana
"pk_student":
 ALTER TABLE studenti_grupe
ADD CONSTRAINT fk_student_grupe_st FOREIGN KEY (pk_student)
REFERENCES studenti (pk_student)

Page 76 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

Această constângere nu permite ștergerea unei linii din tabela "studentI dacă există linii aferente în tabela
"studenti_grupe" (nu pot șterge studentul dacă el este înscris în diverse grupe, are note, etc. Toate aceste
informaţii ar rămâne suspendate în aer dacă s-ar șterge studentul).

Cum se poate rezolva problema? Sunt două soluţii:


 Mergem mai întâi în tabelele copil (note, studenti_grupe) și ștergem toate liniile atașate de
studentul ce trebuie șters și la urmă ștergem studentul:
 delete from note where pk_student_grupa in
(select pk_student_grupa
from studenti_grupe stg , studenti st
where stg.pk_student = st.pk_student
and st.nume_student = 'Iacob'
);
 delete from studenti_grupe where pk_student in
(select pk_student from studenti where nume_student = 'Iacob');

 delete from studenti where nume_student = 'Iacob';

 Modificăm definiţia constrângerii de tip "foreign key" dintre tabele adăugând sufixul "on
delete cascade":
 ALTER TABLE studenti_grupe drop CONSTRAINT fk_student_grupe_st;
 ALTER TABLE studenti_grupe
ADD CONSTRAINT fk_student_grupe_st FOREIGN KEY (pk_student)
REFERENCES studenti (pk_student) on delete cascade;

 ALTER TABLE note drop CONSTRAINT fk_nota_student;


 ALTER TABLE note
ADD CONSTRAINT fk_nota_student FOREIGN KEY (pk_student_grupa)
REFERENCES studenti_grupe (pk_student_grupa) on delete cascade;

Iar acum putem șterge foarte simplu studentul:


 delete from studenti where nume_student = 'Chiriac';

Foarte simplă a doua variantă , dar nu indicată. Pentru exemplul nostru a fost simplu, am avut numai aceste
trei tabele, dar ce ne facem dacă de tabela "studenti" se mai leagă şi alte tabele copil, care la rândul lor
sunt părinţi pentru alte tabele şi aşa mai departe? Punem peste tot "ON DELETE CASCADE" ? Nu-i bine,
putem scăpa de sub control aceste ştergeri şi la un moment dat, nu mai ştii de ce a dispărut disciplina de
matematică din bază când tu nu ai făcut decât să ştergi un student.

Page 77 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

9 Tranzacţii în baza de date


9.1 Comanda Rollback

Revenim la problema când am pus din greşeală la toată lumea nota 10:
 update note set nota = 10 ;
 select * from note;

Constat o eroare de proporţii, toată lumea are nota 10, la toate obiectele şi în toate sesiunile.

Din fericire încă mai pot corecta eroarea prin utilizarea comenzii ROLLBACK:
 rollback;
Pur şi simplu rulăm rollback şi totul s-a rezolvat, am revenit la situaţia iniţială. Problema e, cât de iniţială
este situaţia? Până la ce punct m-am întors cu baza de date?

9.2 Comanda Commit

Comanda ROLLBACK anulează ultima tranzacţie, dar când a început această tranzacţie?

Orice tranzacţie începe după comanda commit și se termină la comanda commit. Tranzacţia reprezintă un
şir de comenzi de tipul select, update, insert, etc, care este privit de Oracle ca un tot unitar: ori toate
comenzile se termină cu succes, ori sunt anulate toate.

De exemplu, ne hotărâm să ştergem un student din baza de date. Pentru aceasta începem să-i ştergem
notele, apoi prezenţa la curs, laborator, apoi din tabela de examene, apoi de la bibliotecă, etc.După ce
ştergem informaţiile din toate tabelele copil, la sfârşit ștergem din tabela "studenti". Dar ce se întâmplă
dacă, undeva pe parcurs, o instrucţiune dă eroare? De exemplu, când ștergem studentul din registrul
bibliotecii, constatăm că acest tabel are o altă tabelă copil cu cărţile împrumutate de la bibliotecă. Iar acel
student nu a returnat toate cărţile luate împrumut de la bibliotecă. Evident ca procesul de ștergere se
oprește aici și nu poate continua până când studentul nu returnează împrumuturile.
Pe de altă parte, avem deja efectuate câteva ștergeri din baza de date. Acestea trebuie refăcute, pentru că
nu putem lăsa unele tabele sterse și altele nu. Intreg procesul de ștergere trebuie terminat cu succes, caz

Page 78 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

în care încheiem tranzacţia prin comanda "Commit", altfel situaţia în bază trebuie să rămână aceeași.
Refacerea situaţiei se face prin comanda ROLLBACK , caz în care ne întoarcem la situaţia de la ultimul
commit executat.

Comanda commit încheie tranzacţia curentă astfel încât, toate modificările realizate până în acel moment
trec în stare definitivă. Prima comandă SQL după commit începe o nouă tranzacţie care se termină la
următorul commit. Să reţinem deci că prin ROLLBACK putem reface doar modificările din tranzacţia
curentă, nimic nu ne mai salvează după execuţia comenzii COMMIT.

9.2.1Commit implicit
Se întamplă ca uneori comanda Rollback să nu mai restaureze situaţia dată de ultimul commit. Aceasta
pentru că, uneori baza de date realizează un commit implicit, adică execută comanda commit fara ca noi să
comandăm explicit acest lucru.
Commit-ul implicit se execută atunci când utilizatorul rulează o comandă specială de tip DDL sau DCL:
 comandă DDL (Data Definition Language): de exemplu comanzile "create table..", "alter
table...",etc.
 comandă DCL (Data Control Language): "create user...", "grant user...",etc.

9.2.2 Comanda Savepoint

Este util câteodată să împărţim o tranzacţie în mai multe subtranzacţii şi să anulăm prin rollback numai o
anumită subtranzacţie. De exemplu, vindem un produs la un client, proces ce presupune mai multe etape:
- scoatem produsul din magazie (modificăm stocul din magazia respectivă)
- facem factură pentru client (adăugăm un document în tabela de documente emise)
- contăm acel document (pentru evidenţa contabilă)
Ce se întâmplă dacă nu merge contarea ? (nu ştiu exact care sunt conturile pe care trebuie să contez). Nu
mai vând produsul clientului? Dar el este la poartă şi aşteaptă să plece cu produsul.
In acest caz salvăm câteva puncte intermediare în tranzacţia noastră. După scoaterea produsului din
magazie definim un punct intermediar de succes :
 SAVEPOINT iesire_magazie_succes;
Mergem mai departe şi scoatem şi factura:
 SAVEPOINT factura;
Apoi contăm factura. Dacă totul e OK dăm un COMMIT, altfel mă intorc la ultima situaţie de succes:
 ROLLBACK to factura;

Page 79 of 98
Product name: Programarea sistemelor de masura I – note de Date: Sep - 2020
curs

Version no.: 6.0 CR no.: Author: Lucian Nita

In acest fel am reuşit să să scoatem factura clientului, rămânând pentru mai târziu să rezolvăm problema
contării.

Page 80 of 98
Baze de date
Project no. BD 2010 Product name: Baze de date – note de curs Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

10 PL/SQL

SQL este OK în majoritatea taskurilor pe care le avem de îndeplinit când lucrăm cu o bază de date. Dar de
multe ori, există necesitatea de a putea rula câteva linii de cod direct pe bază, să putem extrage informaţia
într-un mod mai flexibil.

De exemplu, m-ar interesa să afişez pentru fiecare student media sa generală calculată prin media
aritmetică a tuturor notelor obţinute de student. Dar doresc ca media generală să nu fie influenţată de
notele obţinute la sport sau alte materii opţionale. Mi-ar fi foarte uşor să aflu aceste informaţii dacă aş putea
scrie o funcţie care să primească ca parametru pk_student (identificatorul unic al studentului) şi să-mi
returneze acele valori de care am nevoie. E clar că într-o funcţie pot folosi acele bucle FOR, LOOP, WHILE,
condiţii IF de care avem atâta nevoie când este necesar să alegem din mai multe variante, să facem tot
felul de sume, să extragem informaţia în funcţie de anumite condiţii.

Oricât de puternic ar fi SQL-ul, tot mai avem nevoie de linii de cod, de tehnicile specifice limbajelor de
programare. Un alt avantaj al acestor programe (pe care le denumim PL/SQL) este dat de faptul că ele
rulează pe server, deci nu încărcăm în mod excesiv reţeaua de calculatoare cu un trafic imens între staţia
noastră şi server (de cât să cer de zeci de ori cu câte un select o porţiune de informaţie, scriu o funcţie
PL/SQL în bază care returnează o singură dată tot blocul de date cerut).

Ce înseamnă PL/SQL? înseamnă SQL introdus într-o structură de programare. Prin SQL obţinem o
informaţie care se afişează şi atât. Dar dacă vreau ca această informaţie să o salvez într-o variabilă şi apoi
să o prelucrez conform unui algoritm? In SQL clasic nu putem, de aceea folosim PL/SQL.

10.1 Structura programelor PL/SQL

Programele PL/SQL pot fi funcţii, proceduri, sau blocuri anonime de cod. Diferenţa între funcţii şi proceduri?
Funcţia întoarce o valoare, procedura nu întoarce nimic, prin codul ei modifică un obiect din baza de date
sau valoarea unui parametru.

Indiferent dacă este funcţie sau procedură structura este aceeaşi:


declare
nume_variabile tip;
begin
instructiuni;
RETURN return_value ; (numai pentru functii)

Page 81 of 98
Baze de date
Project no. BD 2010 Product name: Baze de date – note de curs Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

exception
WHEN exception_name THEN
instructiuni tratare exceptii ;
END;
Prima parte din program este rezervată declaraţiilor de variabile. Urmează blocul de instrucţiuni care se
termină cu instrucţiunea "end". Intre "begin" si "end" se poate include eventual clauza "exception" unde se
introduc instrucţiuni de tratare a erorilor apărute în blocul de instrucţiuni. Structura respectă arhitectura
oricărui limbaj de programare: declaraţie variabile, instrucţiuni, tratare erori (construcţia begin .... exception
... end poate fi privită ca un bloc try ... catch din limbajele de programare moderne).

Lucrând pe o bază de date care ne poate surprinde oricând cu date invalide sau lipsă, este obligatorie
tratarea erorilor printr-o clauză de tip exception, altfel eroarea se transmite mai departe şi apare la interfaţa
utilizator cu tot felul de mesaje Oracle neinteligibile pentru utilizatorul final.

10.2 Funcţia de calcul a mediei ponderate

Există o medie ponderată ce ia în calcul creditele obţinute de un student când promovează un examen.
Această medie are formula:
nr _ total _ discipline

 nr _ credite * nota i i
Medie _ ponderata  i 0
nr _ total _ discipline

 nr _ credite
i 0
i

Se face produsul dintre numărul de credite de la fiecare disciplină studiată de student într-un an de studiu și
nota obţinută de student. Suma produselor se împarte la numărul total de credite. In caz că studentul nu are
notă, atunci se consideră nota zero.

Este destul de clar că această problemă nu prea poate fi rezolvată prin SQL, deci se va construi o funcţie
ce primește ca parametru un numar dat de "pk_student_grupa" și va returna un număr ce reprezintă media
ponderată.

create or replace function calcul_medie_ponderata( p_pk_student_grupa in


number) return number is

cursor c_discipline_studiate is
select d.pk_disciplina, d.cod_disciplina, d.credite
from studenti_grupe stg, grupe g, discipline d

Page 82 of 98
Baze de date
Project no. BD 2010 Product name: Baze de date – note de curs Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

where stg.pk_grupa = g.pk_grupa


and g.pk_specializare = d.pk_specializare
and stg.pk_student_grupa = p_pk_student_grupa
and lower(d.cod_disciplina) != 'educatie fizica';

cursor c_note(p_pk_disciplina in number) is


select max(n.nota)
from note n
where n.pk_student_grupa = p_pk_student_grupa
and n.pk_disciplina= p_pk_disciplina;

v_medie_ponderata number := 0;
sum_credite number := 0;
sum_medie_credite number := 0;
nota_curenta number := 0;

begin
for rec in c_discipline_studiate loop
open c_note(rec.pk_disciplina);
fetch c_note into nota_curenta;
if c_note%notfound then
nota_curenta := 0;
end if;
close c_note;
sum_medie_credite := sum_medie_credite + nvl(rec.credite,0) *
nvl(nota_curenta,0);
sum_credite := sum_credite + nvl(rec.credite,0);
end loop;

if sum_credite != 0 then
v_medie_ponderata := sum_medie_credite/sum_credite;
else
v_medie_ponderata := 0;
end if;
return round(v_medie_ponderata,2) ;

exception when others then


return 0;
end;

Analiza funcţiei "calcul_medie_ponderata":


 Mai întâi sunt declarate variabilele "v_medie_ponderata", "sum_credite", "cursor c_note",
etc.
Ce este CURSORUL ? Un cursor este o zonă de memorie în care Oracle îşi depune rezultatele dintr-un
select. Orice select cu care ne-am obişnuit noi în SQL este de fapt un cursor pe care îl declară implicit
Oracle. In PL/SQL noi avem posibilitatea să definim explicit un astfel de cursor şi apoi să parcurgem zona
de memorie şi să extragem diverse valori. Avantajul este că ne putem plimba prin cursor şi pentru fiecare
valoare să executăm anumite operaţii în funcţie de parametri.

Page 83 of 98
Baze de date
Project no. BD 2010 Product name: Baze de date – note de curs Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

Am declarat două cursoare, unul ce aduce toate disciplinele studiate de studentul dat, celălalt aduce nota
obţinută de student la o disciplină dată.
 Am baleiat întreg cursorul "c_discipline_studiate" (for rec in
c_discipline_studiate loop) şi am calculat suma produselor dintre credite și note:
sum_medie_credite:=sum_medie_credite+nvl(rec.credite,0)*nvl(nota_curenta,0);
 Dacă studentul nu are notă, sau disciplina nu are credite, atunci se pune implicit zero
(nvl(nota_curenta,0).
 La sfârșit se calculează media prin împărţire:
if sum_credite != 0 then
v_medie_ponderata := sum_medie_credite/sum_credite;
else
v_medie_ponderata := 0;
end if;

 Nu lipsește clauza EXCEPTION unde se intră în caz de o eroare în codul nostru ("when others"
adică oricare ar fi eroarea , ea va fi tratată în acest segment). Aici nu facem nimic altceva decât
returnăm zero.
 Nu explicăm aici cum lucrează instrucţiunea IF sau altele (FOR, WHILE, EXIT, ... ) ele au aceeaşi
funcţiune ca-n orice limbaj de programare. Trebuie doar să fim atenţi la sintaxa lor care se
aseamănă cu cea din DELPHI.
 Testăm funcţia printr-un select obișnuit din bază:
 select st.nume_student, st.prenume_student,
calcul_medie_ponderata(stg.pk_student_grupa) medie_ponderata
from studenti st, studenti_grupe stg
where st.pk_student = stg.pk_student
;

10.3 Triggeri

O bază de date performantă trebuie să vină în întâmpinarea programatorilor cu diverse obiecte şi


mecanisme care să le facă munca mai uşoară. Unul din aceste obiecte este TRIGGER-ul.

Page 84 of 98
Baze de date
Project no. BD 2010 Product name: Baze de date – note de curs Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

TRIGER-ul este o secţiune de cod ce se execută automat la un anumit eveniment. Odată definit acel
eveniment, baza de date are grijă să lanseze în execuţie trigger-ul corespunzător ori de câte ori are loc
evenimentul. Este foarte util atunci când trebuie executate anumite sarcini în mod automat când sunt
întrunite anumite condiţiile impuse.

10.3.1 Completarea automată a coloanelor de tip PK

La inserarea datelor în baza de date am folosit în mod extensiv triggerii de completare a valorilor din
coloanele de tip "primary key". Am discutat în acel capitol problema completării valorilor unice și modul de
rezolvare prin utilizarea secvenţelor și trigerilor:

CREATE OR REPLACE TRIGGER bef_studenti_grupe


BEFORE INSERT ON studenti_grupe
REFERENCING NEW AS NEW OLD AS OLD FOR EACH ROW
begin
select pk_student_grupa.NEXTVAL into :new.pk_student_grupa from dual;
end;

In acest mod, indiferent de câţi utilizatori introduc simultan date în bază, se asigură în mod unic o valoare
de PK pentru fiecare.

Sintaxa unui trigger este aceeași cu a unui bloc PL/SQL cu diferenţa că, în cazul triggerului avem acces la
valorile vechi și noi din linia de tabel care tocmai se modifică.
In header-ul triggerului se definesc condiţiile de rulare care fac să se execute triggerul. In exemplul de mai
sus, dorim ca triggerul să se execute înaintea unui insert în tabela studenti_grupe:
BEFORE INSERT ON studenti_grupe
REFERENCING NEW AS NEW OLD AS OLD FOR EACH ROW
Ceea ce se traduce prin următoarele:
- Triggerul se execută înainte de a introduce datele (before insert)
- Se aplica la tabela "studenti_grupe" (ON studenti_grupe)
- Informaţiile care sunt înlocuite sunt accesibile prin construcţia "OLD", iar cele noi prin
constructia "NEW". Exemplu: ":new.pk_student_grupa" este valoarea care tocmai se
dorește a se introduce în linia curentă, coloana "pk_student_grupa". Avand acces la ambele
valori, putem face comparaţii și analize care să decidă dacă operaţia de modificare este
corectă sau nu.
- Triggerul se va executa pentru fiecare linie afecată de operaţia în desfașurare din tabelă (FOR
EACH ROW).

Page 85 of 98
Baze de date
Project no. BD 2010 Product name: Baze de date – note de curs Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

10.3.2 Verificarea notelor obţinute de studenţi

Un exemplu pentru demonstrarea utilităţii triggeri-lor este dat de necesitatea verificării notelor inserate în
tabela note. Din diverse cauze, poate interveni eroarea ca un student să primească notă la o disciplină pe
care nu o studiază (sunt mai multe surse de program care pot insera note: modulul de profesori, secretara
și pot interveni erori de acest tip). Binenţeles că se pot face verificări pe parcursul inserării notelor, dar toate
aceste verificări pot da eroare la fel de bine. De aceea, baza de date este ultima și cea mai sigură barieră
împotriva erorilor de acest fel. Se definește un trigger de verificare a notelor și în mod sigur acesta se va
executa întotdeauna când se introduce o nouă notă în tabel.

Triggerul de verificare a notelor este listat in continuare:


create or replace trigger verifica_disciplina_note
before insert or update on note
referencing new as new old as old for each row
begin
declare
cursor c_discipline_studiate is
select 1
from studenti_grupe stg, grupe g, discipline d
where stg.pk_grupa = g.pk_grupa
and g.pk_specializare = d.pk_specializare
and stg.pk_student_grupa = :new.pk_student_grupa
and d.pk_disciplina = :new.pk_disciplina;

dummy number;
begin
open c_discipline_studiate;
fetch c_discipline_studiate into dummy;
if c_discipline_studiate%notfound then
raise_application_error(-20101,'studentul nu poate primi nota
pentru ca nu studiaza disciplina respectiva');
end if;
close c_discipline_studiate;
exception when others then
raise_application_error(-20101,'Eroare ' || sqlerrm);
end;
end;

Dacă încercăm acum să introducem o notă la o disciplină greșită, obţinem eroare:


 insert into note values(null, 7, 10,9, sysdate);

Page 86 of 98
Baze de date
Project no. BD 2010 Product name: Baze de date – note de curs Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

Recapitulare:
 Acest ultim capitol din curs introduce câteva noţiuni elementare despre programarea PL/SQL.
 Nu toate bazele de date suportă limbajul PL/SQL ci doar cele mai performante.
 Executarea sarcinilor direct pe server, prin programare PL/SQL are multiple avantaje (trafic redus
în reţea, viteză mare de execuţie, eliminarea conflictelor de date între sesiuni, etc).
 Se pot define funcţii, proceduri, biblioteci de asemenea programe, triggeri ce se execută automat
pe evenimente prestabilite.
 Ușurează foarte mult din munca programaoriloe de aplicaţii complexe.

Page 87 of 98
Baze de date
Project no. BD 2010 Product name: Baze de date – note de curs Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

11 Bibliografie

 http://office.microsoft.com/ro-ro/access-help/notiuni-de-baza-despre-proiectarea-bazelor-de-date-
HA001224247.aspx

 http://www.w3schools.com/sql/default.asp

 http://st-curriculum.oracle.com/tutorial/SQLDeveloper/index.htm

 http://www.java2s.com/Tutorial/Oracle/CatalogOracle.htm

Page 88 of 98
Baze de date
Project no. BD 2010 Product name: Baze de date – note de curs Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

12 Anexe
12.1 Instructiunile SQL pentru crearea obiectelor în baza de date

In continuare sunt date frazele SQL ce creează tabelele de lucru împreună cu legăturile între ele.

12.1.1 Creare tabele


--ani universitari
delete from ani_universitari;
drop table ani_universitari;
create table ani_universitari
(
pk_an_universitar number,
cod_an_universitar varchar2(15),
descriere_an_universitar varchar2(50)
);
alter table ani_universitari add constraint pk_ani_universitari primary
key(pk_an_universitar);
alter table ani_universitari add constraint uk_cod_an_univ unique
(cod_an_universitar);
alter table ani_universitari add constraint uk_desc_ani_univ unique
(descriere_an_universitar);

--ani studiu
drop table ani_studiu;
create table ani_studiu
(
pk_an_studiu number,
cod_an_studiu varchar2(2),
descriere_an_studiu varchar2(50)
);
alter table ani_studiu add constraint pk_an_studiu primary key (pk_an_studiu);
alter table ani_studiu add constraint uk_cod_ani_studiu unique (cod_an_studiu);

-- specializari
drop table specializari;
create table specializari
(
pk_specializare number,
cod_specializare varchar2(15),
descriere_specializare varchar2(50)
);
alter table specializari add constraint pk_specializare primary key
(pk_specializare);
alter table specializari add constraint uk_specializare unique
(cod_specializare);

-- grupe
drop table grupe;

Page 89 of 98
Baze de date
Project no. BD 2010 Product name: Baze de date – note de curs Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

create table grupe


(
pk_grupa number,
cod_grupa varchar2(15),
descriere_grupa varchar2(50), -- aici punem descrieri diferite pentru
acelasi cod
pk_specializare number,
pk_an_studiu number
);
alter table grupe add constraint pk_grupa primary key (pk_grupa);
alter table grupe add constraint fk_grupa_specializare foreign key
(pk_specializare) references specializari(pk_specializare) ;
alter table grupe add constraint fk_grupa_an_studiu foreign key (pk_an_studiu)
references ani_studiu(pk_an_studiu) ;

--studenti
drop table studenti;
create table studenti
(
pk_student number,
nume_student varchar2(50),
prenume_student varchar2(50),
nr_matricol number
);

alter table studenti add constraint pk_student primary key (pk_student);


alter table studenti add constraint uk_nr_matricol_student unique
(nr_matricol);

--studenti_grupe
drop table studenti_grupe;
create table studenti_grupe
(
pk_student_grupa number,
pk_student number,
pk_grupa number,
pk_an_universitar number
);
alter table studenti_grupe add constraint pk_student_grupa primary key
(pk_student_grupa);
alter table studenti_grupe add constraint fk_student_grupe_st foreign key
(pk_student) references studenti(pk_student);
alter table studenti_grupe add constraint fk_student_grupe_gr foreign key
(pk_grupa) references grupe(pk_grupa);
alter table studenti_grupe add constraint fk_student_grupe_au foreign key
(pk_an_universitar) references ani_universitari(pk_an_universitar);

--discipline;
drop table discipline;
create table discipline
(
pk_disciplina number,
cod_disciplina varchar2(50),

Page 90 of 98
Baze de date
Project no. BD 2010 Product name: Baze de date – note de curs Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

descriere_disciplina varchar2(100),
pk_specializare number,
pk_an_studiu number,
semestru number,
credite number
);

alter table discipline add constraint pk_disciplina primary key


(pk_disciplina);
alter table discipline add constraint fk_disciplina_spec foreign key
(pk_specializare) references specializari(pk_specializare);
alter table discipline add constraint fk_disciplina_an_studiu foreign key
(pk_an_studiu) references ani_studiu(pk_an_studiu);
alter table discipline add constraint ck_semestru check (semestru in
(1,2));

--note
drop table note;
create table note
(
pk_nota number,
pk_student_grupa number,
pk_disciplina number,
nota number,
data date
);
alter table note add constraint pk_nota primary key (pk_nota);
alter table note add constraint fk_nota_student
foreign key (pk_student_grupa) references studenti_grupe(pk_student_grupa);
alter table note add constraint fk_not_disciplina foreign key
(pk_disciplina) references discipline(pk_disciplina);
ALTER TABLE note ADD CONSTRAINT ck_note CHECK (nota <= 10);

/* -------------------------------------------------------------------------

Secvente
--------------------------------------------------------------------------
*/
CREATE SEQUENCE pk_an_universitar
INCREMENT BY 1
START WITH 1
MINVALUE 1
MAXVALUE 9999999999999;
CREATE SEQUENCE pk_an_studiu;
CREATE SEQUENCE pk_specializare;
CREATE SEQUENCE pk_grupa;
CREATE SEQUENCE pk_student;
CREATE SEQUENCE pk_student_grupa;
CREATE SEQUENCE pk_disciplina;
CREATE SEQUENCE pk_nota;

/* ---------------------------------------------------------------------------

triggeri ---> completare automata a coloanei pk....

Page 91 of 98
Baze de date
Project no. BD 2010 Product name: Baze de date – note de curs Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

----------------------------------------------------------------------
*/

CREATE OR REPLACE TRIGGER bef_ani_universitari


BEFORE INSERT ON ani_universitari REFERENCING NEW AS NEW OLD AS OLD FOR EACH
ROW
begin
select pk_an_universitar.NEXTVAL into :new.pk_an_universitar from dual;
end;
/

CREATE OR REPLACE TRIGGER bef_ani_studiu


BEFORE INSERT ON ani_studiu REFERENCING NEW AS NEW OLD AS OLD FOR EACH ROW
begin
select pk_an_studiu.NEXTVAL into :new.pk_an_studiu from dual;
end;
/

CREATE OR REPLACE TRIGGER bef_specializari


BEFORE INSERT ON specializari REFERENCING NEW AS NEW OLD AS OLD FOR EACH ROW
begin
select pk_specializare.NEXTVAL into :new.pk_specializare from dual;
end;
/

CREATE OR REPLACE TRIGGER bef_grupe


BEFORE INSERT ON grupe REFERENCING NEW AS NEW OLD AS OLD FOR EACH ROW
begin
select pk_grupa.NEXTVAL into :new.pk_grupa from dual;
end;
/

CREATE OR REPLACE TRIGGER bef_studenti


BEFORE INSERT ON studenti REFERENCING NEW AS NEW OLD AS OLD FOR EACH ROW
begin
select pk_student.NEXTVAL into :new.pk_student from dual;
end;
/

CREATE OR REPLACE TRIGGER bef_studenti_grupe


BEFORE INSERT ON studenti_grupe REFERENCING NEW AS NEW OLD AS OLD FOR EACH ROW
begin
select pk_student_grupa.NEXTVAL into :new.pk_student_grupa from dual;
end;
/

CREATE OR REPLACE TRIGGER bef_discipline


BEFORE INSERT ON discipline REFERENCING NEW AS NEW OLD AS OLD FOR EACH ROW
begin
select pk_disciplina.NEXTVAL into :new.pk_disciplina from dual;
end;
/

Page 92 of 98
Baze de date
Project no. BD 2010 Product name: Baze de date – note de curs Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

CREATE OR REPLACE TRIGGER bef_note


BEFORE INSERT ON note REFERENCING NEW AS NEW OLD AS OLD FOR EACH ROW
begin
select pk_nota.NEXTVAL into :new.pk_nota from dual;
end;
/

12.1.2 Introducerea date în bază

select * from ani_universitari;


--1. ani_universitari
delete from ani_universitari;
insert into ani_universitari (pk_an_universitar, cod_an_universitar,
descriere_an_universitar)
values (-1, '2010-2011', 'an universitar 2010-2011');
insert into ani_universitari (pk_an_universitar, cod_an_universitar,
descriere_an_universitar)
values (-111, '2011-2012', 'an universitar 2011-2012');
insert into ani_universitari values (null, '2012-2013', 'an universitar 2012-
2013');
insert into ani_universitari (cod_an_universitar, descriere_an_universitar)
values ('2013-2014', 'an universitar 2013-2014');

--2. ani_studiu
insert into ani_studiu values(null,1,'an 1');
insert into ani_studiu values(null,2,'an 2');
insert into ani_studiu values(null,3,'an 3');
insert into ani_studiu values(null,4,'an 4');
insert into ani_studiu values(null,5,'an 5');
insert into ani_studiu values(null,6,'an 6');

--3. specializari
insert into specializari(cod_specializare,descriere_specializare)
values('IAD', 'Instrumentatie si Achizitii de Date');
insert into specializari(cod_specializare,descriere_specializare)
values('IA', 'Informatica Aplicata');
insert into specializari(cod_specializare,descriere_specializare)
values('EM', 'Electromecanica');
insert into specializari(cod_specializare,descriere_specializare)
values('EPAE', 'Actionari');

--4. discipline
insert into discipline values(null,'PSM1','Progr.Sist. de Masurare1',1,4,1);
insert into discipline values(null,'IB','Instrumentatie de bord',1,4,1);
insert into discipline values(null,'ME','Masurari Electrice',1,3,1);
insert into discipline values(null,'BD','Baze Date',2,3,1);
insert into discipline values(null,'MEP','Masini Electrice de putere',3,4,1);
insert into discipline values(null,'AE','Actionari Electrice',4,3,2);

--5. grupe
insert into grupe values(null,'6403','Grupa 6403',1,4);

Page 93 of 98
Baze de date
Project no. BD 2010 Product name: Baze de date – note de curs Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

insert into grupe values(null,'6404','Grupa 6404',1,4);


insert into grupe values(null,'6303','Grupa 6303',1,3);
insert into grupe values(null,'6401','Grupa 6401',3,4);
insert into grupe values(null,'6409','Grupa 6409',2,4);
insert into grupe values(null,'6402','Grupa 6402',4,4);

--6. inserez studentii in tabela


delete from studenti;
insert into studenti values(null,'Iosub','Ioan',null);
insert into studenti values(null,'Chiriac','Ionut',null);
insert into studenti values(null,'Proca','Ovidiu',null);
insert into studenti values(null,'Maxim','Ciprian',null);
insert into studenti values(null,'Condurache','George',null);
insert into studenti values(null,'Burca','Bogdan',null);

insert into studenti values(null,'Antohe','Adina',null);


insert into studenti values(null,'Iacob','Adelina',null);
insert into studenti values(null,'Hogas','Ionel',null);
insert into studenti values(null,'Pavel','Ionel',null);
insert into studenti values(null,'Jora','Bogdan',null);

insert into studenti values(null,'Burlacu','Cosmin',null);


insert into studenti values(null,'Simionescu','C-tin',null);
insert into studenti values(null,'Moisa','Cristina',null);

insert into studenti values(null,'Ichim','Andrei',null);


insert into studenti values(null,'Burlacu','Lucian',null);
insert into studenti values(null,'Puiu','Daniel',null);

insert into studenti values(null,'Maxim','Manuela',null);


insert into studenti values(null,'Lemnariu','Ana-Maria',null);

--7. Atasez studentii la grupe


delete from studenti_grupe;
insert into studenti_grupe(pk_student_grupa, pk_student, pk_grupa,
pk_an_universitar) values(-1,1,1,2);
insert into studenti_grupe(pk_student_grupa, pk_student, pk_grupa,
pk_an_universitar) values(-1,2,1,2);
insert into studenti_grupe(pk_student_grupa, pk_student, pk_grupa,
pk_an_universitar) values(-1,3,1,2);
insert into studenti_grupe(pk_student_grupa, pk_student, pk_grupa,
pk_an_universitar) values(-1,4,1,2);
insert into studenti_grupe(pk_student_grupa, pk_student, pk_grupa,
pk_an_universitar) values(-1,5,1,2);
insert into studenti_grupe(pk_student_grupa, pk_student, pk_grupa,
pk_an_universitar) values(-1,6,1,2);

insert into studenti_grupe(pk_student_grupa, pk_student, pk_grupa,


pk_an_universitar) values(-1,7,2,2);
insert into studenti_grupe(pk_student_grupa, pk_student, pk_grupa,
pk_an_universitar) values(-1,8,2,2);
insert into studenti_grupe(pk_student_grupa, pk_student, pk_grupa,
pk_an_universitar) values(-1,9,2,2);

Page 94 of 98
Baze de date
Project no. BD 2010 Product name: Baze de date – note de curs Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

insert into studenti_grupe(pk_student_grupa, pk_student, pk_grupa,


pk_an_universitar) values(-1,10,2,2);
insert into studenti_grupe(pk_student_grupa, pk_student, pk_grupa,
pk_an_universitar) values(-1,11,2,2);

insert into studenti_grupe(pk_student_grupa, pk_student, pk_grupa,


pk_an_universitar) values(-1,12,6,2);
insert into studenti_grupe(pk_student_grupa, pk_student, pk_grupa,
pk_an_universitar) values(-1,13,6,2);
insert into studenti_grupe(pk_student_grupa, pk_student, pk_grupa,
pk_an_universitar) values(-1,14,6,2);

insert into studenti_grupe(pk_student_grupa, pk_student, pk_grupa,


pk_an_universitar) values(-1,15,4,2);
insert into studenti_grupe(pk_student_grupa, pk_student, pk_grupa,
pk_an_universitar) values(-1,16,4,2);
insert into studenti_grupe(pk_student_grupa, pk_student, pk_grupa,
pk_an_universitar) values(-1,17,4,2);

insert into studenti_grupe(pk_student_grupa, pk_student, pk_grupa,


pk_an_universitar) values(-1,18,5,2);
insert into studenti_grupe(pk_student_grupa, pk_student, pk_grupa,
pk_an_universitar) values(-1,19,5,2);

-- stdenti de anul trecut


insert into studenti_grupe(pk_student_grupa, pk_student, pk_grupa,
pk_an_universitar) values(-1,1,3,1);
insert into studenti_grupe(pk_student_grupa, pk_student, pk_grupa,
pk_an_universitar) values(-1,2,3,1);
insert into studenti_grupe(pk_student_grupa, pk_student, pk_grupa,
pk_an_universitar) values(-1,3,3,1);
insert into studenti_grupe(pk_student_grupa, pk_student, pk_grupa,
pk_an_universitar) values(-1,4,3,1);
insert into studenti_grupe(pk_student_grupa, pk_student, pk_grupa,
pk_an_universitar) values(-1,5,3,1);
insert into studenti_grupe(pk_student_grupa, pk_student, pk_grupa,
pk_an_universitar) values(-1,6,3,1);

insert into studenti_grupe(pk_student_grupa, pk_student, pk_grupa,


pk_an_universitar) values(-1,7,2,1);
insert into studenti_grupe(pk_student_grupa, pk_student, pk_grupa,
pk_an_universitar) values(-1,8,2,1);

-- 7. Note
--grupa 6404
delete from note;
insert into note(pk_nota,pk_student_grupa,pk_disciplina,nota,data)
values(-1,26,2,5,sysdate-401);
insert into note(pk_nota,pk_student_grupa,pk_disciplina,nota,data)
values(-1,26,1,4,sysdate-402);

insert into note(pk_nota,pk_student_grupa,pk_disciplina,nota,data)

Page 95 of 98
Baze de date
Project no. BD 2010 Product name: Baze de date – note de curs Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

values(-1,7,2,10,sysdate-1);
insert into note(pk_nota,pk_student_grupa,pk_disciplina,nota,data)
values(-1,7,1,10,sysdate);

insert into note(pk_nota,pk_student_grupa,pk_disciplina,nota,data)


values(-1,9,2,8,sysdate-1);
insert into note(pk_nota,pk_student_grupa,pk_disciplina,nota,data)
values(-1,9,1,9,sysdate);

insert into note(pk_nota,pk_student_grupa,pk_disciplina,nota,data)


values(-1,8,2,9,sysdate-1);
insert into note(pk_nota,pk_student_grupa,pk_disciplina,nota,data)
values(-1,8,1,9,sysdate);

insert into note(pk_nota,pk_student_grupa,pk_disciplina,nota,data)


values(-1,11,2,5,sysdate-1);
insert into note(pk_nota,pk_student_grupa,pk_disciplina,nota,data)
values(-1,11,1,4,sysdate);

insert into note(pk_nota,pk_student_grupa,pk_disciplina,nota,data)


values(-1,10,2,9,sysdate-1);
insert into note(pk_nota,pk_student_grupa,pk_disciplina,nota,data)
values(-1,10,1,9,sysdate);
--grupa 6403
insert into note(pk_nota,pk_student_grupa,pk_disciplina,nota,data)
values(-1,2,2,8,sysdate-1);
insert into note(pk_nota,pk_student_grupa,pk_disciplina,nota,data)
values(-1,2,1,6,sysdate);

insert into note(pk_nota,pk_student_grupa,pk_disciplina,nota,data)


values(-1,4,3,4,sysdate);

--grupa 6401
insert into note(pk_nota,pk_student_grupa,pk_disciplina,nota,data)
values(-1,15,5,7,sysdate);
insert into note(pk_nota,pk_student_grupa,pk_disciplina,nota,data)
values(-1,16,5,9,sysdate);
insert into note(pk_nota,pk_student_grupa,pk_disciplina,nota,data)
values(-1,17,5,4,sysdate);

--grupa 6303
insert into note(pk_nota,pk_student_grupa,pk_disciplina,nota,data)
values(-1,25,3,5,sysdate);
insert into note(pk_nota,pk_student_grupa,pk_disciplina,nota,data)
values(-1,21,3,9,sysdate);
insert into note(pk_nota,pk_student_grupa,pk_disciplina,nota,data)
values(-1,24,3,8,sysdate);
insert into note(pk_nota,pk_student_grupa,pk_disciplina,nota,data)
values(-1,22,3,6,sysdate);
commit;

Page 96 of 98
Baze de date
Project no. BD 2010 Product name: Baze de date – note de curs Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

12.2 Fraze select în baza de date

12.2.1 Studenti-grupe-discipline-note
select stg.pk_student_grupa, st.nume_student, st.prenume_student, g.cod_grupa,
d.cod_disciplina, n.nota, n.data, d.pk_disciplina, ast.cod_an_studiu,
au.cod_an_universitar
from studenti_grupe stg, studenti st, ani_universitari au, grupe g,
specializari s,
discipline d, ani_studiu ast, note n
where stg.pk_student = st.pk_student
and stg.pk_an_universitar = au.pk_an_universitar
and stg.pk_grupa = g.pk_grupa
and g.pk_specializare = s.pk_specializare
and s.pk_specializare = d.pk_specializare
and g.cod_grupa = '6404'
and g.pk_an_studiu = d.pk_an_studiu
and g.pk_an_studiu = ast.pk_an_studiu
and stg.pk_student_grupa = n.pk_student_grupa
and d.pk_disciplina = n.pk_disciplina
order by au.cod_an_universitar, g.cod_grupa,st.nume_student
;

Page 97 of 98
Baze de date
Project no. BD 2010 Product name: Baze de date – note de curs Date: Feb - 2010

Document no. Version no.: 0.1 CR no.: Author: Lucian Nita

12.3 Creare useri, import, export


--exp luci2/luci2@statia1_scoala file=d:\stud.dmp
--imp pavel/pavel@statia1_scoala fromuser=luci2 touser=pavel file=d:\stud.dmp
drop user pavel cascade;
create user pavel identified by pavel;
grant dba to pavel;

Page 98 of 98

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