Baze de Date Versiunea 4.0 Nov 2011

142
Baze de date Note de curs

description

ok.

Transcript of Baze de Date Versiunea 4.0 Nov 2011

Page 1: Baze de Date Versiunea 4.0 Nov 2011

Baze de date

Note de curs

Page 2: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

Cuprins1 INTRODUCERE........................................................................................................................................................5

1.1 CE ESTE O BAZA DE DATE...................................................................................................................................51.2 CUM SE STOCHEAZA INFORMATIA IN BAZA DE DATE..........................................................................................71.3 INSTALAREA BAZEI DE DATE...............................................................................................................................8

1.3.1 Instalare Oracle 9i, 10g.............................................................................................................................91.3.2 Verificarea instalării bazei de date..........................................................................................................101.3.3 Dezinstalarea bazei Oracle. Exportul informatiilor din baza..................................................................11

1.3.3.1 Salvarea bazei de date:...........................................................................................................................................111.4 CE ESTE LIMBAJUL SQL...................................................................................................................................12

2 NOŢIUNI DE BAZĂ DESPRE PROIECTAREA BAZELOR DE DATE........................................................13

2.1 TERMENI DE ŞTIUT DESPRE BAZELE DE DATE...................................................................................................132.2 CE REPREZINTĂ O PROIECTARE BUNĂ A UNEI BAZE DE DATE?.........................................................................142.3 PROCESUL DE PROIECTARE...............................................................................................................................14

2.3.1 Determinarea scopului bazei de date.......................................................................................................152.3.2 Găsirea şi organizarea informaţiilor necesare........................................................................................152.3.3 Împărţirea informaţiilor în tabele............................................................................................................172.3.4 Transformarea elementelor informaţionale în coloane...........................................................................192.3.5 Specificarea cheilor primare....................................................................................................................212.3.6 Crearea relaţiilor tabelelor......................................................................................................................232.3.7 Crearea unei relaţii de tipul unul-la-mai-mulţi........................................................................................242.3.8 Crearea unei relaţii mai-mulţi-la-mai-mulţi............................................................................................252.3.9 Crearea unei relaţii de tipul unu-la-unu..................................................................................................272.3.10 Rafinarea proiectării................................................................................................................................282.3.11 Rafinarea tabelului Produse.....................................................................................................................292.3.12 Aplicarea regulilor de normalizare..........................................................................................................30

2.3.12.1 Prima formă normală..........................................................................................................................................312.3.12.2 A doua formă normală.......................................................................................................................................312.3.12.3 A treia formă normală........................................................................................................................................31

3 STRUCTURA ORGANIZATORICĂ A FACULTĂŢII. CREAREA BAZEI "STUD".................................33

3.1 CREAREA CONTULUI UTILIZATOR ÎN BAZA DE DATE........................................................................................333.2 STRUCTURA ORGANIZATORICĂ A FACULTĂŢII..................................................................................................333.3 STRUCTURA TABELELOR...................................................................................................................................34

3.3.1 Analiza tabelelor din baza de date...........................................................................................................353.4 RAFINAREA BAZEI DE DATE..............................................................................................................................383.5 CREAREA TABELELOR ÎN BAZA DE DATE..........................................................................................................393.6 TIPURI DE DATE DEFINITE ÎN BAZA DE DATE....................................................................................................40

4 CONSTRÂNGERI.................................................................................................................................................42

4.1 CONSTRÂNGERI DE TIP PRIMARY KEY (PK).....................................................................................................424.2 CONSTRÂNGERI DE UNICITATE (UK)................................................................................................................424.3 CONSTRÂNGERI DE TIP "NOT NULL" (NN).......................................................................................................434.4 CONSTRÂNGERI DE TIP "FOREIGN KEY"...........................................................................................................444.5 CONSTRÂNGERI DE TIP "CHECK".......................................................................................................................44

Page 2 of 101

Page 3: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

4.6 DEFINIREA CONSTRÂNGERILOR ÎN BAZA DE DATE "STUD"...............................................................................44

5 INTRODUCEREA DATELOR ÎN TABELE......................................................................................................46

5.1 SINTAXA COMENZII INSERT...............................................................................................................................465.2 VALOAREA NULL............................................................................................................................................465.3 INTRODUCEREA DATELOR ÎN TABELE...............................................................................................................47

6 EXTRAGEREA INFORMAŢIILOR DIN BAZA DE DATE............................................................................48

6.1 COMANDA SELECT.........................................................................................................................................486.1.1 Selectarea datelor dintr-un database link................................................................................................49

6.2 SELECTAREA INFORMAŢIILOR DIN MAI MULTE TABELE SIMULTAN..................................................................496.3 AFIŞAREA LINIILOR CE NU RESPECTĂ CONDIŢIA DE LEGĂTURĂ ÎN COMANDA SELECT.....................................516.4 CLAUZA WHERE. OPERATORI LOGICI................................................................................................................52

6.4.1 Operatori de comparaţie..........................................................................................................................526.4.2 Operatori AND , OR, NOT.......................................................................................................................536.4.3 Operatorul "between"...............................................................................................................................556.4.4 Operatorul "in".........................................................................................................................................556.4.5 Operatorul "like"......................................................................................................................................556.4.6 Clauza distinct..........................................................................................................................................566.4.7 Operatorul "is null"..................................................................................................................................57

6.5 CLAUZA ORDER BY.......................................................................................................................................58

7 FUNCŢII SQL........................................................................................................................................................60

7.1 FUNCŢII PENTRU PRELUCRAREA ŞIRURILOR DE CARACTERE............................................................................607.2 FUNCŢII PENTRU VALORI NUMERICE................................................................................................................617.3 FUNCŢII PENTRU DATE CALENDARISTICE.........................................................................................................627.4 FUNCŢII PENTRU CONVERSIA TIPULUI DE DATE...............................................................................................63

7.4.1 Conversia datelor de tip "date" în şiruri de caractere.............................................................................637.4.2 Conversia numerelor în şiruri de caractere.............................................................................................647.4.3 Conversia datelor de tip text in format "date".........................................................................................657.4.4 Conversia textului in format numeric.......................................................................................................66

7.5 FUNCŢIA DECODE...........................................................................................................................................667.6 FUNCŢII DE GRUP..............................................................................................................................................67

7.6.1 Functii matematice de grup......................................................................................................................677.6.2 Clauza "group by"....................................................................................................................................69

8 SUBINTEROGĂRI................................................................................................................................................72

8.1 CONSTRUCTIA CLAUZEI "WHERE" PRIN SUBINTEROGARE.................................................................................728.2 COLOANE OBŢINUTE PRIN SUBINTEROGĂRI......................................................................................................738.3 TABELE INTERMEDIARE....................................................................................................................................748.4 VIZUALIZĂRI.....................................................................................................................................................75

9 INSTRUCŢIUNI DML..........................................................................................................................................77

9.1 COMANDA INSERT..........................................................................................................................................779.1.1 Folosirea funcţiilor pentru completarea valorilor de insert....................................................................789.1.2 Utilizarea subinterogărilor în comanda insert.........................................................................................78

9.2 COMANDA UPDATE........................................................................................................................................799.3 COMANDA DELETE.........................................................................................................................................79

9.3.1 Stergerea în cascadă................................................................................................................................80

10 TRANZACŢII ÎN BAZA DE DATE................................................................................................................82

10.1 COMANDA ROLLBACK......................................................................................................................................8210.2 COMANDA COMMIT..........................................................................................................................................82

Page 3 of 101

Page 4: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

10.2.1 Commit implicit........................................................................................................................................8310.2.2 Comanda Savepoint..................................................................................................................................83

11 PL/SQL................................................................................................................................................................85

11.1 STRUCTURA PROGRAMELOR PL/SQL...............................................................................................................8511.2 FUNCŢIA DE CALCUL A MEDIEI PONDERATE.....................................................................................................8611.3 TRIGGERI...........................................................................................................................................................88

11.3.1 Completarea automată a coloanelor de tip PK........................................................................................8911.3.2 Verificarea notelor obţinute de studenţi...................................................................................................90

12 BIBLIOGRAFIE................................................................................................................................................92

13 ANEXE................................................................................................................................................................93

13.1 INSTRUCTIUNILE SQL PENTRU CREAREA OBIECTELOR ÎN BAZA DE DATE........................................................9313.1.1 Creare tabele............................................................................................................................................9313.1.2 Introducerea date în bază.........................................................................................................................97

13.2 FRAZE SELECT ÎN BAZA DE DATE....................................................................................................................10113.2.1 Studenti-grupe-discipline-note...............................................................................................................101

13.3 Creare useri, import, export............................................................................................................................102

Page 4 of 101

Page 5: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

1 Introducere

Acest curs se vrea un îndrumar pentru cei care vor să se iniţieze în domeniul bazelor de date, prezentând

modul de stocare a datelor şi principalele instrucţiuni de accesare a informaţiilor stocate în bază. 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 101

Page 6: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

Document no. Version no.: 3.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. Baza de date poate fi privită ca un container în care noi

introducem tot felul de piese electronice: rezistenţe, condensatori, circuite integrate de mărimi, culori şi

valori diferite. Dupa ce-am introdus aceste piese, putem să cerem bazei de date să ne spună câte

rezistenţe de 100 de Ohm există în container specificând culoarea, tehnologia de fabricaţie şi producătorul

pentru fiecare. Mai mult, piesele sunt descărcate simultan de mai mulţi lucrători, în timp ce alţii extrag

