Baze de Date Versiunea 4.0 Nov 2011
-
Upload
mihaila-petronel -
Category
Documents
-
view
222 -
download
7
description
Transcript of Baze de Date Versiunea 4.0 Nov 2011
Baze de date
Note de curs
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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