componente, alţii fac inventarul pentru a determina ce piese sunt în cantitatea critică şi trebuie făcute noi

comenzi de achiziţie.

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.

Page 6 of 101

Page 7: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

1.2 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.

1.2.1 Instalare 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.

Serviciile Windows sunt programe care se lansează automat la pornirea calculatorului ( de aceea stăm şi

aşteptăm atâta la pornire, Windows-ul are de pornit serviciile, la care am adăugat şi noi baza Oracle).

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).

Page 7 of 101

Page 8: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

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.2.2 Verificarea 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 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 =

Page 8 of 101

Page 9: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

(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.2.3 Dezinstalarea 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.2.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

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:

Page 9 of 101

Page 10: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

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 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 10 of 101

Page 11: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

2 Noţiuni de bază despre proiectarea bazelor de date

O bază de date proiectată corespunzător furnizează acces la informaţii precise, actualizate. Deoarece o

proiectare corectă este esenţială pentru atingerea scopurilor utilizării unei baze de date, investiţia în timpul

necesar învăţării principiilor unei bune proiectări este esenţială. În cele din urmă, veţi reuşi să creaţi o bază

de date care să vă îndeplinească necesităţile şi care să poată fi modificată cu uşurinţă.

Acest capitol furnizează indicaţii pentru planificarea unei baze de date. Veţi învăţa cum să decideţi de ce

informaţii aveţi nevoie, cum să împărţiţi aceste informaţii în tabele şi coloane corespunzătoare şi cum să

faceţi ca aceste tabele să interacţioneze între ele.

2.1 Termeni de ştiut despre bazele de date

Oracle organizează informaţiile în tabele: liste de rânduri şi coloane ce amintesc de registrul unui contabil

sau de o foaie de lucru din Microsoft Office Excel. Într-o bază de date simplă, se poate să aveţi doar un

singur tabel. Pentru cele mai multe baze de date va trebui să aveţi mai multe. De exemplu, se poate să

aveţi un tabel care stochează informaţii despre produse, alt tabel care stochează informaţii despre comenzi

şi un altul cu informaţii referitoare la clienţi.

Figura 1: Organizarea datelor in tabele

Fiecare rând se mai numeşte înregistrare şi fiecare coloană, de asemenea, se mai numeşte câmp. O

înregistrare este o modalitate semnificativă şi consistentă de a combina anumite informaţii. Un câmp este

Page 11 of 101

Page 12: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

un element singular de informaţie - un tip de element care apare în orice înregistrare. De exemplu, în

tabelul produse, fiecare rând sau înregistrare ar conţine informaţii despre un produs. Fiecare coloană sau

câmp conţine un anumit tip de informaţie despre acest produs, cum ar fi numele sau preţul.

2.2 Ce reprezintă o proiectare bună a unei baze de date?

Anumite principii ghidează procesul de proiectare al unei baze de date. Primul principiu este acela că

informaţiile dublură (numite şi date redundante) au o influenţă negativă, deoarece consumă spaţiu şi

sporesc probabilitatea producerii de erori şi inconsistenţe. Al doilea principiu îl reprezintă importanţa

corectitudinii şi caracterului complet al informaţiilor. Dacă baza de date conţine informaţii incorecte, orice

rapoarte care extrag informaţii din baza de date vor conţine, de asemenea, informaţii incorecte. Drept

urmare, orice decizie luată bazându-vă pe aceste rapoarte va fi greşit informată.

O proiectare bună a unei baze de date respecta urmatoarele:

Împarte informaţiile în tabele pe baza subiectelor, pentru a reduce datele redundante.

Furnizează programului Oracle informaţiile necesare pentru a asocia informaţiile din tabele după

necesităţi.

Asistă şi asigură acurateţea şi integritatea informaţiilor.

Adaptează necesităţile de procesare a datelor şi cele de raportare.

2.3 Procesul de proiectare

Procesul de proiectare constă în următorii paşi:

Determinarea scopului bazei de date :

o acesta ajută la pregătirea paşilor rămaşi.

Găsirea şi organizarea informaţiilor necesare:

o Adunarea tuturor tipurilor de informaţii pe care le înregistraţi în baza de date, cum ar fi

numele produsului şi numărul comenzii.

Împărţirea informaţiilor în tabele

o Împărţirea elementelor de informaţii în entităţi sau subiecte majore cum ar fi Produse sau

Comenzi. Apoi, fiecare subiect devine un tabel.

Transformarea elementelor de informaţii în coloane

Page 12 of 101

Page 13: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

o Decideţi ce informaţii să stocaţi în fiecare tabel. Fiecare element devine un câmp care este

afişat sub formă de coloană în tabel. De exemplu, un tabel Angajaţi poate include câmpuri,

cum ar fi Nume de familie şi Data angajării.

Specificarea cheilor primare

o Alegeţi cheia primară pentru fiecare tabel. Cheia primară este o coloană care se utilizează

pentru a identifica în mod unic fiecare rând. Un exemplu poate fi ID produs sau ID

comandă.

Configurarea relaţiilor din tabel

o Priviţi fiecare tabel şi decideţi cum se asociază datele dintr-un tabel cu datele din alte

tabele. Adăugaţi câmpuri la tabele sau creaţi noi tabele pentru a clarifica relaţiile, după

necesităţi.

Rafinarea proiectării

o Analizaţi proiectarea Pentru eliminarea erorilor. Creaţi tabele şi adăugaţi câteva înregistrări

de date eşantion. Vedeţi dacă reuşiţi să obţineţi rezultatele dorite din tabele. Efectuaţi

ajustări ale proiectării, după necesitate

Aplicarea regulilor de normalizare

o Aplicaţi regulile de normalizare a datelor pentru a vedea dacă tabelele sunt corect

structurate. Efectuaţi ajustări pentru tabele, după necessitate

2.3.1 Determinarea scopului bazei de dateEste o idee bună să vă notaţi scopul bazei de date pe o hârtie - scopul acesteia, cum doriţi să o utilizaţi şi

cine o va utiliza. Pentru o bază de date mică pentru o afacere de familie, de exemplu, se poate nota ceva

simplu, cum ar fi "Baza de date a clienţilor păstrează o listă a informaţiilor despre clienţi în scopul producerii

de liste de corespondenţă şi de rapoarte." Dacă baza de date este mai complexă sau este utilizată de mai

multe persoane, cum se întâmplă de obicei într-o conjunctură corporativă, scopul se poate întinde pe mai

multe paragrafe şi trebuie să includă când şi de către cine va fi utilizată baza de date. Ideea principală este

să se descrie riguros misiunea bazei de date, care să fie consultată în cadrul procesului de proiectare. O

astfel de instrucţiune vă ajută să vă concentraţi asupra obiectivelor atunci când luaţi decizii.

2.3.2 Găsirea şi organizarea informaţiilor necesarePentru a găsi şi organiza informaţiile necesare, începeţi cu informaţiile existente. De exemplu, se pot

înregistra comenzile de cumpărare într-un registru sau se pot ţine informaţii despre clienţi în formulare, într-

un dulap pentru dosare. Colectaţi aceste documente şi treceţi în listă fiecare tip de informaţii afişate (de

exemplu, fiecare casetă completată dintr-un formular). Dacă nu aveţi formulare existente, imaginaţi-vă că

trebuie să proiectaţi un formular pentru a înregistra informaţii despre clienţi. Ce informaţii aţi dori să puneţi

în formular? Ce casete de completat aţi crea? Identificaţi şi treceţi în listă toate aceste elemente. De

Page 13 of 101

Page 14: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

exemplu, să presupunem că în prezent ţineţi lista de clienţi pe fişe indexate. Examinând aceste fişe veţi

descoperi că fiecare fişă conţine numele, adresa, oraşul, statul, codul poştal şi numărul de telefon ale unui

client. Fiecare dintre aceste elemente poate reprezenta o coloană din tabel.

Pe măsură ce pregătiţi lista, nu vă faceţi griji dacă nu este perfectă din prima încercare. În schimb, treceţi în

listă fiecare element la care vă gândiţi. Dacă va utiliza şi altcineva baza de date, cereţi-i părerea. Lista se

poate îmbunătăţi ulterior.

Apoi, luaţi în considerare tipurile de rapoarte sau de liste poştale pe care doriţi să le obţineţi din baza de

date. De exemplu, se poate crea un raport de vânzări pentru un produs, care afişează vânzările în funcţie

de regiune sau un raport de rezumare a inventarului, care afişează nivelurile de inventar ale produselor. De

asemenea, se pot genera scrisori formale, care li se vor trimite clienţilor pentru a îi anunţa de evenimente

sau de oferte speciale. Proiectaţi mintal raportul şi imaginaţi-vă cum ar arăta. Ce informaţii aţi dori să puneţi

în raport? Treceţi fiecare element în listă. Faceţi acelaşi lucru pentru scrisoarea formală şi pentru orice alt

raport pe care consideraţi că îl veţi crea.

Proiectarea mentală a rapoartelor şi a listelor poştale pe care doriţi să le creaţi vă ajută la identificarea

elementelor de care veţi avea nevoie în baza de date. De exemplu, să presupunem că le oferiţi clienţilor

oportunitatea de a se abona (sau a se dezabona) la actualizări periodice prin poştă electronică şi că doriţi

să imprimaţi o listă a celor care s-au abonat. Pentru a înregistra acele informaţii, adăugaţi o coloană

“Abonat la mesaje de poştă electronică” la tabelul pentru clienţi. Pentru fiecare client, se poate seta câmpul

la Da sau la Nu.

Page 14 of 101

Page 15: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

Necesitatea de a le trimite mesaje de poştă electronică clienţilor sugerează alt element de înregistrat. După

ce ştiţi că un client doreşte să primească mesaje de poştă electronică, va trebui să aflaţi adresa de poştă

electronică la care să le trimiteţi. Aşadar, trebuie înregistrată o adresă de poştă electronică pentru fiecare

client.

Este logic să se construiască un prototip al fiecărui raport sau listare de ieşire şi să se ia în considerare

elementele necesare pentru a produce raportul. De exemplu, când examinaţi o scrisoare formală, se poate

să vă vină în minte alte idei. Pentru a include o formulă introductivă corespunzătoare — de exemplu, şirul

"Dl.", "Dna." sau "Dra." cu care începe o formulă de salut, va trebui creat un element pentru introducere. De

asemenea, este mai bine să se înceapă scrisorile cu “Dragă Dl. Georgescu”, decât cu “Dragă Dl. Florin

Georgescu”. Aşadar, de obicei este mai bine să se stocheze numele de familie separat de prenume.

Trebuie să se ţină cont de faptul că informaţiile trebuie despărţite în cele mai mici părţi utile. În cazul unui

nume, pentru ca numele de familie să fie uşor disponibil, se va despărţi numele în două părţi — Nume şi

Prenume. Pentru a sorta un raport după numele de familie, de exemplu, este util să se stocheze separat

numele de familie ale clienţilor. În general, pentru a sorta, căuta, celula sau raporta în funcţie de un element

informaţional, trebuie pus acel element într-un câmp propriu.

Gândiţi-vă la întrebările la care doriţi să răspundă baza de date. De exemplu, câte vânzări s-au finalizat

pentru produsul principal? Unde locuiesc cei mai importanţi clienţi? Cine este furnizorul produsului care se

vinde cel mai bine? Anticiparea acestor întrebări că ajută să vă daţi seama de elementele suplimentare

care trebuie înregistrate.

După ce colectaţi aceste informaţii, sunteţi gata pentru pasul următor.

2.3.3 Împărţirea informaţiilor în tabele

Pentru a împărţi informaţiile în tabele, alegeţi cele mai importante entităţi sau subiecte. De exemplu, după

ce găsiţi şi organizaţi informaţiile unei baze de date pentru vânzări de produse, lista preliminară poate

conţine:

Page 15 of 101

Page 16: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

Entităţile principale afişate aici sunt produsele, furnizorii, clienţii şi comenzile. Aşadar, este logică să porniţi

cu aceste patru tabele: unul pentru date despre produse, unul pentru date despre furnizori şi unul pentru

date despre comenzi. Deşi lista este incompletă, este un punct de pornire bun. Lista se poate rafina până

când se ajunge la un proiect care funcţionează bine.

Când examinaţi prima dată lista preliminară de elemente, veţi fi tentat(ă) să le plasaţi pe toate într-un singur

tabel, în locul celor patru afişate în imaginea precedentă. Veţi învăţa acum de ce nu este o idee bună. Luaţi

în considerare tabelul afişat aici:

În acest caz, fiecare rând conţine informaţii atât despre produs, cât şi despre furnizorul lui. Deoarece se

poate ca multe produse să aibă acelaşi furnizor, numele şi informaţiile furnizorului se repetă de multe ori.

Acest lucru iroseşte spaţiul de pe disc. Înregistrarea informaţiilor despre furnizor o singură dată, într-un

tabel separat denumit Furnizori, iar apoi legarea acelui tabel cu tabelul Produse, este o soluţie mult mai

bună.

A doua problemă a acestui proiect apare atunci când trebuie modificate informaţiile despre furnizor. De

exemplu, să presupunem că trebuie schimbată adresa unui furnizor. Deoarece apare în multe locuri, se

Page 16 of 101

Page 17: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

poate, în mod accidental, să modificaţi adresa într-un loc şi să uitaţi să o modificaţi în celelalte. Înregistrarea

adresei furnizorului într-un singur loc rezolvă problema.

Când proiectaţi baza de date, încercaţi să înregistraţi fiecare informaţie o singură dată. Dacă se repetă

aceeaşi informaţie, cum ar fi adresa unui anumit furnizor, în mai multe locuri amplasaţi informaţia într-un

tabel separat.

În final, să presupunem că există un singur produs furnizat de Coho Winery şi că doriţi să ştergeţi produsul,

dar să păstraţi numele şi informaţiile furnizorului. Cum se poate şterge înregistrarea produsului fără a pierde

informaţiile despre furnizor? Este imposibil. Deoarece fiecare înregistrare conţine date despre un produs,

cât şi despre un furnizor, este imposibil să se şteargă separat. Pentru a menţine datele separate, trebuie

împărţit tabelul în două tabele: unul pentru informaţii despre produse şi celălalt pentru informaţii despre

furnizori. Ştergerea înregistrării unui produs ar trebui să şteargă doar datele despre produs, nu şi datele

despre furnizor.

După ce alegeţi subiectul reprezentat de un tabel, coloanele din acel tabel trebuie să stocheze numai datele

despre acel subiect. De exemplu, tabelul pentru produse trebuie să stocheze numai date despre produse.

Deoarece adresa unui furnizor este o informaţie despre furnizor, şi nu una despre produs, aparţine de

tabelul pentru furnizori.

2.3.4 Transformarea elementelor informaţionale în coloane

Pentru a stabili coloanele dintr-un tabel, decideţi asupra informaţiilor necesare pentru subiectul înregistrat în

tabel. De exemplu, pentru tabelul Clienţi, Nume, Adresă, Oraş-CodPoştal, Abonat la mesaje de poştă

electronică, Formulă introductivă şi Adresă de poştă electronică reprezintă o listă de coloane bună, pentru

început. Fiecare înregistrare a tabelului conţine acelaşi set de coloane, aşadar se pot stoca informaţiile din

câmpurile Nume, Adresă, Oraş-CodPoştal, Abonat la mesaje de poştă electronică, Formulă introductivă şi

Adresă de poştă electronică pentru fiecare înregistrare. De exemplu, coloana pentru adrese conţine

adresele clienţilor. Fiecare înregistrare conţine date despre un client, iar câmpul pentru adresă conţine

adresa acelui client.

După ce stabiliţi setul iniţial de coloane pentru fiecare tabel, aveţi posibilitatea să îmbunătăţiţi coloanele. De

exemplu, este logic să se stocheze numele clienţilor în două coloane: prenume şi nume de familie, pentru a

fi posibilă sortarea, căutarea şi indexarea pentru una singură dintre coloane. Similar, adresa este alcătuită

din cinci componente separate, adresă, oraş, judeţ, cod poştal şi ţară/regiune, şi este logic să se stocheze

şi acestea în coloane separate. Pentru a efectua o operaţiune de căutare, filtrare sau sortare după judeţ, de

exemplu, trebuie ca informaţiile despre judeţ să se stocheze într-o coloană separată.

Page 17 of 101

Page 18: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

De asemenea, trebuie să se ştie dacă informaţiile conţinute în baza de date au doar caracter intern sau şi

internaţional. De exemplu, dacă planificaţi să stocaţi adrese internaţionale, este mai bine să aveţi o coloană

Regiune în locul coloanei Judeţ, deoarece o astfel de coloană poate conţine judeţe naţionale sau alte

ţări/regiuni. Asemănător, codul poştal este mai bun decât codul Zip dacă stocaţi adrese internaţionale.

Următoarea listă afişează câteva sfaturi pentru stabilirea coloanelor.

Nu includeţi date calculate

În cele mai multe cazuri, nu trebuie stocate rezultatele unor calcule în tabele. În schimb, Oracle poate

efectua calculele atunci când doriţi să vedeţi rezultatele. De exemplu, să presupunem că există un

raport Produse comandate care afişează subtotalul unităţilor comandate, pentru fiecare categorie de

produse din baza de date. Cu toate acestea, nu există o coloană Subtotal Unităţi comandate în niciun

tabel. În schimb, tabelul Produse include o coloană Unităţi comandate, care stochează unităţile

comandate din fiecare produs. Utilizând aceste date, Oracle calculează subtotalul de fiecare dată

când imprimaţi raportul. Subtotalul nu trebuie stocat într-un tabel.

Stocaţi cele mai mici părţi logice din informaţii.

Poate fi tentant să creaţi un singur câmp pentru nume complete, sau pentru numele produselor

împreună cu descrierile produselor. Dacă se combină mai multe tipuri de informaţii într-un câmp, este

dificil să se regăsească ulterior date individuale. Încercaţi să despărţiţi informaţiile în părţi logice; de

exemplu, creaţi câmpuri separate pentru prenume şi pentru nume de familie, sau pentru numele

produselor şi pentru categorii şi descrieri.

Page 18 of 101

Page 19: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

După îmbunătăţirea coloanelor de date din fiecare tabel, se poate alege cheia primară a fiecărui tabel.

2.3.5 Specificarea cheilor primare

Fiecare tabel ar trebui să includă o coloană sau un set de coloane care identifică, în mod unic, fiecare rând

stocat în tabel. De obicei, se utilizează un număr unic de identificare, cum ar fi numărul de ID al unui

angajat sau un număr de serie. În terminologia bazelor de date, aceste informaţii reprezintă cheia primară a

tabelului. Oracle utilizează câmpuri de tipul cheie primară pentru a asocia rapid date din tabele multiple şi a

cumula datele.

Dacă aveţi deja un identificator unic pentru un tabel, cum ar fi un număr de produs care identifică în mod

unic fiecare produs din catalog, aveţi posibilitatea să utilizaţi acel identificator ca şi cheie primară a tabelului

— dar numai dacă valorile din această coloană vor fi întotdeauna diferite pentru fiecare înregistrare. Nu pot

exista valori duplicate într-o cheie primară. De exemplu, nu utilizaţi numele oamenilor pentru cheia primară,

deoarece numele nu sunt unice. Este foarte posibil să existe doi oameni cu acelaşi nume în acelaşi tabel.

O cheie primară trebuie întotdeauna să aibă o valoare. Dacă este posibil ca valoarea unei coloane să

devină neatribuită sau necunoscută (valoare lipsă) la un anumit moment, nu se poate utiliza ca şi

componentă într-o cheie primară.

Trebuie întotdeauna să alegeţi o cheie primară a cărei valori nu se va schimba. Într-o bază de date care

utilizează mai multe tabele, se poate utiliza cheia primară a unui tabel care referinţă în alte tabele. Dacă se

Page 19 of 101

Page 20: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

schimbă cheia primară, modificarea trebuie aplicată oriunde se face referire la cheie. Utilizarea unei chei

primară care nu se va modifica reduce şansele de a se desincroniza cheia primară cu tabelele care fac

referinţă la ea.

Deseori, e utilizează ca şi cheie primară un număr unic arbitrar. De exemplu, i se poate atribui fiecărei

comenzi un număr unic de comandă. Singurul scop al numărului de comandă este identificarea unei

comenzi. O dată atribuit, nu se schimbă niciodată.

Dacă nu aveţi o coloană sau un set de coloane care se poate utiliza ca şi cheie primară, luaţi în considerare

utilizarea unei coloane care are tipul de date AutoNumerotare. Când se utilizează tipul de date

AutoNumerotare, Oracle atribuie automat o valoare. Un astfel de identificator nu are date; nu conţine

informaţii care descriu rândul pe care îl reprezintă. Identificatorii fără date sunt ideali pentru rolul de cheie

primară, deoarece nu se modifică. Este mai posibil ca o cheie primară care conţine date despre un rând —

de exemplu, un număr de telefon sau numele unui client — să se modifice, deoarece se poate modifica

informaţia în sine.

O coloană setată la tipul de date AutoNumerotare este o cheie primară potrivită. Nu există două ID-uri

identice pentru produse.

În unele cazuri, este de preferat să se utilizeze două sau mai multe câmpuri care împreună asigură cheia

primară a unui tabel. De exemplu, un tabel Detalii Comenzi care stochează elemente de linie pentru

comenzi ar folosi două coloane în cheia sa primară : ID Comandă şi ID Produs. Când o cheie primară

utilizează mai mult de o coloană, aceasta se mai numeşte şi cheie compusă.

În cazul bazei de date pentru vânzări de produse, se poate crea o coloană de tipul AutoNumerotare pentru

fiecare dintre tabele, pentru a îndeplini rolul de cheie primară: IDProdus pentru tabelul Produse,

IDComandă pentru tabelul Comenzi, IDClient pentru tabelul Clienţi şi IDFurnizor pentru tabelul Furnizori.

Page 20 of 101

Page 21: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

2.3.6 Crearea relaţiilor tabelelor

După ce aţi împărţit informaţiile în tabele, este nevoie de o asociere utilă a informaţiilor. De exemplu,

următorul formular include informaţii din mai multe tabele.

Informaţiile din acest formular provin din tabelul Clienţi...

Page 21 of 101

Page 22: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

…tabelul Angajaţi...

…tabelul Comenzi...

…tabelul Produse...

…şi tabelul Detalii Comandă.

Oracle este un sistem de gestionare a bazelor de date relaţionale. Într-o bază de date relaţională,

informaţiile se împart în tabele separate, bazate pe subiecte. Se pot utiliza relaţiile dintre tabele pentru a

asocia informaţiile în moduri utile.

2.3.7 Crearea unei relaţii de tipul unul-la-mai-mulţi

Luaţi în considerare acest exemplu: tabelele Furnizori şi Produse din baza de date pentru comenzi de

produse. Un furnizor poate furniza oricâte produse. Aşadar, pentru orice furnizor din tabelul Furnizori pot

exista multe produse în tabelul Produse. Relaţia dintre tabelul Furnizori şi tabelul Produse este, prin

urmare, o relaţie de tipul unul-la-mai-mulţi.

Pentru a reprezenta o relaţie de tipul unul-la-mai-mulţi în proiectul bazei de date, luaţi cheia primară din

partea "unu" a relaţiei şi adăugaţi-o ca o coloană suplimentară la tabelul din partea "mai-mulţi" a relaţiei. În

acest caz, de exemplu, se adaugă coloana ID furnizor, din tabelul Furnizori, la tabelul Produse. Oracle

poate utiliza numărul de ID al furnizorului în tabelul Produse pentru a găsi furnizorul potrivit pentru fiecare

produs.

Page 22 of 101

Page 23: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

Coloana ID furnizor din tabelul Produse se numeşte cheie externă. O cheie externă este cheia primară a

unui alt tabel. Coloana ID furnizor din tabelul Produse este o cheie externă, deoarece este şi cheia primară

a tabelului Furnizori.

Furnizaţi baza pentru a uni tabelele legate prin stabilirea perechilor de chei primare şi chei externe. Dacă nu

sunteţi sigur care tabele ar trebui să partajeze o coloană comună, identificarea unei relaţii unu-la-mai-mulţi

va asigura necesitatea unei coloane partajate între cele două tabele implicate.

2.3.8 Crearea unei relaţii mai-mulţi-la-mai-mulţi

Luaţi în considerare relaţia dintre tabelul Produse şi tabelul Comenzi.

O comandă poate include mai multe produse. Pe de altă parte, un produs poate apărea în mai multe

comenzi. De aceea, pentru fiecare înregistrare din tabelul Comenzi, pot exista mai multe înregistrări în

tabelul Produse. Şi pentru fiecare înregistrare din tabelul Produse, pot exista mai multe înregistrări în

tabelul Comenzi. Această relaţie este de tipul mai-mulţi-la-mai-mulţi, deoarece pentru orice produs pot

exista mai multe comenzi; şi pentru orice comandă pot exista mai multe produse. Reţineţi faptul că pentru a

detecta relaţiile de tipul mai-mulţi-la-mai-mulţi dintre tabele, este important să luaţi în considerare ambele

sensuri ale relaţiei.

Page 23 of 101

Page 24: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

Subiectele celor două tabele — comenzi şi produse — se află într-o relaţie mai-mulţi-la-mai-mulţi. Acest

lucru prezintă o problemă. Pentru a înţelege problema, imaginaţi-vă ce s-ar întâmpla dacă aţi încerca să

creaţi o relaţie între două tabele adăugând câmpul ID produs la tabelul Comenzi. Pentru a avea mai mult de

un produs pentru fiecare comandă, aveţi nevoie de mai mult de o înregistrare pentru fiecare comandă în

tabelul Comenzi. S-ar repeta informaţiile despre comandă pentru fiecare rând asociat cu o comandă —

rezultând o proiectare ineficientă care poate produce date exacte. Aceeaşi problemă apare dacă se adaugă

câmpul ID comandă la tabelul Produse — rezultă mai multe înregistrări în tabelul Produse pentru fiecare

produs. Cum se rezolvă această problemă?

Răspunsul este crearea celui de-al treilea tabel, numit adesea tabel de joncţiune, care separă relaţia mai-

mulţi-la-mai-mulţi în două relaţii unu-la-mai-mulţi. Inseraţi cheia primară a fiecăruia dintre cele două tabele

în al treilea tabel. Ca rezultat, al treilea tabel înregistrează fiecare apariţie sau instanţă a relaţiei.

Fiecare înregistrare din tabelul Detalii comandă reprezintă un element linie într-o comandă. Cheia primară a

tabelului Detalii comandă constă în două câmpuri — cheile externe ale tabelelor Comenzi şi Produse.

Utilizarea câmpului ID comandă singur nu funcţionează ca o cheie primară pentru acest tabel, deoarece o

comandă poate avea mai multe elemente linie. ID comandă se repetă pentru fiecare element linie dintr-o

comandă, astfel încât câmpul nu conţine valori unice. Nici utilizarea câmpului ID produs singur nu

funcţionează, deoarece un produs poate apărea în mai multe comenzi diferite. Dar, împreună, cele două

câmpuri produc întotdeauna o valoare unică pentru fiecare înregistrare.

Page 24 of 101

Page 25: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

În baza de date pentru vânzări de produse, tabelele Comenzi şi Produse nu sunt asociate direct. În schimb,

ele sunt asociate indirect prin tabelul Detalii comandă. Relaţia mai-mulţi-la-mai-mulţi între comenzi şi

produse se reprezintă în baza de date utilizând două relaţii unu-la-mai-mulţi:

Între tabelele Comenzi şi Detalii comandă există o relaţie unu-la-mai-mulţi. Fiecare comandă are mai

mult de un element line, dar fiecare element linie este conectat cu o singură comandă.

Între tabelele Produse şi Detalii comandă există o relaţie unu-la-mai-mulţi. Fiecare produs poate avea

mai multe elemente linie asociate, dar fiecare element linie face referire la un singur produs.

Din tabelul Detalii comandă, se pot determina toate produsele dintr-o anumită comandă. De asemenea, se

pot determina toate comenzile pentru un anumit produs.

După incorporarea tabelului Detalii comandă, lista tabelelor şi câmpurilor poate arăta cam aşa:

2.3.9 Crearea unei relaţii de tipul unu-la-unu

Un alt tip de relaţie este relaţia unu-la-unu. De exemplu, să presupunem că trebuie înregistrate câteva

informaţii speciale despre produse suplimentare, de care veţi avea nevoie rar sau care se aplică numai

câtorva produse. Deoarece veţi avea nevoie rar de aceste informaţii şi stocarea informaţiilor în tabelul

Page 25 of 101

Page 26: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

Produse ar produce spaţii libere pentru fiecare produs la care acestea nu se aplică, amplasaţi-le într-un

tabel separat. Ca şi tabelul Produse, ID produs se utilizează cu rolul de cheie primară. Relaţia dintre acest

tabel suplimentar şi tabelul Produs este o relaţie de tipul unu-la-unu. Pentru fiecare înregistrare din tabelul

Produs, există o singură înregistrare care se potriveşte în tabelul suplimentar. Când identificaţi o astfel de

relaţie, ambele tabele trebuie să partajeze un câmp comun.

Când observaţi necesitatea unei relaţii unu-la-unu în baza de date, gândiţi-vă dacă se pot pune informaţiile

din cele două tabele împreună într-un singur tabel. Dacă, dintr-un anumit motiv, nu doriţi să faceţi acest

lucru, poate pentru că ar rezulta multe spaţii libere, lista următoare vă arată cum se reprezintă relaţia în

proiectare:

Dacă cele două tabele au acelaşi subiect, probabil se poate configura relaţia utilizând aceeaşi

cheie primară în ambele tabele.

Dacă cele două tabele au subiecte diferite, cu chei primare diferite, alegeţi unul din tabele (oricare)

şi inseraţi cheia sa primară în celălalt tabel pe post de cheie externă.

Determinarea relaţiilor dintre tabele vă ajută să vă asiguraţi că aveţi tabelele şi coloanele corecte. Când

există o relaţie unu-la-unu sau unu-la-mai-mulţi, tabelele implicate trebuie să partajeze o coloană sau mai

multe coloane comune. Când există o relaţie mai-mulţi-la-mai-mulţi, este necesar un al treilea tabel pentru a

reprezenta relaţia.

2.3.10 Rafinarea proiectării

Din momentul în care aveţi tabelele, câmpurile şi relaţiile de care aveţi nevoie, trebuie să creaţi şi să

populaţi tabelele cu date eşantion şi să încercaţi să lucraţi cu informaţiile: creând interogări, adăugând

înregistrări noi şi aşa mai departe. Acest lucru ajută la evidenţierea problemelor potenţiale — de exemplu,

este posibil să aveţi nevoie să adăugaţi o coloană pe care aţi uitat să o inseraţi în timpul fazei de proiectare,

sau este posibil să aveţi un tabel care să trebuiască separat în două tabele pentru a elimina duplicarea.

Vedeţi dacă se poate utiliza baza de date pentru a obţine răspunsurile dorite. Creaţi schiţe neprelucrate ale

formularelor şi rapoartelor, şi vedeţi dacă vă arată datele pe care le aşteptaţi. Căutaţi dubluri inutile de date

şi, dacă le găsiţi, modificaţi proiectarea pentru a le elimina.

Pe măsură ce testaţi baza de date iniţială, probabil veţi descoperi că se pot face îmbunătăţiri. Câteva lucruri

care trebuie verificate:

Page 26 of 101

Page 27: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

Aţi uitat vreo coloană? Dacă da, apar informaţiile în tabelele existente? Dacă informaţiile sunt

despre altceva, este posibil să fie nevoie să creaţi un alt tabel. Creaţi o coloană pentru fiecare

element informaţional care trebuie urmărit. Dacă informaţiile nu se poate calcula de pe o altă

coloană, probabil aveţi nevoie de o coloană nouă pentru asta.

Sunt inutile unele coloane, pentru că se pot calcula din câmpuri deja existente? Dacă un element

informaţional se poate calcula dintr-o altă coloana deja existentă — ca, de exemplu, preţul redus

calculat din preţul de vânzare — este mai bine, în general, să se procedeze aşa şi să se evite

crearea unei coloane noi.

Introduceţi în mod repetat informaţii dublate în unul din tabele? Dacă da, probabil că trebuie

împărţit tabelul în două tabele între care să existe o relaţie de tipul unu-la-mai-mulţi.

Aveţi tabele cu multe câmpuri, un număr limitat de înregistrări şi multe câmpuri goale în

înregistrările individuale? Dacă da, gândiţi-vă la reproiectarea tabelului astfel încât să aibă mai

puţine câmpuri şi mai multe înregistrări.

A fost împărţit fiecare element informaţional în cele mai mici părţi utile? Dacă trebuie efectuate

operaţii de raportare, sortare, căutare sau calculare pentru un element informaţional, puneţi acel

element în propria sa coloană.

Conţine fiecare coloană date despre subiectul tabelului? Dacă o coloană nu conţine informaţii

despre subiectul tabelului, aceasta aparţine unui alt tabel.

Sunt toate relaţiile dintre tabele reprezentate prin câmpuri comune sau printr-un al treilea tabel?

Relaţiile unu-la-unu şi unu-la-mai-mulţi necesită coloane comune. Relaţiile mai-mulţi-la-mai-mulţi

necesită un al treilea tabel.

2.3.11 Rafinarea tabelului Produse

Să presupunem că fiecare produs din baza de date vânzări intră într-o categorie generală, cum ar fi băuturi,

condimente, sau fructe de mare. Tabelul Produse poate conţine un câmp care arată categoria fiecărui

produs.

Să presupunem că, după examinarea şi redefinirea proiectului bazei de date, decideţi să stocaţi o descriere

a categoriei alături de numele acesteia. Dacă adăugaţi un câmp Descriere categorie la tabelul Produse,

trebuie repetată descrierea fiecărei categorii pentru fiecare produs care intră in acea categorie — iar

aceasta nu este o soluţie bună.

O soluţie mai bună ar fi să faceţi Categorii un subiect nou de urmărit pentru baza de date, cu propriul tabel

şi propria cheie primară. Se poate adăuga cheia primară de la tabelul Categorii la tabelul Produse, cu rol de

cheie externă.

Page 27 of 101

Page 28: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

Între tabelele Categorii şi Produse există o relaţie unu-la-mai-mulţi: o categorie poate include mai mult de

un produs, dar un produs poate aparţine numai unei categorii.

Când revizualizaţi structurile tabelului, căutaţi grupuri repetitive. De exemplu, luaţi în considerare un tabel

care conţine următoarele coloane:

ID produs

Nume

ID produs1

Nume1

ID produs2

Nume2

ID produs3

Nume3

În acest caz, fiecare produs este un grup repetitiv de coloane, care diferă numai prin adăugarea unui număr

la sfârşitul numelui coloanei. Când vedeţi coloanele numerotate astfel, ar trebui să reanalizaţi proiectarea.

Un astfel de proiect are mai multe defecte. Pentru început, vă obligă să stabiliţi o limită superioară pentru

numărul produselor. După ce se depăşeşte această limită, trebuie adăugat un grup de coloane nou la

structura tabelului, ceea ce reprezintă o activitate administrativă majoră.

O altă problemă este faptul că furnizorii care au mai puţin decât numărul maxim de produse vor irosi spaţiu,

din moment ce coloanele suplimentare vor fi goale. Cel mai serios defect al unui astfel de proiect este faptul

că efectuarea multor activităţi, cum ar fi sortarea sau indexarea unui tabel după ID-urile sau numele

produselor, devine dificilă.

Oricând vedeţi un grup repetitiv, reanalizaţi cu atenţie proiectarea, în ideea de a împărţi tabelul în două. În

exemplul de mai sus, este mai bine să utilizaţi două tabele, unul pentru furnizori şi unul pentru produse,

legate prin ID furnizor.

2.3.12 Aplicarea regulilor de normalizare

Regulile de normalizare a datelor (denumite uneori reguli de normalizare) pot fi aplicate ca un pas din

cadrul proiectării. Aceste reguli se utilizează pentru a verifica dacă tabelele sunt structurate corect. Procesul

aplicării regulilor la proiectarea bazei de date este denumit normalizarea bazei de date, sau doar

normalizare.

Page 28 of 101

Page 29: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

Normalizarea este foarte utilă dacă aţi determinat toate elementele informaţionale şi aţi creat un proiect

preliminar. Scopul este să vă asiguraţi că aţi împărţit elementele informaţionale în tabelele

corespunzătoare. Normalizarea nu vă poate ajuta să vă asiguraţi că aveţi de la început toate elementele de

date corecte.

Regulile se aplică succesiv, asigurându-vă la fiecare pas că proiectul va ajunge la ceea ce se numeşte o

"formă normală." În principiu, sunt acceptate cinci forme normale — de la prima formă normală până la a

cincea. Acest articol le acoperă pe primele trei, deoarece acestea sunt necesare pentru majoritatea

proiectelor de baze de date.

2.3.12.1 Prima formă normală

Prima formă normală presupune că există o singură valoare la fiecare intersecţie dintre un rând şi o

coloană din tabel, şi niciodată o listă de valori. De exemplu, nu poate exista un câmp denumit Preţ în care

să plasaţi mai multe preţuri. Dacă priviţi intersecţia dintre un rând şi o coloană ca pe o celulă, atunci fiecare

celulă poate conţine o singură valoare.

2.3.12.2 A doua formă normală

A doua formă normală necesită ca fiecare coloană care nu este cheie să depindă complet de cheia primară,

nu doar de o parte a cheii. Această regulă se aplică când se utilizează o cheie primară care conţine mai

multe coloane. De exemplu, să presupunem că aveţi un tabel care conţine următoarele coloane, dintre care

ID comandă şi ID produs alcătuiesc cheia primară:

ID comandă (cheie primară)

ID produs (cheie primară)

Nume produs

Acest proiect încalcă a doua formă normală, deoarece Nume produs depinde de ID produs, dar nu şi de ID

comandă, aşadar nu depinde de întreaga cheie primară. Nume produs trebuie eliminat din tabel. Aparţine

de alt tabel (Produse).

2.3.12.3 A treia formă normală

A treia formă normală necesită ca fiecare coloană care nu este cheie să depindă de întreaga cheie primară,

dar şi ca toate coloanele care nu sunt chei să fie reciproc independente.

Page 29 of 101

Page 30: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

Un alt mod de a spune aste este că fiecare coloană care nu este cheie trebuie să depindă de întreaga

cheie primară şi numai de cheia primară. De exemplu, să presupunem că aveţi un tabel care conţine

următoarele coloane:

ID produs (cheie primară)

Nume

PSV

Reducere

Să presupunem că Reducere depinde de preţul sugerat de vânzare (PSV). Acest tabel încalcă a treia formă

normală, deoarece o coloană care nu este cheie, Reducere, depinde de altă coloană care nu este cheie,

PSV. Independenţa coloanelor înseamnă că se poate modifica orice coloană care nu este cheie fără a

afecta alte coloane. Dacă se modifică o valoare din câmpul PSV, se modifică în mod corespunzător

Reducere, aşadar încălcându-se regula. În acest caz, Reducere trebuie mutat în alt tabel pentru care PSV

este cheie.

In acest capitol am învăţat despre modul de proiectare a unei baze de date: cum împărţim informaţiile în

tabele, definirea relaţiilor între tabele, reguli de normalizare a bazei de date.

In continuare trecem efectiv la crearea unei baze de date aplicând aceste reguli de proiectare. Baza de

date va conţine informaţiile primare despre studenţii unei facultăţi, necesare în realizarea rapoartelor despre

situaţia la învăţătură a studentilor.

Page 30 of 101

Page 31: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

3 Structura organizatorică a facultăţii. Crearea bazei "stud"

3.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;

Atentie: ş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 in 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.

3.2 Structura organizatorică a facultăţii

Să spunem câteva cuvinte despre structura organizatorică a facultăţii noastre :

Anul universitar î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.

Page 31 of 101

Page 32: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

La începutul fiecarui an universitar studenţii se înscriu la facultate, fiind repartizaţi într-o

grupă de studiu.

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 dint-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.

3.3 Structura tabelelor

Conform observaţiilor de mai sus, ar rezulta următoarea structură de tabele necesară pentru stocarea

informaţiilor specifice activităţii didactice :

Tabela "ani_universitari": ţine evidenţa anilor şcolari: 2011-2012, 2012-2013,...;

Tabela "specializări": include denumirea specializărilor pe facultate;

Tabela "ani_studiu": conţine anii de studiu din facultate: anul 1, anul 2, 3,...;

Tabela "grupe": memorează denumirea grupelor de studiu

Tabela "studenti": conţine toţi studenţii care trec prin facultate

Tabela "studenti_grupe" este tabela de legatura între studenţi şi grupe. Nu se poate trece

direct numărul grupei la fiecare student pentru ca acel student trece prin mai multe grupe

de studiu în decursul anilor, deci un student are ataşate mai multe grupe, aşa cum o grupă

are ataşaţi mai mulţi studenţi. Este o legatură de tip "mai-multi-la-mai-multi" ce se rezolvă

prin această tabelă suplimentară.

Tabela "discipline": când se introduce o disciplină în tabelă trebuie specificat anul de studiu

şi specializarea la care se studiază acea disciplină, precum si semestrul de studiu (1 sau

2).

Tabela "note" conţine catalogul în care vor fi trecute notele la diverse testări şi examene

finale ale studenţilor. Fiecare notă trecută în catalog trebuie să aparţină unui student

(pk_student) şi unei discipline (pk_disciplina).

In figura de mai jos sunt date tabelele bazei de date, la fiecare tabelă precizându-se numele şi tipurile

coloanelor incluse.

Page 32 of 101

Page 33: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

Tabelele bazei de lucru

Structura tabelelor reflectă în fapt structura organizatorică a facultăţii. In acelaşi timp, trebuie avut în vedere

şi eventualele rapoarte pe care trebuie să le furnizăm despre procesul didactic din facultate. O listă

minimală a acestor rapoarte trebuie să includă următoarele situaţii:

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 face parte

Studenţii care repetă un anumit an de studiu

Etc

3.3.1 Analiza tabelelor din baza de date

In principiu, majoritatea tabelelor trebuie să conţină o serie de trei coloane relativ obligatorii:

Page 33 of 101

Page 34: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

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.

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.

Coloana pentru descrierea informaţiei din rând, are prefixul "descriere_", şi conţine un text

descriptiv despre linia respectivă.

Aceste trei coloane se vor întâlni în toate tabelele create de noi în baza de date având semnificaţiile

descrise mai sus.

In continuare prezentăm arhitectura fiecărui tabel cu discuţiile aferente:

1. Tabela "ani_universitari": este tabela ce stochează anii universitari parcurşi din momentul creării

bazei de date. Este o tabelă independentă de celelalte date din bază (tabela parinte), nu depinde

de nici o alta tabela, reprezintă pur şi simplu o inşiruire de ani universitari. Include următoarele

coloane:

Pk_an_universitar: (ex: 1,2,3, ...)un numar unic ce identifică fiecare an universitar în parte

Cod_an_universitar: (ex: "2011/2012", "2012/2013", ...) un text ce descrie simplu un an

universitar

Descriere_an_universitar: (ex: "An universitar 2011/2012")

2. Tabela "specializari": este tabela ce conţine specializările din facultate. De asemenea este o

tabela independentă, structura specializărilor nu depinde de studenţi sau grupe, ci este data de

profilul facultăţii.

Include următoarele coloane:

Pk_specializare: (ex: 1,2,3, ...) un număr unic ce identifică fiecare specializare în parte

Cod_specializare: (ex: "IAD", "IA", ...) un text ce descrie simplu specializarea

Descriere_specializare: (ex: "Instrumentatie si Achizitii de Date"), reprezintă denumirea

completă a specializarii

3. Tabela "ani_studiu": este tabela ce conţine anii de studiu pe care îi parcurge un student în

decursul facultăţii.

Include următoarele coloane:

Pk_an_studiu: (ex: 1,2,3, ...) un număr unic ce identifică fiecare an în parte

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

Page 34 of 101

Page 35: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

4. Tabela "discipline": este tabela ce conţine disciplinele studiate în facultate. Nu mai este o tabela

independentă, ci una copil, aceasta tabela depinzând de anii de studiu şi de specializările din

facultate.

Include următoarele coloane:

Pk_disciplina: (ex: 1,2,3, ...) un număr unic ce identifică fiecare disciplină în parte

Cod_disciplina: (ex: "BD", "ME", ...) un text ce descrie simplu disciplina

Descriere_specializare: (ex: "Instrumentatie si Achizitii de Date"), reprezintă denumirea

completă a specializării

Pk_specializare: este specializarea la care se predă această disciplină. Curicula nu este

aceeaşi pentru toate specializările, ci fiecare specializare are ataşate discipline proprii

Pk_an_studiu: specifică anul de studiu la care se predă disciplina

Semestru: (ex:1,2), semestrul de studiu

5. Tabela "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:

Pk_grupa: (ex: 1,2,3, ...) un număr unic ce identifică fiecare grupă în parte

Cod_grupa: (ex: "6102", "6301", ...)

Descriere_grupa: (ex: "Grupa 6301")

Pk_specializare: specializarea la care aparţine grupa

Pk_an_studiu: specifică anul de studiu pentru grupa respectivă

6. Tabela "studenti": este tabela cu toti studenţii din facultate, conţine informaţiile statice ale unui

student.

Include următoarele coloane:

Pk_student: (ex: 1,2,3, ...) un număr unic ce identifică fiecare student în parte

Nume_student

Prenume_student

Nr_matricol

Adresa

7. Tabela "studenti_grupe": reprezintă legatura între tabela studenţi şi tabela grupe. Un student

parcurge mai multe grupe în decursul facultăţii, aşa cum o grupă are mai multi studenţi. Deci nu se

poate face legatura directă între cele două tabele, ci prin intermediul unei a treia tabele care să

specifice clar în fiecare an universitar componenţa grupelor.

Include următoarele coloane:

Pk_student: este pk-ul studentului curent

Page 35 of 101

Page 36: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

Pk_grupa: pk-ul grupei din care face parte studentul

Pk_an_universitar: pk-ul anului universitar pentru care studentul a aparţinut grupei

respective.

Medie: media studentului din anul respectiv

Nr_credite: numărul de credite obţinute de student

8. Tabela "Note": ţine evidenţa notelor obţinute de studenţi în timpul examinărilor. Este legată de

tabela "studenti" – orice notă este asignată în mod unic unui student, şi tabela "discipline" – orice

notă este pusă la o anumită disciplină.

Include următoarele coloane:

Pk_nota: identificatorul unic al notei

Pk_student: studentul ce a primit nota respectivă

Pk_disciplina: la ce disciplina a luat nota studentul

Nota: un număr cuprins între 1 şi 10 reprezentând nota luată de student

Data: data examinării, de tipul "date"

3.4 Rafinarea bazei de date

Chiar dacă baza de date este relativ simplă, totuşi se impun anumite discuţii referitoare la proiectarea bazei

de date:

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 unui tabel de legătură între studenţi şi grupe.

Relaţia discipline-specializări: există posibilitatea ca o disciplină mai generală să se predea la mai

multe specializări. Soluţia în acest caz o reprezintă o noua tabelă de legatură între discipline şi

specializări care să includă şi anul universitar curent. Este posibil ca o disciplină să se reformuleze

la un moment dat, nu se mai cheamă "BD" ci "BDR" (baze de date relationale) ş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

Page 36 of 101

Page 37: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

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" decat un număr abstract. S-ar

vedea de la prima vedere la ce specializare este ataşată această grupă, faără să mai merg prin

tabela specializări. Dar, aşa cum am discutat la punctul anterior, pot adauga 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.

Acceaş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.

3.5 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.

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)

Page 37 of 101

Page 38: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

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;

3.6 Tipuri de date definite în baza de date

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 coloana poatet 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:

Page 38 of 101

Page 39: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

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 cand 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 39 of 101

Page 40: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

4 Constrângeri

4.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 care 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ă.

Dar cum ştim să introducem valori în acea coloană? 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 numar 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.

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);

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 ;

4.2 Constrângeri de unicitate (UK)

Page 40 of 101

Page 41: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

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;

Daca 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 studenti_uk unique(pk_stud, nume_stud) enable novalidate;

OBSERVATIE: novalidate merge numai daca s-a creat un index pe acele coloane:

create index ind_studenti on studenti(pk_stud, nume_stud);

Alte comenzi utile:

Stergerea index: drop index ind_studenti;

Stergere constrângere: alter table studenti drop constraint studenti_uk;

Enable/disable constrângere:

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 date în bază 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.

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

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ă.

Page 41 of 101

Page 42: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

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_stud varchar2(50) not null);

4.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 studenti_grupe 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';

4.5 Constrângeri de tip "check"

Mai există o posibilitate de limitare a surselor de eroare: constrângerile generale de tip "check". De

exemplu, nu putem introduce note în afara intervalului [1-10]:

Alter table note add constraint ck_nota CHECK (nota between 1 and 10);

4.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:

- pk_an_universitar (pk_an_universitar)

2. Ani_studiu:

- pk_an_studiu (cod_an_studiu)

3. Specializari:

- Pk_specializari (cod_specializare)

Page 42 of 101

Page 43: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

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 43 of 101

Page 44: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

5 Introducerea datelor în tabele

5.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 scolar 2007-2008' ).

Aceeaşi comandă poate fi dată şi prin sintaxa:

insert into ani_scolari values (4,'an scolar 2007-2008');

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.

5.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"

Page 44 of 101

Page 45: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

şi dă multe bătăi de cap programatorilor. Deoarece un singur NULL pus într-o relaţie sau într-o 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'.

5.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, sepecializă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 45 of 101

Page 46: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

6 Extragerea informaţiilor din baza de date

6.1 Comanda SELECT

Orice informaţie din bază trebuie la un moment dat extrasă şi vizualizată. In acest scop folosim comanda

SQL SELECT, comanda 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 studentiwhere 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 46 of 101

Page 47: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

Document no. Version no.: 3.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.

6.1.1 Selectarea 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 ;

6.2 Selectarea informaţiilor din mai multe tabele simultan

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 legatura între studenti si 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 47 of 101

Page 48: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

Document no. Version no.: 3.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ă între cele două tabele astfel încât unei linii dintr-o tabelă să-i corespundă una sau

mai multe linii din cealaltă tabelă. 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 In 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 48 of 101

Page 49: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

Document no. Version no.: 3.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 ;

6.3 Afişarea liniilor ce nu respectă condiţia de legătură în comanda select

Să presupunem că este un student care nu este ataşat la nici o grupă, deci nu are nici o linie inserată în

tabela "studenti_grupe".

insert into studenti values(null,'Chirila', 'C-tin',null);

Nu atasez nici o 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ă.

In acest caz trebuie să utilizez operatorul (+):

select st.nume_student, st.prenume_student, stg.pk_grupa from studenti st, studenti_grupe stg where st.pk_student = stg.pk_student (+)

Page 49 of 101

Page 50: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

order by nume_student asc ;

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 ;

6.4 Clauza where. Operatori logici

6.4.1 Operatori 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

Page 50 of 101

Page 51: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

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 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 ;

6.4.2 Operatori 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"

Page 51 of 101

Page 52: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

"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 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 nici o 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 ;

Page 52 of 101

Page 53: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

Dacă uităm de paranteze, atunci obţinem sute de mii de linii cu informaţii eronate, deoarece pentru fiecare

nota 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":

6.4.3 Operatorul "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 ;

6.4.4 Operatorul "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 ;

6.4.5 Operatorul "like"

Page 53 of 101

Page 54: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

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%';

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%';

6.4.6 Clauza distinct

Sa 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 ;

Page 54 of 101

Page 55: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

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 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 ;

6.4.7 Operatorul "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 ce 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;

Page 55 of 101

Page 56: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

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

select * from studenti where nr_matricol is not null;

6.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

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_studentfrom studenti stwhere st.nr_matricol is nullorder 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_studentfrom studenti stwhere st.nr_matricol is nullorder 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_disciplinaorder by n.nota desc, st.nume_student;

Page 56 of 101

Page 57: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

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:

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 57 of 101

Page 58: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

7 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:

7.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,

m/,n/)

Intoarce n caractere din cadrul expresiei începînd cu pozitia m.

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

Page 58 of 101

Page 59: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

INSTR(expresie ,"sir") Caută şirul de caractere "sir" în expresie şi întoarce poziţia unde a

fost găsit.

Exemple:

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.

7.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:

Page 59 of 101

Page 60: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

select 3/2 from dual;

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".

7.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;

Page 60 of 101

Page 61: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

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

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

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

7.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.

7.4.1 Conversia 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

Page 61 of 101

Page 62: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

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

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;

7.4.2 Conversia 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,

Page 62 of 101

Page 63: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

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.

7.4.3 Conversia 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.

Page 63 of 101

Page 64: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

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).

7.4.4 Conversia textului in format numeric

funcţia to_number(sir_caractere, format):

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;

7.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".

Page 64 of 101

Page 65: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

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 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_disciplinaorder 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.

7.6 Funcţii de grup

Page 65 of 101

Page 66: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

7.6.1 Functii 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;

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):

Page 66 of 101

Page 67: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

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;

7.6.2 Clauza "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.notafrom discipline d, note nwhere n.pk_disciplina = d.pk_disciplinaorder 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 nwhere n.pk_disciplina = d.pk_disciplinaorder by d.cod_disciplina;

select d.cod_disciplina, round(avg(n.nota),2)from discipline d, note n

Page 67 of 101

Page 68: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

where n.pk_disciplina = d.pk_disciplinagroup by d.cod_disciplinaorder 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 nwhere n.pk_disciplina = d.pk_disciplinaand round(avg(n.nota),2) < 8 group by d.cod_disciplinaorder 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 nwhere n.pk_disciplina = d.pk_disciplinagroup by d.cod_disciplinahaving 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.

Page 68 of 101

Page 69: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

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 69 of 101

Page 70: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

8 Subinterogări

8.1 Constructia 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 nota î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.notafrom studenti st, studenti_grupe stg, note n, discipline d, ani_universitari aniwhere st.pk_student = stg.pk_studentand stg.pk_an_universitar = ani.pk_an_universitarand stg.pk_student_grupa = n.pk_student_grupaand n.pk_disciplina = d.pk_disciplinaand 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 selectul inferior greşim codul disciplinei, atunci tot selectul principal dă greş:

select st.nume_student, st.prenume_student, d.cod_disciplina, n.notafrom studenti st, studenti_grupe stg, note n, discipline d, ani_universitari aniwhere st.pk_student = stg.pk_studentand stg.pk_an_universitar = ani.pk_an_universitarand stg.pk_student_grupa = n.pk_student_grupaand n.pk_disciplina = d.pk_disciplinaand 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

Page 70 of 101

Page 71: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

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' );

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 aniwhere st.pk_student = stg.pk_studentand stg.pk_an_universitar = ani.pk_an_universitarand stg.pk_student_grupa = n.pk_student_grupaand ani.cod_an_universitar = '2011-2012'group by st.nume_student, st.prenume_studenthaving 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' );

8.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 aniwhere st.pk_student = stg.pk_studentand stg.pk_an_universitar = ani.pk_an_universitarand stg.pk_student_grupa = n.pk_student_grupaand n.pk_disciplina = d.pk_disciplina

Page 71 of 101

Page 72: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

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.

8.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_grupafrom studenti st, studenti_grupe stg,

(select g.pk_grupa , g.cod_grupa, round(avg(nota),2) medie_grupafrom grupe g, studenti_grupe stg, note nwhere g.pk_grupa = stg.pk_grupaand stg.pk_student_grupa = n.pk_student_grupagroup by g.pk_grupa, g.cod_grupa)medie_grupe,

(select st.pk_student, round(avg(nota),2) medie_studfrom studenti st, studenti_grupe stg, note nwhere st.pk_student = stg.pk_studentand stg.pk_student_grupa = n.pk_student_grupagroup by st.pk_student) medie_studenti

where st.pk_student = stg.pk_studentand stg.pk_grupa = medie_grupe.pk_grupaand st.pk_student = medie_studenti.pk_studentand medie_stud > medie_grupaorder by cod_grupa;

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.

Page 72 of 101

Page 73: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

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).

8.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 asselect g.pk_grupa , g.cod_grupa, round(avg(nota),2) medie_grupa, ani.pk_an_universitarfrom grupe g, studenti_grupe stg, note n, ani_universitari aniwhere g.pk_grupa = stg.pk_grupaand stg.pk_student_grupa = n.pk_student_grupaand stg.pk_an_universitar = ani.pk_an_universitargroup 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 asselect stg.pk_student_grupa, st.nume_student, st.prenume_student, g.cod_grupa, d.cod_disciplina, n.nota, ani.pk_an_universitar

Page 73 of 101

Page 74: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

from studenti st, studenti_grupe stg, grupe g, note n, discipline d, ani_universitari aniwhere st.pk_student = stg.pk_studentand stg.pk_an_universitar = ani.pk_an_universitarand stg.pk_grupa = g.pk_grupaand stg.pk_student_grupa = n.pk_student_grupaand 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 74 of 101

Page 75: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

9 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).

9.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 75 of 101

Page 76: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

Document no. Version no.: 3.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".

9.1.1 Folosirea 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);

9.1.2 Utilizarea 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_studentand stg.pk_an_universitar = ani.pk_an_universitarand 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 76 of 101

Page 77: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

9.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 dwhere st.pk_student = stg.pk_studentand stg.pk_student_grupa = n.pk_student_grupaand n.pk_disciplina = d.pk_disciplinaand 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".

9.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

Page 77 of 101

Page 78: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

from studenti st, studenti_grupe stg, note n, discipline dwhere st.pk_student = stg.pk_studentand stg.pk_student_grupa = n.pk_student_grupaand n.pk_disciplina = d.pk_disciplinaand 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.

9.3.1 Stergerea î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_grupeADD CONSTRAINT fk_student_grupe_st FOREIGN KEY (pk_student)REFERENCES studenti (pk_student)

Page 78 of 101

Page 79: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

Document no. Version no.: 3.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 79 of 101

Page 80: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

10 Tranzacţii în baza de date

10.1Comanda 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?

10.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.

Page 80 of 101

Page 81: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

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

î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.

10.2.1 Commit 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.

10.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;

Page 81 of 101

Page 82: Baze de Date Versiunea 4.0 Nov 2011

Baze de date Project no. BD 2011 Product name: Baze de date – note de curs Date: July - 2011

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

Apoi contăm factura. Dacă totul e OK dăm un COMMIT, altfel mă intorc la ultima situaţie de succes:

ROLLBACK to factura;

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 82 of 101

Page 83: Baze de Date Versiunea 4.0 Nov 2011

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 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.

11.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;

Page 83 of 101

Page 84: Baze de Date Versiunea 4.0 Nov 2011

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

RETURN return_value ; (numai pentru functii)

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.

11.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:

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

Page 84 of 101

Page 85: Baze de Date Versiunea 4.0 Nov 2011

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

select d.pk_disciplina, d.cod_disciplina, d.credite 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 = 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

Page 85 of 101

Page 86: Baze de Date Versiunea 4.0 Nov 2011

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

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.

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 stgwhere st.pk_student = stg.pk_student;

11.2.1 Medie student

CREATE OR REPLACE FUNCTION calcul_medie( p_pk_student_grupa in number) return number is

Page 86 of 101

Page 87: Baze de Date Versiunea 4.0 Nov 2011

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

cursor c_discipline_studiate is select d.pk_disciplina, d.cod_disciplina 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 = 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 number := 0;suma_note number := 0;nota_curenta number := 0;nr_note number := 0;

begindbms_output.put_line('*** pk_stud_grupa=' || p_pk_student_grupa); nr_note := 0; suma_note := 0; for rec in c_discipline_studiate loop nota_curenta := -1; open c_note(rec.pk_disciplina); fetch c_note into nota_curenta; if nota_curenta != -1 then nr_note := nr_note + 1;dbms_output.put_line(' nota_curenta =' || nota_curenta || ' nr_note=' ||nr_note); else nota_curenta := 0; end if; close c_note; suma_note := suma_note + nvl(nota_curenta,0); end loop; if nr_note > 0 thendbms_output.put_line(' suma_note = '||suma_note||' nr_note= '||nr_note); v_medie := suma_note/nr_note; else v_medie := 0; end if; return round(v_medie,2) ; exception when others then return 0;end;/

Page 87 of 101

Page 88: Baze de Date Versiunea 4.0 Nov 2011

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.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.

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.

11.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_grupeBEFORE INSERT ON studenti_grupeREFERENCING NEW AS NEW OLD AS OLD FOR EACH ROWbegin 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

Page 88 of 101

Page 89: Baze de Date Versiunea 4.0 Nov 2011

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

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).

11.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_notebefore insert or update on notereferencing new as new old as old for each rowbegindeclarecursor 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;

Page 89 of 101

Page 90: Baze de Date Versiunea 4.0 Nov 2011

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

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);

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 90 of 101

Page 91: Baze de Date Versiunea 4.0 Nov 2011

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 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 91 of 101

Page 92: Baze de Date Versiunea 4.0 Nov 2011

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

13 Anexe

13.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.

13.1.1 Creare tabele

--ani universitaridelete 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 studiudrop 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);

-- specializaridrop 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);

-- grupedrop table grupe;

Page 92 of 101

Page 93: Baze de Date Versiunea 4.0 Nov 2011

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) ;

--studentidrop 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_grupedrop 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 93 of 101

Page 94: Baze de Date Versiunea 4.0 Nov 2011

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));

--notedrop 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 94 of 101

Page 95: Baze de Date Versiunea 4.0 Nov 2011

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_universitariBEFORE INSERT ON ani_universitari REFERENCING NEW AS NEW OLD AS OLD FOR EACH ROWbegin select pk_an_universitar.NEXTVAL into :new.pk_an_universitar from dual;end;/

CREATE OR REPLACE TRIGGER bef_ani_studiuBEFORE INSERT ON ani_studiu REFERENCING NEW AS NEW OLD AS OLD FOR EACH ROWbegin select pk_an_studiu.NEXTVAL into :new.pk_an_studiu from dual;end;/

CREATE OR REPLACE TRIGGER bef_specializariBEFORE INSERT ON specializari REFERENCING NEW AS NEW OLD AS OLD FOR EACH ROWbegin select pk_specializare.NEXTVAL into :new.pk_specializare from dual;end;/

CREATE OR REPLACE TRIGGER bef_grupeBEFORE INSERT ON grupe REFERENCING NEW AS NEW OLD AS OLD FOR EACH ROWbegin select pk_grupa.NEXTVAL into :new.pk_grupa from dual;end;/

CREATE OR REPLACE TRIGGER bef_studentiBEFORE INSERT ON studenti REFERENCING NEW AS NEW OLD AS OLD FOR EACH ROWbegin select pk_student.NEXTVAL into :new.pk_student from dual;end;/

CREATE OR REPLACE TRIGGER bef_studenti_grupeBEFORE INSERT ON studenti_grupe REFERENCING NEW AS NEW OLD AS OLD FOR EACH ROWbegin select pk_student_grupa.NEXTVAL into :new.pk_student_grupa from dual;end;/

CREATE OR REPLACE TRIGGER bef_disciplineBEFORE INSERT ON discipline REFERENCING NEW AS NEW OLD AS OLD FOR EACH ROWbegin select pk_disciplina.NEXTVAL into :new.pk_disciplina from dual;end;/

Page 95 of 101

Page 96: Baze de Date Versiunea 4.0 Nov 2011

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_noteBEFORE INSERT ON note REFERENCING NEW AS NEW OLD AS OLD FOR EACH ROWbegin select pk_nota.NEXTVAL into :new.pk_nota from dual;end;/

13.1.2 Introducerea date în bază

select * from ani_universitari;--1. ani_universitaridelete 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. specializariinsert 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. disciplineinsert 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. grupeinsert into grupe values(null,'6403','Grupa 6403',1,4);

Page 96 of 101

Page 97: Baze de Date Versiunea 4.0 Nov 2011

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 tabeladelete 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 grupedelete 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 97 of 101

Page 98: Baze de Date Versiunea 4.0 Nov 2011

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 trecutinsert 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 6404delete 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 98 of 101

Page 99: Baze de Date Versiunea 4.0 Nov 2011

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 6403insert 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 6401insert 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 6303insert 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 99 of 101

Page 100: Baze de Date Versiunea 4.0 Nov 2011

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

13.2 Fraze select în baza de date

13.2.1 Studenti-grupe-discipline-noteselect 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_disciplinaorder by au.cod_an_universitar, g.cod_grupa,st.nume_student;

Page 100 of 101

Page 101: Baze de Date Versiunea 4.0 Nov 2011

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

13.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.dmpdrop user pavel cascade;create user pavel identified by pavel;grant dba to pavel;

Page 101 of 101