Sunteți pe pagina 1din 410

1.

GENERALITĂŢI DESPRE BAZE DE DATE


1.1. Introducere
Baza de date este un ansamblu structurat de date coerente, fără
redondanţă inutilă, astfel încât acestea pot fi prelucrate eficient de mai
mulţi utilizatori într-un mod concurent.
Baza de date este o colecţie de date persistente, care sunt folosite de
către sistemele de aplicaţii ale unei anumite „întreprinderi“. Datele din baza
de date persistă deoarece, după ce au fost acceptate de către sistemul de
gestiune pentru introducerea în baza de date, ele pot fi şterse din bază
numai printr-o cerere explicită adresată sistemului de gestiune.
Aici, termenul de „întreprindere“ este un cuvânt generic, utilizat
pentru a desemna orice organizaţie independentă, de natură tehnică,
comercială, ştiinţifică sau de alt tip. Întreprinderea poate fi, de exemplu, un
spital, o bancă, o facultate, o fabrică, un aeroport etc. Fiecare întreprindere
are regulile proprii de funcţionare şi conţine o mulţime de date
referitoare la modul său de operare.
Datele din baza de date pot fi atît integrate, cât şi partajate.
Noţiunea de integrat se referă la faptul că baza de date poate fi considerată
ca o unificare a mai multor fişiere, iar prin partajare se înţelege că baza de
date poate fi partajată concurent între diferiţi utilizatori.
Un sistem de gestiune a bazelor de date (SGBD – Data Base
Management System) este un produs software care asigură interacţiunea cu
o bază de date, permiţând definirea, consultarea şi actualizarea datelor din
baza de date. Toate cererile de acces la baza de date sunt tratate şi
controlate de către SGBD. Organizarea datelor în baze de date constituie o
formă de centralizare a acestora. Aceasta implică existenţa unui
administrator al bazei de date (DBA – Data Base Administrator)
care este o persoană sau un grup de persoane ce răspund de ansamblul
activităţilor (analiză, proiectare, implementare, exploatare, întreţinere etc.)
legate de baza de date. Atribuţiile unui administrator pot fi grupate în patru
mari categorii: atribuţii de proiectare, atribuţii administrative, atribuţii
operative şi atribuţii de coordonare.

Concepte ale bazelor de date relaţionale

În această parte se face o prezentare generală a conceptelor bazelor


de date relaţionale.
O bază de date relațională este o colecţie de informaţii
interrelaţionate gestionate ca o singură unitate.
2
A ceastă definiţie este foarte largă, deoarece există mari diferenţe
între concepţiile diferiţilor producători care pun la dispoziţie sisteme de
baze de date. De exemplu, Oracle Corporation defineşte o bază de date ca
fiind o colecţie de fişiere fizice gestionate de o singură instanţă (copie) a
produsului software pentru baze de date, în timp ce Microsoft defineşte o
bază de date SQL Server ca fiind o colecţie de date şi alte obiecte.
Un obiect al bazei de date este o structură de date denumită, stocată
în bază de date, cum ar fi un tabel, o vizualizare sau un index.
Există mari diferenţe între implementările furnizorilor de baze de
date. În majoritatea sistemelor de baze de date, datele sunt stocate în mai
multe fişiere fizice, dar în Microsoft Access toate obiectele bazei de date,
împreună cu datele care aparţin unei baze de date sunt stocate într-un
singur fişier fizic.(Un fişier este o colecţie de înregistrări înrudite stocate ca
o singură untiate de sistemul de operare al calculatorului.) Totuşi, unul
dintre principalele avantaje ale bazelor de date relaţionale este faptul că
detaliile de implementare fizică sunt separate de definiţiile logice ale
obiectelor bazei de date, astfel încât majoritatea utilizatorilor bazei de date
nu au nevoie să ştie unde (şi cum) sunt stocate obiectele bazei de date în
sistemul de fişiere al calculatorului.

Sistem de gestionare a bazei de date (DBMS sau SGBD)

Un sistem de gestionare a bazei de date (DBMS database


management system) este un produs software furnizat de producătorul
bazei de date. Produse software precum Microsoft Access, Microsoft SQL
Server, Oracle Database,Sybase, DB2,INGRES, MySQL şi Postgre SQL
fac parte din categoria DBMS sau, mai corect, DBMS relaţionale
(RDBMS).
RDBMS-urile sunt cunoscute şi sub numele de SGBD-uri. Ambele
prescurtări vor fi folosite în acestă expunere.
Sistemul DBMS pune la dispoziţie toate serviciile de bază necesare
pentru organizarea şi întreţinerea bazei de date, inclusiv următoarele:
- Transferarea datelor în şi din fişierele fizice de date, în funcţie de
cerinţe.
- Gestionarea accesului concurenţial la date al mai multor
utilizatori, inclusiv prevenirea conflictelor care ar putea fi
cauzate de actualizările simultane.
- Gestionarea tranzacţiilor, astfel încât toate modificările făcute
asupra bazei de date printr-o tranzacţie să fie executate ca o
singură unitate. Cu alte cuvinte, dacă tranzacţia reuşeşte, toate
3

modificările efectuate de tranzacţie sunt înregistrate în bază de


date; dacă tranzacţia eşuează, nici una dintre modificări nu este
înregistrată în bază de date.Totuşi, reţineţi ca unele sisteme
RDBMS nu asigură suportul pentru tranzacţii.
- Acceptă un limbaj de interogare, care reprezintă sistemul de
comenzi folosit de utilizator pentru a obţine date din bază de
date. SQL este principalul limbaj folosit pentru sistemele DBMS
relaţionale.
- Funcţii pentru salvarea bazei de date şi pentru refacerea bazei de
date în urma erorilor.
- Mecanisme de securitate pentru împiedicarea accesului neautorizat
la date şi modificarea acestora.

Ce este o bază de date relaţională ?

O bază de date relaţională este o bază de date care respectă modelul


relaţional, dezvoltat de Dr.E.F.Codd. Modelul relaţional prezintă datele sub
forma familiarelor tabele bidimensionale, similar cu o foaie de calcul
tabelar. Spre deosebire de o foaie de calcul tabelar, nu este obligatoriu ca
datele să fie stocate într-o formă tabelară, iar modelul permite şi
combinarea tabelelor (crearea uniunilor (joining), în terminologia
relaţională) pentru formarea vizualizarilor, care sunt prezentate tot ca tabele
bidimensionale. Flexibilitatea extraordinară a bazelor de date relaţionale
este dată de posibilitatea de a folosi tabelele independent sau în combinaţii,
fără nici o ierarhie sau secvenţă predefinită în care trebuie să se facă
accesul la date.

Dicţionarul datelor (catalog de sistem), structurat şi administrat


ca o bază de date (metabază de date), contine „date despre date“, furnizează
descrierea tuturor obiectelor unei baze de date, starea acestor obiecte,
diversele constrângeri de securitate şi de integritate etc. Dicţionarul poate fi
interogat, la fel, ca orice altă bază de date.
4
1.2. Gestiunea bazelor de date

Un sistem de baze de date presupune următoarele componente


principale, care definesc arhitectura acestuia:
• baza de date propriu-zisă în care se memorează datele;
• sistemul de gestiune a bazei de date, care realizează gestionarea şi
prelucrarea complexă a datelor;
• un dicţionar al bazei de date (metabaza de date), ce conţine
informaţii despre date, structura acestora, statistici, documentaţie;
• mijloace hardware (comune sau specializate);
• reglementări administrative destinate bunei funcţionări a
sistemului;
• personalul implicat (utilizatori finali, administratorul datelor,
administratorul bazei de date, proiectanţi, programatori de
aplicaţii).
Se pot identifica patru categorii de persoane implicate în mediul
bazelor de date:
• administratorii de date şi baze de date,
• proiectanţii (designeri) de baze de date,
• programatorii de aplicaţii,
• utilizatorii finali.
Administratorul de date (DA) este un manager, nu un tehnician, ce:
• decide care date trebuie stocate în baza de date;
• stabileşte regulile de întreţinere şi de tratare a acestor date după ce
sunt stocate. De exemplu, o regulă ar putea fi aceea prin care se
stabilesc pentru utilizatori privilegii asupra informaţiilor din baza
de date, cu alte cuvinte o anumită politică de securitate a datelor.
Administratorul bazei de date (DBA) este responsabil cu
implementarea deciziilor administratorului de date şi cu controlul general al
sistemului, la nivel tehnic. El este un profesionist în domeniul IT, care:
• creează baza de date reală;
• implementează elementele tehnice de control;
• este responsabil cu asigurarea funcţionării sistemului la
performanţe adecvate, cu monitorizarea performanţelor;
• furnizează diverse servicii tehnice etc.
Proiectanţii de baze de date pot acoperi atât aspectul fizic, cât şi cel
logic al concepţiei.
Proiectantul de baze de date care abordează direcţia logică trebuie să
posede o cunoaştere completă şi amănunţită a modelului real de proiectat şi
a regulilor de funcţionare ale acestuia. Practic, acesta proiectează
5

conceptual baza de date, iar modelul creat este independent de programele


de aplicaţii, de limbajele de programare. De asemenea, va proiecta logic
baza de date, proiectare care este îndreptată spre un anumit model de date
(relaţional, orientat obiect, ierarhic etc.).
Proiectantul de baze de date fizice preia modelul logic de date şi
stabileşte cum va fi realizat fizic. Acesta trebuie să cunoască
funcţionalităţile SGBD-ului, avantajele şi dezavantajele fiecărei alternative
corespunzătoare unei implementări. Practic, se face transpunerea modelului
logic într-un set de tabele supuse unor constrângeri, se selectează structuri
de stocare şi metode de acces specifice, astfel încât să se asigure
performanţe, se iau măsuri privind securitatea datelor.
Utilizatorii finali sunt cei care accesează interactiv baza de date.
Aceasta a fost proiectată, implementată, întreţinută pentru a satisface
necesităţile informaţionale ale clienţilor. Utilizatorii finali pot fi utilizatori
simpli, care nu cunosc nimic despre baza de date, despre SGBD, dar
accesează baza prin intermediul unor programe de aplicaţie. În general,
această clasă de utilizatori alege anumite opţiuni din meniul aplicaţiei.
Există utilizatori finali sofisticaţi, care sunt familiarizaţi cu structura bazei
de date. Ei pot utiliza limbaje speciale pentru a exploata posibilităţile
oferite de baza de date.
Programatori de aplicaţii sunt responsabili de scrierea programelor
aplicaţie ce conferă funcţionalitatea cerută de utilizatorii finali. Programele
pot fi scrise în diferite limbaje de programare (C++, PL/SQL, Java etc.).

Cerinţe minimale care se impun unei baze de date:


• asigurarea unei redundanţe minime în date;
• furnizarea în timp util a informaţiilor solicitate (timpul de răspuns
la o interogare);
• asigurarea unor costuri minime în prelucrarea şi întreţinerea
informaţiei;
• capacitatea de a satisface, cu aceleaşi date, necesităţi
informaţionale ale unui număr mare de utilizatori,
• posibilitatea de adaptare la cerinţe noi, răspunsuri la interogări
neprevăzute iniţial (flexibilitate);
• exploatarea simultană a datelor de către mai mulţi utilizatori
(sincronizare);
• asigurarea securităţii datelor prin mecanisme de protecţie împotriva
accesului neautorizat (confidenţialitate);
6
• înglobarea unor facilităţi destinate validării datelor şi recuperării
lor în cazul unor deteriorări accidentale, garantarea (atât cât este
posibil) că datele din baza de date sunt corecte (integritate);
• posibilitatea de valorificare a eforturilor anterioare şi anticiparea
nevoilor viitoare (compatibilitate şi expandabilitate);
• permisivitatea, prin ierarhizarea datelor după criteriul frecvenţei
acceselor, a unor reorganizări (eventual dinamice) care sporesc
performanţele bazei.
În cadrul unei baze de date putem vorbi de patru niveluri de
abstractizare şi de percepţie a datelor: intern, conceptual, logic şi
extern. Datele există doar la nivel fizic, iar celelalte trei niveluri reprezintă
virtualizări ale acestora.
• Nivelul fizic (intern) este descris de schema fizică a datelor (bit,
octet, adresă);
• Nivelul conceptual este descris de schema conceptuală a datelor
(articol, înregistrare, zonă) şi reprezintă viziunea programatorilor
de sistem asupra datelor;
• Nivelul logic este descris de una din schemele logice posibile ale
datelor şi reprezintă viziunea programatorului de aplicaţie asupra
datelor;
• Nivelul virtual (extern) reprezintă viziunea utilizatorului final
asupra datelor.
Independenţa datelor cuprinde două aspecte fundamentale: o
modificare a structurii fizice nu va afecta aplicaţia şi reciproc, modificări
ale aplicaţiei vor lăsa nealterată structura fizică de date.
• Independenţa fizică: posibilitatea modificării schemei fizice a
datelor fără ca aceasta să implice modificarea schemei conceptuale,
a schemei logice şi a programelor de aplicaţie. Este vorba despre
imunitatea programelor de aplicaţie faţă de modificările modului în
care datele sunt stocate fizic şi accesate.
• Independenţa logică: posibilitatea modificării schemei conceptuale
a datelor fără ca aceasta să implice modificarea schemei logice şi a
programelor de aplicaţie. Prin independenţa logică a datelor se
urmăreşte a se crea fiecărui utilizator iluzia că este singurul
beneficiar al unor date pe care, în realitate, le foloseşte în comun
cu alţi utilizatori.
Independenţă faţă de strategiile de acces permite programului să
precizeze data pe care doreşte să o acceseze, dar nu modul cum accesează
această dată. SGBD-ul va stabili drumul optim de acces la date.
7

În limbajele de programare uzuale declaraţiile şi instrucţiunile


executabile aparţin aceluiaşi limbaj. În lumea bazelor de date, funcţiile de
declarare şi de prelucrare a datelor sunt realizate cu ajutorul unor limbaje
diferite, numite limbaje pentru baze de date.
• Limbaje pentru definirea datelor (DDL – Data Description
Language). Descrierea concretă a unui DDL este specifică fiecărui
sistem de gestiune, dar funcţiile principale sunt aceleaşi. La nivel
conceptual, DDL realizează definirea entităţilor şi a atributelor
acestora, sunt precizate relaţiile dintre date şi strategiile de acces la
ele, sunt stabilite criterii diferenţiate de confidenţialitate şi de
validare automată a datelor utilizate.
• Limbaje pentru prelucrarea datelor (DML – Data Manipulation
Language). Operaţiile executate în cadrul unei baze de date
presupun existenţa unui limbaj specializat, în care comenzile se
exprimă prin fraze ce descriu acţiuni asupra bazei. În general, o
comandă are următoarea structură: operaţia (calcul aritmetic sau
logic, editare, extragere, deschidere-închidere, adăugare, ştergere,
căutare, reactualizare etc.), criterii de selecţie, mod de acces
(secvenţial, indexat etc.), format de editare. Există limbaje DML
procedurale, care specifică cum se obţine rezultatul unei comenzi
DML şi limbaje neprocedurale, care descriu doar datele ce vor fi
obţinute şi nu modalitatea de obţinere a acestora.
• Limbaje pentru controlul datelor (DCL – Data Control Language).
Controlul unei baze de date se referă la asigurarea confidenţialităţii
şi integrităţii datelor, la salvarea informaţiei în cazul unor
defecţiuni, la obţinerea unor performanţe, la rezolvarea unor
probleme de concurenţă.

Limbajele universale nu se utilizează frecvent pentru gestionarea


unei baze de date, dar există această posibilitate. De exemplu, sistemul
Oracle este dotat cu precompilatoare (C, Pascal, ADA, Cobol, PL/1,
Fortran) care ajută la incorporarea de instrucţiuni SQL sau blocuri PL/SQL
în programe scrise în alte limbaje, de nivel înalt, numite limbaje gazdă.
Sistemul de gestiune a bazelor de date interacţionează cu programele
de aplicaţie ale utilizatorului şi cu baza de date, oferind o mulţime de
facilităţi. Realizarea optimă a acestor facilităţi este asigurată de
obiectivele fundamentale ale unui sistem de gestiune. Câteva dintre
aceste obiective vor fi enumerate în continuare.
• Independenţa fizică. Obiectivul esenţial este acela de a permite
realizarea independenţei structurilor de stocare în raport cu
8
structurile de date din lumea reală. Se defineşte mulţimea de date
indiferent de forma acesteia din lumea reală, ţinând seama doar de
a realiza un acces simplu la date şi de a obţine anumite
performanţe.
• Independenţa logică. Grupul de lucru care exploatează baza de date
poate să utilizeze diferite informaţii de bază (nu aceleaşi), pentru a-
şi construi entităţi şi relaţii. Fiecare grup de lucru poate să
cunoască doar o parte a semanticii datelor, să vadă doar o
submulţime a datelor şi numai sub forma în care le doreşte.
Această independenţă asigură imunitatea schemelor externe faţă de
modificările făcute în schema conceptuală.
• Prelucrarea datelor de către neinformaticieni. Neinformaticienii
văd datele independent de implementarea lor şi pot exploata aceste
date prin intermediul unui sistem de meniuri oferit de aplicaţia pe
care o exploatează.
• Administrarea centralizată a datelor. Administrarea datelor
presupune definirea structurii datelor şi a modului de stocare a
acestora. Administrarea este în general centralizată şi permite o
organizare coerentă şi eficace a informaţiei.
• Coerenţa datelor. Informaţia trebuie să satisfacă constrângeri
statice sau dinamice, locale sau generale.
• Neredundanţa datelor. Fiecare aplicaţie posedă datele sale proprii
şi aceasta conduce la numeroase dubluri. De asemenea,
organizarea nejudicioasă a relaţiilor poate să genereze redundanţă
în date. Administrarea coerentă a datelor trebuie să asigure
neduplicarea fizică a datelor. Totuşi, nu sunt excluse nici cazurile
în care, pentru a realiza performanţe referitoare la timpul de acces
la date şi răspuns la solicitările utilizatorilor, să se accepte o
anumită redundanţă a datelor.
• Partajabilitatea datelor. Aceasta permite ca aplicaţiile să partajeze
datele din baza de date în timp şi simultan. O aplicaţie poate folosi
date ca şi cum ar fi singura care le utilizează, fără a şti că altă
aplicaţie, concurent, le poate modifica.
• Securitatea şi confidenţialitatea datelor. Datele trebuie protejate de
un acces neautorizat sau rău intenţionat. Există mecanisme care
permit identificarea şi autentificarea utilizatorilor şi există
proceduri de acces autorizat care depind de date şi de utilizator.
Sistemul de gestiune trebuie să asigure securitatea fizică şi logică a
informaţiei şi să garanteze că numai utilizatorii autorizaţi pot
efectua operaţii corecte asupra bazei de date.
9

Sistemele de gestiune a bazelor de date au, din nefericire, şi


dezavantaje dintre care se remarcă:
• complexitatea şi dimensiunea sistemelor pot să crească
considerabil, datorită necesităţii extinderii funcţionalităţilor
sistemului;
• costul, care variază în funcţie de mediu şi funcţionalitatea oferită,
la care se adugă cheltuieli periodice de întreţinere;
• costuri adiţionale pentru elemente de hardware;
• costul conversiei aplicaţiilor existente, necesară pentru ca acestea
să poată funcţiona în noua configuraţie hardware şi software;
• impactul unei defecţiuni asupra aplicaţiilor, bazei de date sau
sistemului de gestiune.

Structura unui sistem de gestiune a bazelor de date este de


complexitate variabilă, iar nivelul real de funcţionalitate diferă de la produs
la produs. În orice moment apar noi necesităţi, care cer o nouă
funcţionalitate, astfel încât aceasta nu va putea deveni niciodată statică. În
general, un SGBD trebuie să includă cel puţin cinci clase de module:
• programe de gestiune a bazei de date (PGBD), care realizează
accesul fizic la date ca urmare a unei comenzi;
• module pentru tratarea limbajului de definire a datelor, ce permit
traducerea unor informaţii (care realizează descrierea datelor, a
legăturilor logice dintre acestea şi a constrângerilor la care sunt
supuse), în obiecte ce pot fi apoi exploatate în manieră procedurală
sau neprocedurală;
• module pentru tratarea limbajului de prelucrare a datelor
(interpretativ, compilativ, generare de programe), care permit
utilizatorilor inserarea, ştergerea, reactualizarea sau consultarea
informaţiei dintr-o bază de date;
• module utilitare, care asigură întreţinerea, prelucrarea, exploatarea
corectă şi uşoară a bazei de date;
• module de control, care permit controlul programelor de aplicaţie,
asigurarea confidenţialităţii şi integrităţii datelor, rezolvarea unor
probleme de concurenţă, recuperarea informaţiei în cazul unor
avarii sau defecţiuni hardware sau software etc.
10
Modulele PGBD asigură accesul fizic la date ca urmare a unei
comenzi. Cum lucrează aceste module?
• găsesc descrierea datelor implicate în comandă;
• identifică datele şi tipul acestora;
• identifică informaţii ce permit accesul la structurile fizice de
stocare (fişiere, volume etc.);
• verifică dacă datele sunt disponibile;
• extrag datele, fac conversiile, plasează datele în spaţiul de memorie
al utilizatorului;
• transmit informaţii de control necesare execuţiei comenzii, în
spaţiul de memorie al utilizatorului;
• transferă controlul programului de aplicaţie.
Prin urmare, din punct de vedere conceptual:
• utilizatorul lansează o cerere de acces;
• SGBD-ul acceptă cererea şi o analizează;
• SGBD-ul inspectează pe rând, schema internă corespunzatoare
utilizatorului, schema conceptuală, definiţia structurii de stocare şi
corespondenţele corespunzătoare;
• SGBD-ul execută operaţiile necesare în baza de date stocată.

1.3. Arhitectura sistemelor de gestiune a bazelor de date

Asigurarea independenţei fizice şi logice a datelor impune adoptarea


unei arhitecturi de baze de date organizată pe trei niveluri:
• nivelul intern (baza de date fizică);
• nivelul conceptual (modelul conceptual, schema conceptuală);
• nivelul extern (modelul extern, subschema, vizualizarea).

Nivelul central este nivelul conceptual. Acesta corespunde structurii


canonice a datelor ce caracterizează procesul de modelat, adică structura
semantică a datelor fără implementarea pe calculator. Schema conceptuală
permite definirea tipurilor de date ce caracterizează proprietăţile elementare
ale entităţilor, definirea tipurilor de date compuse care permit regruparea
atributelor pentru a descrie entităţile modelului şi legăturile între aceste
entităţi, definirea regulilor pe care trebuie să le respecte datele etc.
Nivelul intern corespunde structurii interne de stocare a datelor.
Schema internă permite descrierea datelor unei baze sub forma în care sunt
11

stocate în memoria calculatorului. Sunt definite fişierele care conţin aceste


date, articolele din fişiere, drumurile de acces la aceste articole etc.
La nivel conceptual sau intern, schemele descriu o bază de date. La
nivel extern schemele descriu doar o parte din date care prezintă interes
pentru un utilizator sau un grup de utilizatori. Schema externă reprezintă o
descriere a unei părţi a bazei de date ce corespunde viziunii unui program
sau unui utilizator. Modelul extern folosit este dependent de limbajul
utilizat pentru prelucrarea bazei de date. Schema externă permite asigurarea
unei securităţi a datelor. Un grup de lucru va accesa doar datele descrise în
schema sa externă, iar restul datelor sunt protejate împotriva accesului
neautorizat sau rău intenţionat.
Pentru o bază de date particulară există o singură schemă internă, o
singură schemă conceptuală, dar există mai multe scheme externe.
În afară de aceste trei niveluri, arhitectura presupune şi anumite
corespondenţe dintre acestea:
• corespondenţa conceptual-intern defineşte relaţia dintre nivelul
conceptual şi baza de date stocată, specificând modul în care
înregistrările şi câmpurile conceptuale sunt reprezentate la nivel
intern;
• corespondenţa extern-conceptual defineşte relaţia dintre o anumită
vizualizare externă şi nivelul (vizualizarea) conceptual,
reprezentând cheia independenţei logice de date;
• corespondenţa extern-extern permite definirea unor vizualizări
externe în funcţie de altele, fără a necesita o definiţie explicită a
corespondenţei cu nivelul conceptual.
Arhitectura funcţională de referinţă propusă de grupul de lucru
ANSI/X3/SPARC este axată pe dicţionarul datelor şi cuprinde două părţi:
• prima, permite descrierea datelor (compoziţia dicţionarului
datelor);
• a doua, permite prelucrarea datelor (interogarea şi reactualizarea
bazei de date).
În fiecare parte se regăsesc cele trei niveluri: intern, conceptual şi
extern. Acestea nu sunt neapărat distincte pentru orice SGBD.
Interfeţele numerotate din figura 1.1, ce descriu arhitectura de
referinţă a unui SGBD, corespund următoarelor transformări:
a) Limbaj de descriere a datelor conceptuale, format sursă – permite
administratorului întreprinderii să definească schema conceptuală,
format sursă.
12
b) Limbaj de descriere a datelor conceptuale, format obiect – se
obţine din compilarea celui precedent şi permite aranjarea schemei
obiect în dicţionarul datelor.
c) Limbaj de descriere a datelor conceptuale, format editare –
permite administratorilor aplicaţiilor şi a bazelor să consulte
schema conceptuală pentru a defini reguli de corespondenţă.
d) Limbaje de descriere a datelor externe, format sursă – permit
administratorilor aplicaţiilor să definească scheme externe
corespunzând schemei conceptuale. Deoarece sistemele de
gestiune pot suporta mai multe modele externe, pot exista mai
multe limbaje de descriere a datelor externe.
e) Limbaje de descriere a datelor externe, format obiect – corespund
formelor compilate ale celor precedente şi permit aranjarea
schemelor externe (obiect) în dicţionarul datelor.
f) Limbaj de descriere a datelor interne, format sursă – permite
administratorului bazei de date să definească schema internă şi
regulile de corespondenţă cu schema conceptuală.
g) Limbaj de descriere a datelor interne, format obiect – corespunde
formei compilate a celui precedent şi permite aranjarea schemei
interne (obiect) în dicţionarul datelor.
h) Limbaje de prelucrare a datelor externe, format sursă – permit
programatorilor de aplicaţii sau utilizatorilor neinformaticieni să
manipuleze date externe (view).
i) Limbaje de prelucrare a datelor externe, format obiect – corespund
formelor compilate ale celor precedente.
j) Limbaj de prelucrare a datelor conceptuale, format obiect – produs
de procesorul de transformare extern/ conceptual pentru a
manipula datele externe.
k) Limbaj de prelucrare a datelor interne, format obiect –produs de
procesorul de transformare conceptual/intern pentru a gestiona
datele interne.
l) Limbaj de stocare a datelor, format obiect – corespunde interfeţei
cu sistemul de stocare a datelor.
m) Interfaţa cu memoria secundară – permite efectuarea de
intrări/ieşiri în/din unitatea de memorie secundară.
n) Interfaţa de acces la dicţionarul datelor – permite diverselor
procesoare de transformare să acceseze scheme obiect şi reguli de
corespondenţă.
13

Procesoarele din figura 1.1 au următoarele funcţii:


• procesorul schemei conceptuale compilează schema conceptuală şi
dacă nu sunt erori depune schema compilată în dicţionarul datelor;
• procesorul schemei externe compilează schemele externe şi
regulile de corespondenţă externă şi dacă nu sunt erori aranjează
schema compilată şi regulile de corespondenţă în dicţionarul
datelor;
• procesorul schemei interne are rol similar pentru schema internă;
• procesorul de transformare extern/conceptual transformă
manipulările externe în manipulări conceptuale şi invers, datele
conceptuale în date externe;
• procesorul de transformare conceptual/intern transformă
manipulările conceptuale în manipulări interne şi invers, datele
interne în date conceptuale;
• procesorul de transformare intern/stocare transformă manipulările
interne în primitive ale sistemului de stocare şi invers, eliberează
datele stocate într-un format corespunzător schemei interne.
14

administrator
întreprindere

a
administratorul c procesor c administratorul
bazei de date schema aplicaţiilor

DESCRIERE
conceptuală

b
f d

g e
procesor dicţionarul procesor
schema datelor schema
internă externă

procesor k procesor j procesor


intern/ conceptual/ extern/
alocare intern conceptual

l i

sistem

PRELUCRARE
program
de aplicaţii
alocare extern

h h
m

programator
aplicaţie utilizatori

memorii
secundare

Fig. 1.1. Arhitectura de referinţă a unui SGBD.

Gardarin a propus o arhitectură funcţională apropiată de arhitectura


sistemelor de gestiune actuale care are la bază doar două niveluri:
• schema, care corespunde integrării schemelor interne şi
conceptuale;
• vizualizarea, care este o schemă externă.
15

Sistemul de gestiune gestionează un dicţionar de date care este


alimentat prin comenzi de definire a schemei şi prin comenzi de definire a
vizualizărilor.
Aceste comenzi, precum şi cererile de prelucrare sunt analizate şi
tratate de un procesor numit analizor. Analizorul realizează analiza
sintactică şi semantică a cererii şi o traduce în format intern. O cerere în
format intern care face referinţă la o vizualizare este tradusă în una sau mai
multe cereri care fac referinţă la obiecte ce există în baza de date
(modificarea cererilor).
În cadrul acestei arhitecturi există un procesor, numit translator,
care realizează modificarea cererilor, asigură controlul drepturilor de acces
şi controlul integrităţii în cazul reactualizărilor.
Componenta cheie a sistemului de gestiune este procesorul
optimizor care elaborează un plan de acces optim pentru a trata cererea.
Acest procesor descompune cererea în operaţii de acces elementare şi alege
o ordine de execuţie optimală. De asemenea, evaluează costul planului de
acces înaintea execuţiei sale.
Planul de acces ales şi elaborat de optimizor este executat de un
procesor numit executor. La acest nivel este gestionat controlul
concurenţei.

1.4. Evoluţia bazelor de date

Istoria bazelor de date şi a sistemelor de gestiune a bazelor de date


poate fi rezumată în trei generaţii:
• sisteme ierarhice şi reţea,
• sisteme relaţionale,
• sisteme avansate (orientate obiect, relaţionale orientate obiect,
deductive, distribuite, multimedia, multibaze, active, temporale,
decizionale, magazii de date etc.).

Baze de date ierarhice şi reţea
Pentru modelele ierarhice şi reţea, datele sunt reprezentate la nivel de
articol prin legături ierarhice (arbore) sau de tip graf. Slaba independenţă
fizică a datelor complică administrarea şi prelucrarea acestora. Limbajul de
prelucrare a datelor impune programatorului să specifice drumurile de
acces la date.
16
Baze de date relaţionale
A doua generaţie de SGBD-uri este legată de apariţia modelelor
relaţionale (1970), care tratează entităţile ca nişte relaţii. Piaţa actuală de
baze de date este acoperită în majoritate de sisteme relaţionale. Bazele de
date relaţionale sunt caracterizate de:
• structuri de date simple, intuitive,
• inexistenţa pointerilor vizibili pentru utilizator,
• constrângeri de integritate,
• operatori aplicaţi relaţiilor care permit definirea, căutarea şi
reactualizarea datelor.
Dezvoltarea unei aplicaţii riguroase utilizand o bază de date
relaţionale necesită cunoaşterea a trei niveluri de instrumente, eterogene
din punct de vedere conceptual:
• nivelul instrumentelor grafice (interfaţa);
• nivelul aplicaţie, cu limbajele sale de dezvoltare;
• nivelul SGBD, cu standardul SQL (Structured Query Language) ce
permite definirea, prelucrarea şi controlul bazei de date.

Baze de date orientate obiect


Bazele de date relaţionale nu folosesc însă obiecte complexe şi
dinamice, nu realizează gestiunea datelor distribuite şi nici gestiunea
cunoştinţelor. A treia generaţie de SGBD-uri, sistemele avansate, încearcă
să depăşească aceste limite ale sistemului relaţional.
Suportul obiectelor complexe şi dinamice şi prelucrarea acestora este
dificilă pentru sistemele relaţionale, deoarece tipul datelor este limitat la
câteva domenii alfanumerice, iar structura datelor este simplă. Sistemele
relaţionale nu modelează obiecte complexe ca grafuri, liste etc. Un obiect
complex poate să fie descompus în relaţii, dar apar dificultăţi atât la
descompunerea, cât şi la refacerea acestuia prin compunere. De asemenea,
limbajele modelului relaţional permit prelucrarea cu dificultate a obiectelor
complexe.
Un sistem relaţional nu suportă obiecte dinamice care incorporează
atât partea de date (informaţii) efective, cât şi o parte relativă la tratarea
acestora.
Îmbinarea tehnicii limbajelor orientate obiect cu a bazelor de date a
permis realizarea bazelor de date orientate obiect. Acestea permit
organizarea coerentă a obiectelor partajate între utilizatori concurenţi.
Sistemele de gestiune de baze de date orientate obiect (SGBDOO) prezintă
o serie de avantaje:
17

• realizează o modelare superioară a informaţiei,


• furnizează posibilităţi superioare de deducţie (ierarhie de clase,
moştenire),
• permit luarea în considerare a aspectelor dinamice şi integrarea
descrierii structurale şi comportamentale,
• asigură îmbunătăţirea interfeţei cu utilizatorul.
Cu toate avantajele incontestabile oferite de SGBDOO-uri,
impunerea lor pe piaţa bazelor de date nu a fost uşoară. Câteva motivaţii a
acestei situaţii:
• absenţa unei fundamentări teoretice face imposibilă definirea unui
SGBDOO de referinţă;
• gestiunea obiectelor complexe este mai dificilă decât accesul la
relaţii prin cereri SQL;
• utilizatorii au investit sume uriaşe în sistemele relaţionale şi nu le
pot abandona cu uşurinţă. Trecerea la noua tehnologie orientată
obiect implică investiţii mari şi nu păstrează aproape nimic din
vechile soluţii.

Baze de date relaţionale orientate obiect


Simplitatea modelului relaţional, combinată cu puterea tehnologiei
orientate obiect a generat un domeniu nou şi promiţător în lumea bazelor de
date, şi anume bazele de date relaţionale orientate obiect.
Construcţia unui sistem de gestiune de baze de date relaţionale
orientate obiect (SGBDROO) trebuie să pornească de la cele existente.
Aceasta se poate realiza în două moduri: dezvoltând un sistem relaţional
prin adăugarea caracteristicilor obiectuale necesare sau pornind de la un
sistem orientat obiect şi adăugând caracteristicile relaţionale.

Baze de date deductive


O relaţie este o mulţime de înregistrări ce reprezintă fapte.
Cunoştinţele sunt aserţiuni generale şi abstracte asupra faptelor.
Cunoştinţele permit să raţionezi, ceea ce permite deducerea de noi fapte,
plecând de la fapte cunoscute. Un SGBD relaţional suportă o formă limitată
de cunoştinţe, şi anume constrângerile de integritate, iar restul trebuie
integrate în programele de aplicaţie. Aceasta generează probleme deoarece
cunoştinţele trebuie codificate în programe şi apare imposibilitatea de a
partaja cunoştinţe între utilizatori. Totul se complică dacă există un volum
mare de fapte.
18
Bazele de date deductive, utilizând programarea logică, gestionează
cunoştinţe relativ la baze de date care, în general, sunt relaţionale. Bazele
de date deductive permit deducerea de noi informaţii, plecând de la
informaţiile stocate în baza de date. Un SGBD deductiv posedă:
• un limbaj de definire a datelor care permite definirea structurii
predicatelor sub formă de relaţii şi constrângeri de integritate
asociate;
• un limbaj de prelucrare a datelor care permite efectuarea
reactualizărilor asupra datelor şi formularea unor cereri;
• un limbaj de reguli de deducţie care permite ca, plecând cu
predicatele definite anterior, să se specifice cum pot fi construite
predicate derivate.

Baze de date distribuite


Un sistem distribuit este un ansamblu de maşini ce sunt
interconectate printr-o reţea de comunicaţie şi utilizate într-un scop global.
Administrarea şi prelucrarea datelor distribuite, situate pe diferite
calculatoare şi exploatate de sisteme eterogene este obiectivul fundamental
al bazelor de date distribuite.
Bazele de date distribuite sunt sisteme de baze de date cooperante
care rezidă pe maşini diferite, în locuri diferite. Această mulţime de baze de
date este exploatată de utilizator ca şi cum ar fi o singură bază de date.
Programul de aplicaţie care exploatează o bază de date distribuite poate
avea acces la date rezidente pe mai multe maşini, fără ca programatorul să
cunoască localizarea datelor.
Modelul relaţional a rămas instrumentul principal prin care se
realizează prelucrarea datelor distribuite.
Câteva dintre argumentele pentru a justifica această afirmaţie sunt:
• bazele relaţionale oferă flexibilitate de descompunere în vederea
distribuirii;
• operatorii relaţionali pot fi folosiţi pentru combinaţii dinamice ale
informaţiilor descentralizate;
• limbajele sistemelor relaţionale sunt concise şi asigură o economie
considerabilă a transmiterii datelor. Ele fac posibil, pentru un nod
oarecare al reţelei, să analizeze intenţia unei tranzacţii, să o
descompună rapid în componente ce pot fi realizate local şi
componente ce pot fi transportate altor noduri.
19

Calculatoare şi maşini baze de date


Soluţia pentru a descentraliza prelucrarea datelor, în scopul evitării
saturării memoriei şi a procesoarelor calculatorului central, a fost apariţia
calculatoarelor baze de date şi a maşinilor baze de date. Descentralizarea
presupune transferarea unei părţi din funcţiile unui SGBD către un
calculator periferic (calculator backend) adică deplasarea algoritmilor de
căutare şi a celor de actualizare a datelor mai aproape de memoria
secundară. Acest calculator periferic permite utilizarea optimă a resurselor
şi realizarea paralelismului în tratarea cererilor de informaţii.
Calculatorul periferic poate fi un calculator clasic, dar cu un software
specific de SGBD (calculator bază de date) sau poate fi o maşină cu
hardware specializat în gestiunea bazelor de date (maşină bază de date).
Maşinile baze de date sunt înzestrate cu arhitecturi paralele special adaptate
pentru gestionarea unui volum mare de date. Tratarea paralelă a cererilor
permite reducerea timpului total de execuţie a acestora.
O execuţie în paralel solicită, fie descompunerea unui program în
module, care pot fi executate în paralel (descompunere funcţională), fie
descompunerea datelor în subgrupe, astfel încât toate procesoarele să
execute acelaşi lucru, dar pe date diferite. Performanţele tratării paralele
depind de modul în care sunt efectuate descompunerile.

Multibaze de date
Diferite departamente ale unei organizaţii mai mari pot folosi diferite
sisteme de gestiune. Cu toate că fiecare sistem este dezvoltat pentru a
satisface nevoile propriului său departament, informaţiile cu care lucrează
pot fi utile şi altor departamente. De aceea, pentru ca organizaţia să
funcţioneze bine, trebuie să existe o modalitate globală da a vedea datele
din fiecare sistem. Există două caracteristici ale unor astfel de sisteme care
fac acceasarea datelor în acest mediu integrat greoaie, uneori chiar
imposibilă:
• autonomie – fiecare SGBD are o autonomie completă, ceea ce
înseamnă că fiecare manager are control deplin asupra sistemului;
• eterogenitate – sistemele pot opera pe diferite platforme, cu diferite
modele de date şi limbajele de interogare.
Una dintre soluţiile folosite pentru a depăşi dificultăţile întâmpinate în
respectarea autonomiei şi a eterogenităţii este utilizarea sistemelor multibaze
de date.
20
Un sistem multibaze de date (SMB) este alcătuit din mai multe sisteme
de baze de date privite integrat, în care se construiesc una sau mai multe
scheme globale pe baza schemelor fiecărei baze de date componente, astfel
încât să se poată realiza accesul uniform şi integrat la fiecare din bazele de
date componente. Fiecare schemă globală este construită pe baza unui model
particular de date. De exemplu, se poate construi o schemă globală ce are la
bază modelul relaţional pentru utilizatorii care sunt familiarizaţi cu acest
model, dar se poate construi o schemă globală bazată pe modelul orientat
obiect pentru utilizatorii bazelor de date orientate obiect.
Pentru o schemă globală dată, un sistem multibaze de date constă din
sistemele componente împreună cu un sistem front-end, care suportă un
singur model de date şi un singur limbaj de interogare. Principalele sarcini ale
sistemului front-end sunt gestionarea schemei globale şi procesarea cererilor
globale.
Un avantaj major al acestui model, faţă de altele, este faptul că o
singură interogare poate accesa date din mai multe baze de date într-un mod
integrat, fără să afecteze nici o aplicaţie care este scrisă utilizând una dintre
bazele de date componente.

Baze de date cu suport decizional


Sistemele informatice, în particular bazele de date, au ajuns la
maturitate. Marile companii au acumulat o mare cantitate de informaţii din
domeniul lor de activitate, pe care le păstrează în tabele istorice şi sunt
nefolositoare sistemelor operaţionale ale companiei, care funcţionează cu
date curente. Analizate, aceste date ar putea oferi informaţii despre tendinţe
şi evoluţii care ar putea interesa compania. Pentru a putea analiza aceste
mari cantităţi de date este nevoie de tehnologii şi instrumente speciale.
Ideea de a analiza colecţii de date provenind din sistemele
operaţionale ale companiei sau din surse externe pentru a le folosi ca suport
în procesul de decizie nu aparţine ultimului deceniu, dar baze de date care
să funcţioneze eficient după aceste criterii au fost studiate şi implementate
în ultimii ani. Principalul scop al acestor baze de date a fost de a întâmpina
nevoile sistemelor operaţionale, a căror natură este inerent tranzacţională.
Sistemele tranzacţionale sunt interesate, în primul rând, să controleze
la un moment dat o singură tranzacţie. De exemplu, într-un sistem bancar,
atunci când clientul face un depozit, sistemul operaţional bancar este
responsabil de a înregistra tranzacţia într-un tabel al tranzacţiilor şi de a
creşte nivelul curent al contului clientului, stocat în alt tabel.
21

Un sistem operaţional tipic operează cu evenimente predefinite şi,


datorită naturii lor, necesită acces rapid la date. Uzual, fiecare tranzacţie
operează cu cantităţi mici de date.
De-a lungul timpului, nevoile sistemelor operaţionale nu se schimbă
mult. Aplicaţia care înregistrează tranzacţia, ca şi cea care controlează
accesul utilizatorului la informaţie (partea de raportare a sistemului
bancar), nu se modifică prea mult. În acest tip de sistem, informaţia
necesară în momentul în care un client iniţiază o tranzacţie trebuie sa fie
actuală. Înainte ca o bancă să aprobe un împrumut este nevoie să se asigure
de situaţia financiară stabilă a clientului în acel moment, şi nu cu un an
înainte.
În ultimii ani s-au pus la punct principii şi tehnologii noi care să
servească procesului de analiză şi administrare a datelor. O bază de date
optimizată în acest scop defineşte o Data Warehouse (magazie de date), iar
principiul pe care îl urmează este cunoscut sub numele de procesare
analitică (OLAP – On Line Analytical Processing). Spre deosebire de
acesta, principiul pe care se bazează sistemele tranzacţionale a fost numit
procesare tranzacţională (OLTP – On Line Transactional Processing).
Aplicaţiile unei Data Warehouse trebuie să ofere răspunsuri unor
întrebări de tipul: „Care zi din săptămână este cea mai aglomerată?“ „Ce
clienţi, cu care avem relaţii intense, nu au beneficiat de reduceri de
preţuri?“. O caracteristică a bazelor de date analitice este că interogările la
care acestea trebuie să răspundă sunt ad-hoc, nu sunt predefinite, iar baza
de date trebuie optimizată astfel încât să fie capabilă să răspundă la orice
fel de întrebare care poate implica mai multe tabele.
În această abordare, organele generale de decizie necesită accesul la
toate datele organizaţiei, oriunde s-ar afla acestea. Pentru o analiză
corespunzătoare a organizaţiei, afacerilor, cerinţelor, tendinţelor este
necesară nu numai accesarea valorilor curente din baza de date, ci şi a
datelor istorice. Prin urmare, pentru a facilita acest tip specific de analiză a
informaţiei a fost creată magazia de date, care conţine informaţii extrase
din diverse surse, întreţinute de diverse unităţi operative, împreună cu
istoricul şi rezumatul tranzacţiilor.
Sursele de date pentru o magazie cuprind:
• date operaţionale, păstrate în baze de date ierarhice, de prima
generaţie;
• date departamentale, păstrate în sisteme de fişiere patentate;
22
• date cu caracter personal, păstrate pe staţii de lucru şi servere
personale;
• sisteme externe (baze de date comerciale, Internet etc.)
Data warehouse este o colecţie de date:
• orientate spre subiect (principalele subiecte ale modelului sunt
clienţii, produsele, vânzările, în loc de domeniile de activitate),
• nevolatile (datele nu sunt reactualizate, înlocuite în timp real, ci
sunt adăugate ca un supliment al bazei),
• integrate (transpunerea datelor provenite din diverse surse de
informaţii se face într-un format consistent),
• variabile în timp (concentrarea depozitului de date se face asupra
schimbărilor care au loc în timp).

Administrator Depozit de date Utilitare


cereri,
META-FLUX rapoarte

Sursa 1 Metadate
Date operationale
Date cu nivel
mare de agregare
Utilitare
Administrator Administrator OLAP
FLUX incarcare date cereri
INTERN
FLUX
Date cu nivel EXTERN
mic de agregare FLUX
ASCENDENT
Date detaliate Utilitare
SGBD Data mining

Sursa n
Date operationale Administrator Depozit de date

Utilitare pentru
Arhive/ date FLUX accesul
backup DESCENDENT utilizatorilor finali

Fig 1.2. Arhitectura unui depozit de date

Înmagazinarea datelor se concentrează asupra gestionării a cinci


fluxuri de informaţii:
23

• fluxul intern, care reprezintă procesele asociate extragerii şi


încărcării datelor din fişierele sursă în magazia de date;
• fluxul ascendent, care reprezintă procesele asociate adăugării de
valoare datelor din magazie, cu ajutorul împachetării şi distribuirii;
• fluxul descendent, care reprezintă procesele asociate arhivării,
salvării, refacerii datelor din magazie;
• fluxul extern, care reprezintă procesele asociate punerii la dispoziţie
a datelor pentru utilizatorii finali;
• meta-fluxul, care reprezintă procesele asociate gestionării meta-
datelor (date despre date).
În arhitectura depozitului de date intervin câteva componente
specifice acestei structuri.
• Administratorul pentru încărcarea datelor (componenta front-end)
realizează toate operaţiile asociate cu obţinerea (extragerea) şi
încărcarea datelor operaţionale într-un depozit de date.
• Administratorul depozitului de date realizează toate operaţiile
legate de administrarea datelor din depozit. Operaţiile realizate de
componenta de administrare a depozitului de date includ: analiza
datelor pentru a asigura consistenţa acestora; transformarea şi
mutarea datelor sursă din structurile temporare de stocare în
tabelele depozitului de date; crearea de indecşi şi vizualizări asupra
tabelelor de bază; generarea denormalizării (dacă este necesar);
generarea agregărilor; crearea arhivelor şi a backup-urilor.
• Administratorul cererilor (componenta back-end) realizează toate
operaţiile legate de administrarea cererilor utilizator. Această
componentă este construită folosind utilitarele de acces la date
disponibile utilizatorilor finali, utilitarele de monitorizare a
depozitului de date, facilităţile oferite de sistemul de baze de date
şi programele personalizate.
• În zona ce include date agregate sunt stocate toate agregările
predefinite de date, pe diferite niveluri. Scopul, menţinerii
acestora, este de a mări performanţa cererilor care necesită
agregări. Datele agregate sunt actualizate permanent, pe măsură ce
sunt încărcate noi informaţii în depozit.
• Scopul principal al depozitelor de date este de a oferi informaţii
necesare utilizatorilor pentru luarea deciziilor strategice de
marketing. Aceşti utilizatori interacţionează cu depozitul de date
prin diferite utilitare de acces (utilitare pentru rapoarte şi cereri,
24
utilitare pentru dezvoltarea aplicaţiilor, utilitare pentru procesarea
analitică on-line (OLAP), utilitare data mining) etc.
Instrumentele de acces pentru utilizatorii finali ai magaziilor de date:
• prelucrarea analitică on-line;
• extensiile limbajului SQL;
• instrumentele de extragere a datelor.
Prelucrarea analitică on-line (OLAP) reprezintă sinteza, analiza şi
consolidarea dinamică a unor volume mari de date multidimensionale.
Serverele de baze de date OLAP utilizează structuri multidimensionale
pentru stocarea datelor şi a relaţiilor dintre date. Aceste structuri pot fi
vizualizate prin cuburi de date şi cuburi în cadrul cuburilor etc. Fiecare
latură a cubului reprezintă o dimensiune. Serverele de baze de date OLAP
multidimensionale acceptă operaţiile analitice uzuale: consolidarea
(gruparea), parcurgerea în jos (inversul consolidării), tranşarea, tăierea.
OLAP necesită o modalitate de agregare a datelor conform mai multor
grupări diferite, în număr foarte mare, iar utilizatorii trebuie să le aibă în
vedere pe toate.
Instrumentele OLAP presupun organizarea informaţiei într-un model
multidimensional care este susţinut de o bază de date:
• multidimensională (MOLAP), în care datele sunt stocate
conceptual în celulele unui tablou multidimensional;
• relaţională (ROLAP), proiectată pentru a permite
interogări multidimensionale.
În acest context, a devenit o necesitate extinderea limbajului SQL
prin operaţii puternice, necesare pentru rezolvarea noului tip de abordare.
Au fost introduse noi funcţii numerice (limita inferioară, limita superioară
etc.), noi funcţii statistice (distribuţie, distribuţie inversă, corelaţie etc.), noi
operatori de agregare, extensii ale clauzei GROUP BY etc.
De exemplu, RISQL (Red Brick Intelligent SQL), proiectat pentru
analiştii din domeniul afacerilor, permite: ordonare după rang (pe diferite
niveluri - de exemplu, gruparea filialelor în trei categorii pe baza venitului
generat în anul precedent), partajarea pieţei, compararea anului curent cu
cel precedent etc.
O altă problemă esenţială este extragerea datelor şi utilizarea
acestora pentru luarea de decizii cruciale în domeniul afacerilor.
Descoperirea unor noi corelaţii, tipare, tendinţe, prin extragerea unor
cantităţi mari de date folosind strategia inteligenţei artificiale este una din
modalităţile de rezolvare.
Extragerea datelor presupune capacitatea de a construi modele mai
degrabă previzibile, decât retrospective. Modelarea predictivă utilizează
25

informaţii pentru a forma un model al caracteristicilor importante ale unui


fenomen.
Tehnicile asociate operaţiilor fundamentale de extragere sunt:
• modelarea predictivă (clasificarea cu ajutorul unei reţele neurale
sau al unei inducţii de tip arbore şi previziunea valorilor, utilizând
tehnici de regresie);
• segmentarea bazei de date (comasarea demografică şi comasarea
neurală care se deosebesc prin metodele uilizate pentru a calcula
distanţa dintre înregistrări, prin intrările de date permise);
• analiza legăturilor (descoperirea asocierilor, descoperirea tiparelor,
descoperirea secvenţelor de timp similare);
• detectarea deviaţiilor (statistici şi vizualizări pentru identificarea
împrăştierii datelor, utilizând tehnici moderne de vizualizare
grafică). În această clasă pot fi considerate, de exemplu, detectarea
fraudelor privind utilizarea cărţilor de credit, pretenţiile de
despăgubire ale asiguraţilor etc.
În concluzie, spre deosebire de un sistem OLTP, Data Warehouse
este o bază de date a cărei structură este proiectată pentru a facilita analiza
datelor. Un sistem de suport decizional urmăreşte, în primul rând, obţinerea
de informaţii din baza de date, în timp ce unul OLTP urmăreşte
introducerea de informaţii în baza de date. Datorită acestor diferenţe,
structura optimă a unei Data Warehouse este radical diferită de cea a unui
sistem OLTP.
Depozitele de date şi sistemele OLTP sunt supuse unor cerinţe
diferite, dintre care cele mai semnificative se referă la operaţii, actualizarea
datelor, proiectare, operaţii tipice şi date istorice.
• Operaţii. Depozitele sunt create pentru a permite interogări ad hoc.
Ele trebuie să fie suficient de flexibile pentru a putea răspunde
interogărilor spontane ale utilizatorilor. Sistemele OLTP suportă
numai operaţii predefinite. Aplicaţiile pot fi optimizate sau create
special numai pentru acele operaţii.
• Actualizarea datelor. Utilizatorii finali ai unui depozit de date nu
fac în mod direct actualizări ale depozitului. În sistemele OLTP,
utilizatorii realizează, de obicei, în mod individual procedurile de
modificare a bazei de date. În acest fel, baza de date OLTP este
întotdeauna la zi şi reflectă starea curentă a fiecărei tranzacţii.
• Proiectare. Depozitele de date folosesc, în mod uzual, scheme
denormalizate, în timp ce sistemele OLTP folosesc scheme
normalizate pentru a optimiza performanţele operaţiilor.
26
• Operaţii tipice. O simplă interogare a depozitului de date poate
scana mii sau chiar milioane de înregistrări (de exemplu, cererea
„Care sunt vânzările totale către toţi clienţii din luna trecută?“), în
timp ce o operaţie tipică OLTP accesează doar o parte mai mică
din înregistrări.
• Date istorice. Depozitele de date stochează datele pe o perioadă
lungă de timp, luni sau ani. Acest lucru oferă suport pentru analiza
istorică a informaţiei. Sistemele OLTP reţin date istorice atât timp
cât este necesar pentru a îndeplini cu succes cerinţele tranzacţiilor
curente.

Sistemele OLTP Data Warehouse


Păstrează date curente Păstrează date istorice
Stochează date detaliate, agregate uşor
Stochează date detaliate
sau puternic
Datele sunt dinamice Datele sunt în mare măsură statice
Prelucrare ad-hoc, nestructurată şi
Prelucrare repetitivă
euristică
Nivel înalt de transfer al Nivel mediu sau scăzut de transfer al
tranzacţiilor tranzacţiilor
Tipar de utilizare previzibil Tipar de utilizare imprevizibil
Conduse prin tranzacţii Conduse prin analiză
Susţin deciziile de zi cu zi Susţin deciziile strategice
Deservesc un număr mare Deservesc un număr relativ redus de
de utilizatori utilizatori din administraţie
Orientate spre aplicaţii Orientate spre subiect

Fig. 1.3. OLTP versus Data Warehouse

O bază de date OLAP poate fi relaţională, dar datorită naturii ei


orientate spre dimensiuni, au fost dezvoltate pentru gestionarea acestor
baze de date construcţii multidimensionale, mai potrivite pentru o raportare
flexibilă. Spre deosebire de bazele de date relaţionale, structura unei baze
de date multidimensionale nu implică tabele, linii şi coloane, ci obiecte de
următoarele tipuri: variabile, dimensiuni, niveluri, ierarhii, atribute.
Data Warehouse, care cuprinde de obicei informaţii despre o
întreagă companie, poate fi subîmpărţită în baze de date departamentale,
numite rafturi de date (Data Marts). De exemplu, poate exista un Data
27

Mart al departamentului financiar, un altul al departamentului vânzări şi un


altul pentru departamentul marketing.
Construcţia unei astfel de baze de date poate fi abordată în două
moduri.
• O primă abordare este de a construi mai întâi un schelet al bazei de
date la care se lipesc ulterior rafturile de date. Aceasta necesită o
analiză prealabilă a întregului şi o delimitare a blocurilor
componente. Ea cere un timp mai lung de dezvoltare, dar rezultatul
este o bază de date unitară.
• A doua metodă este de a construi mai întâi rafturi specifice, efortul
constând, în acest caz, în asocierea acestora. Această soluţie oferă
mai rapid, aplicaţii funcţionale utilizatorilor, dar au de suferit
unitatea şi portabilitatea aplicaţiilor finale.
Utilizatorii trebuie să-şi schimbe optica asupra bazelor de date pentru
a fi capabili să folosească puterea şi flexibilitatea instrumentelor analitice
de care dispun. Instrumentele OLAP au evoluat ca o modalitate de a
rezolva interogările complicate necesare procesului de analiză a datelor.
Combinaţia între bazele de date multidimensionale şi instrumentele
analitice prietenoase face uşoară analiza, sinteza şi consolidarea datelor.
În ultimii ani, marii producători de sisteme de gestiune a bazelor de
date relaţionale, precum Oracle, au introdus în produsele lor construcţii
care să faciliteze accesul la datele din sistemele fundamentale pentru luarea
de decizii. Astfel, noile versiuni de SGBD-uri ale firmelor mari prevăd o
modalitate mai inteligentă de a realiza operaţia de compunere între două
sau mai multe tabele, metode de indexare noi, potrivite pentru marile
cantităţi de date statice cu care operează sistemele Data Warehouse,
capacitatea de a detecta şi optimiza interogări de un tip special,
posibilitatea de a folosi mai multe procesoare pentru a rezolva o interogare.
Un sistem Data Warehouse are un efect fundamental asupra
utilizatorilor. Ei pot manevra mult mai flexibil sistemul, au posibilităţi
elevate pentru interogarea datelor, dar ei trebuie să ştie cum să prelucreze şi
să vizualizeze datele şi cum să le folosească în procesul de decizie.
Un efort ce trebuie făcut pentru construirea unui sistem de suport
pentru decizii (DSS – Decision Support System) constă în procesul de
descoperire a informaţiilor utile din baza de date. Acest proces, numit Data
Mining sau Knowledge Discovery in Databases (KDD), procesează mari
cantităţi de date, a căror corelare nu este neapărat evidentă, în vederea
descoperirii de tendinţe şi tipare.
28

1.5. Arhitecturi multi-user pentru sisteme de gestiune a


bazelor de date

Arhitecturile uzuale care sunt utilizate pentru implementarea


sistemelor de gestiune a bazelor de date multi-user sunt: teleprocesarea,
arhitectura fişier-server arhitectura client-server.
Teleprocesarea este arhitectura tradiţională, ce cuprinde un
calculator cu o singură unitate CPU şi un numar de terminale care sunt
incapabile să funcţioneze singure. Terminalele trimit mesaje la programele
aplicaţie ale utilizatorilor, care la rândul lor, utilizează serviciile SGBD.
Această arhitectură a plasat o greutate teribilă asupra calculatorului
central, care pe lângă rularea programelor de aplicaţii şi ale SGBD-ului,
mai trebuie să preia şi din munca terminalelor (de exemplu, formatarea
datelor pentru afişarea pe ecran).
Arhitectura fişier-server, presupune deja că procesarea este
distribuită în reţea (de obicei o reţea locală LAN). Arhitectura cuprinde
fişierele cerute de aplicaţii şi SGBD-ul. Aplicaţiile şi funcţiile SGBD sunt
executate pe fiecare staţie de lucru, solicitând când este nevoie fişiere de pe
server-ul de fişiere. Dintre dezavantaje se remarcă:
• existenţa unui trafic intens pe reţea;
• necesitatea unei copii complete a SGBD-ului pe fiecare
staţie de lucru;
• acelaşi fişier poate fi accesat de mai multe SGBD-uri,
ceea ce implică un control complex al integrităţii, simultaneităţii,
reconstituirii.
Arhitectura client-server se referă la modul în care interacţionează
componentele software pentru a forma un sistem. Există un proces client,
care necesită resurse şi un proces server, care oferă resurse.
În arhitectura client-server, clientul (front end) emite, prin
intermediul reţelei locale, o cerere SQL care este executată pe server (back-
end); acesta trimite ca răspuns ansamblul înregistrărilor rezultat. Într-o
astfel de interacţiune maşinile sunt eterogene, iar protocoalele de reţea pot
fi distincte.
În contextul bazelor de date, client-ul:
• administrează interfaţa cu utilizatorul şi logica aplicaţiei;
• acceptă şi verifică sintaxa intrărilor utilizatorilor;
• procesează aplicaţiile;
• generează cerinţele pentru baza de date şi le trimite server-ului;
29

• transmite răspunsul înapoi la utilizator.

În contextul bazelor de date, server-ul:


• primeşte şi procesează cerinţele clienţilor pentru baza de date;
• verifică autorizarea;
• garantează respectarea constrângerilor de integritate;
• efectuează procesarea interogare-reactualizare şi trimite clientului
răspunsul;
• realizează optimizarea interogărilor;
• asigură controlul concurenţei dintre mai multi clienţi care se ignoră
(mecanisme de blocare);
• intreţine dictionarul datelor;
• oferă acces simultan la baza de date;
• asigură robusteţea în cazul defecţiunilor;
• oferă controlul reconstituirii etc.
Arhitectura tradiţională client-server pe „două etaje (straturi)“
presupune:
• client-ul – responsabil, în primul rand, de prezentarea datelor către
client;
• server-ul – responsabil, în primul rand, de furnizarea serviciilor
către client.
Arhitectura client-server pe „trei etaje“ presupune trei straturi,
fiecare fiind rulat, potenţial, pe o platformă diferită.
• stratul (client) format din interfaţa cu utilizatorul, care este rulat pe
calculatorul utilizatorului final;
• stratul (server de aplicaţie), ce manevrează logica aplicaţiilor şi
prelucrării datelor, şi care poate servi mai mulţi clienţi (conectare
la celelalte două straturi se face prin reţele locale LAN sau de mare
suprafaţă WAN);
• stratul (server-ul de baze de date), care se ocupă cu validarea
datelor şi accesarea bazei de date (stochează date necesare stratului
din mijloc).
Arhitectura se potriveşte natural mediului Web. Un browser Web
acţionând drept client şi un server Web fiind server de aplicaţie.
Middleware este un strat, evident software, între aplicaţia postului
client şi server-ul de baze de date, constituit dintr-o interfaţă de programare
a aplicaţiilor (API - Application Programming Interface) şi un protocol de
reţea.
30
API descrie tipul de interacţiune dintre o aplicaţie client şi un server
la distanţă, via un protocol de comunicaţie şi de formatare a datelor. Scopul
existenţei interfeţei de programare a aplicaţiilor este de a oferi o interfaţă
unică mai multor server-e de baze de date.
Este convenabil ca sistemele de baze de date să fie considerate ca
fiind formate dintr-un server (sistemul SGBD însăşi) şi un set de clienţi
(aplicaţiile). Frecvent, clienţii şi server-ul pot fi rulate pe calculatoare
diferite, realizându-se un tip simplu de procesare distribuită. În general,
fiecare server poate deservi mai multi clienţi, iar fiecare client poate accesa
mai multe server-e. Dacă sistemul oferă transparenţă totală (fiecare client
se poate comporta ca şi cum ar comunica cu un singur server, de pe un
singur calculator) atunci este vorba despre un sistem de baze de date
distribuite.

1.6. Tehnologia Web şi sistemele SGBD


Internet = o colecţie mondială de reţele de calculatoare.
Intranet = un sit Web sau un grup de sit-uri care aparţin unei
organizaţii, accesibil numai pentru membrii acesteia.
Extranet = o reţea intranet care este parţial accesibilă utilizatorilor
externi autorizaţi.
Reţea Web (World Wide Web) = un sistem bazat pe hipermedii care
pune la dispoziţie un mijloc simplu, de tip „indicare-clic“ de răsfoire a
informaţiilor pe Internet, folosind hiperlegăturile.
HTTP = protocolul utilizat pentru a transfera pagini Web prin
intermediul Internetului.
HTML = limbajul de formatare a documentelor utilizat în
proiectarea majorităţii paginilor Web.
Adresa URL = şir de caractere alfanumerice care reprezintă adresa
unei resurse pe Internet şi modul în care trebuie accesată resursa.
Interfaţa de poartă comună (CGI) = defineşte modul în care
scripturile comunică cu server-ul Web. Este tehnica de bază de integrare a
bazelor de date în reţeaua Web.
În mediul Web funcţionează modelul three tier format din:
• un strat de interfaţă cu utilizatorul (client),
• un strat de logică a afacerii şi prelucrare a datelor (server de
aplicaţii),
• un sistem SGBD (server de baze de date) distribuit pe calculatoare
diferite.
Avantajele reţelei Web ca platformă de baze de date:
• avantagele SGBD;
31

• simplitate;
• independenţa de platformă;
• interfaţa grafică cu utilizatorul;
• acces transparent în reţea;
• standardizare (HTML standard de facto).
Arhitectura de calcul în reţea a sistemului Oracle (NCA Network
Computing Architecture) se axează în principal pe furnizarea
extensibilităţii pentru mediile distribuite. Arhitectura este construită pe
baza tehnologiei CORBA pentru manipularea obiectelor. Este o structură
three tier care se bazează pe utilizarea de:
• cartuşe de software care permit utilizatorilor să adauge
funcţionalităţi individuale în aplicaţii (cartuşele pot fi construite
în Java, C/C++, Visual Basic, SQL şi pot fi conectate la oricare
din cele 3 straturi);
• protocoale deschise şi interfeţe standardizate care permit
comunicarea între cartuşe (distribuite într-o reţea) prin
intermediul unui program magistrală (ICX);
• clienţi extensibili, server-e de aplicaţie, server-e de baze
de date;
• dezvoltarea şi administrarea integrată a cartuşelor.
Un cartus utilizeaza un limbaj de definire a interfetelor (IDL)
pentru a putea fi identificat de alte obiecte intr-un sistem distribuit. De
exemplu, PL/SQL este un astfel de cartus.

Arhitectura multitier a sistemului Oracle9i


Arhitectura cu mai multe niveluri (multitier) conţine următoarele
elemente:
• unul sau mai mulţi client-i care iniţiază operaţii;
• unul sau mai multe server-e de aplicaţii care execută părţi ale
operaţiilor;
• un server de baze de date care stochează datele folosite de operaţii.
Client-ul, care poate fi un browser Web sau un proces user, iniţiază o
cerere pentru a executa o operaţie referitoare la informaţiile stocate în baza
de date. Conectarea la server-ul bazei de date se face printr-unul sau mai multe
server-e de aplicaţii.
Server-ul de aplicaţii constituie interfaţa dintre client-i şi server-ul
bazei de date, asigurând accesul la informaţii. De asemenea, el include un
nivel adiţional pentru securitate. Server-ul de aplicaţii îşi asumă identitatea
client-ului, atunci când execută, pe server-ul de baze de date, operaţiile
solicitate de acesta.
Arhitectura multitier permite folosirea unui server de aplicaţii pentru
32
acreditarea client-ului, conectarea la server-ul de baze de date şi execuţia
operaţiilor iniţiate de client. Privilegiile server-ului de aplicaţii sunt limitate
pentru a preveni execuţia operaţiilor nedorite sau inutile în timpul unei
operaţii client.
Server-ul de baze de date pune la dispoziţia server-ului de aplicaţii
informaţiile necesare pentru soluţionarea operaţiilor lansate de către client.
De asemenea, acesta face distincţia între operaţiile pe care server-ul de
aplicaţii le cere în favoarea client-ului şi cele pe care le solicită în nume
propriu.

Oracle9i Developer Suite

HTTP

Clienti HTTP Oracle9i Application Oracle9i Database


Server
Nivel 1 Nivel 2 Nivel 3

Fig. 1.4. Arhitectura three-tier a sistemului Oracle9i


2 MODELAREA
ENTITATE - RELAŢIE
Proiectarea bazelor de da te orientate ob iect
MODEL AREA BAZELO R D E DAT E

2.1. Preliminarii

Un model este o reprezentare a obiectelor şi evenimentelor lumii reale şi


a asocierilor dintre ele. De fapt, el reprezintă o abstracţie asupra aspectelor
semnificative ale unei „întreprinderi“, ale unui sistem real, ignorând proprietăţile
accidentale. Modelul este cel pe care utilizatorii trebuie să-l cunoască;
implementarea unui model este cea pe care utilizatorii nu este necesar să o
cunoască. Diferenţa dintre model şi implementare este, de fapt, un caz special şi
important al deosebirii uzuale dintre logic şi fizic.
Modelele se impun prin sintaxa şi prin semantica lor şi, din acest punct
de vedere, există trei tipuri fundamentale de modele:
• modele care descriu aspectele statice ale procesului modelat;
• modele care descriu aspectele dinamice ale procesului modelat;
• modele care descriu aspectele funcţionale ale procesului modelat.
Un model de date reprezintă o colecţie integrată de concepte necesare
descrierii:
• datelor,
• relaţiilor dintre ele,
• constrângerilor existente asupra datelor sistemului real analizat.
Modelarea unei baze de date permite trecerea de la percepţia unor fapte
din lumea reală la reprezentarea lor prin date. Modelul de date trebuie să
reflecte fidel fenomene ale lumii reale, să urmărească evoluţia acestei lumi şi
comunicarea dintre fenomenele lumii reale.
Modelul trebuie să asigure conceptele de bază care permit proiectantului
bazei de date şi utilizatorilor să comunice, fără ambiguităţi, cunoştinţele lor
privind funcţionarea şi organizarea modelului real analizat. Prin urmare, un
model de date trebuie să reprezinte datele şi să le facă înţelese.
În esenţă, modelul de date are trei componente:
• o mulţime de reguli conform cărora sunt construite bazele de date
(partea structurală);
• o mulţime de operaţii permise asupra datelor, care sunt utilizate pentru
reactualizarea sau regăsirea datelor (partea de prelucrare);
• o mulţime de reguli de integritate, care asigură coerenţa datelor.

Abordarea generală a problemei modelării semantice a datelor se face în


patru etape.
58 PROIECTAREA BAZELOR DE DATE
• Se identifică o mulţime de concepte semantice care sunt utile în
descrierea lumii reale. Se presupune că lumea reală (modelul real
analizat) este formată din entităţi care au anumite proprietăţi, că
fiecare entitate are o identitate, că există legături, corelaţii între
entităţi. Conceptul de corelaţie, ca şi cel de entitate, este util, în mod
intuitiv, la descrierea modelului.
• Se caută o mulţime de obiecte formale, simbolice care sunt utilizate
pentru reprezentarea conceptelor semantice anterioare.
• Se dau reguli de integritate formale şi generale (constrângeri) care să
reflecte restricţiile la care este supus modelul.
• Se defineşte o mulţime de operatori formali prin care pot fi prelucrate
şi analizate obiectele formale.

2.2. Modelul entitate-relaţie

Una dintre cele mai cunoscute abordări ale modelării semantice (cu
siguranţă una dintre cele mai utilizate) este cea bazată pe modelul entitate-
relaţie (E/R). Acesta a fost introdus de către Peter.P. Chen în 1976 şi rafinat
de atunci în diverse moduri de către acesta şi de mulţi alţi cercetători, ca un
model de date conceptual, pentru a uşura proiectarea bazelor de date. Pentru
reprezentarea grafică a modelului sunt utilizate diagramele E/R, care sunt
modele neformalizate pentru reprezentarea unui model, unui sistem din lumea
reală.
Diagramele E/R constituie o tehnică de reprezentare a structurii logice a
bazei de date, într-o manieră grafică. Aceste diagrame oferă un mijloc simplu şi
inteligibil de comunicare a caracteristicilor importante ale designului unei
anumite baze de date.
Diagrama E/R este un model de date conceptual de nivel înalt,
independent de platforma hardware utilizată şi de tipul SGBD-ului. Modelul
este constituit din concepte care descriu structura bazei de date şi tranzacţiile de
regăsire sau reactualzare asociate.
Popularitatea modelului E/R ca modalitate de abordare a proiectării
bazelor de date poate fi atribuită în principal tehnicii de realizare a diagramelor
E/R. Această tehnică, ca şi modelul E/R însuşi, a evoluat de-a lungul timpului
datorită noilor problematici care au apărut în proiectarea bazelor de date.

Baza de date poate fi definită ca o mulţime de date ce modelează un


sistem real. Acest sistem este format din obiecte legate între ele. Modelul
E/R împarte elementele unui sistem real în două categorii: entităţi şi relaţii
(legături, asocieri) între aceste entităţi. Entităţiile şi legăturile au anumite
caracteristici, numite atribute. Nu trebuie confundat conceptul de relaţie,
în sensul de asociere, care intervine în definirea diagramei E/R cu
conceptul de relaţie care este specific modelului relaţional.
Modelarea entitate-relaţie 59

Studiu de caz
Exemplele din acest capitol se referă la proiectarea unui model de date ce
furnizează informaţii despre prezentări de modă, evenimente care reprezintă
momente importante în lumea caselor de modă.
Vom prezenta modelul de date, restricţiile pe care trebuie să le respecte şi
vom încerca, într-o manieră didactică, să construim diagrama E/R
corespunzătoare. Vom considera, în abordarea iniţială, anumite situaţii care nu
sunt optime, în sensul că pot genera redundanţă, anomalii la reactualizări sau nu
permit rezolvarea anumitor interogări asupra modelului. Vom încerca să arătăm
care sunt deficienţele modelului, situaţiile care le-au generat şi cum pot fi
corectate (parţial sau total) anomaliile respective.
Modelul de date va gestiona informaţii legate de organizarea şi
funcţionarea prezentărilor de modă. Există firme organizatoare care se ocupă de
buna desfăşurare a acestor prezentări. O firmă organizatoare poate fi contactată
prin angajaţi specializaţi pe diferite domenii (financiar, social, publicitate,
securitate, sisteme de iluminare, coregrafie, sisteme de sonorizare, cazare,
primiri/plecări aeroport etc.).
Firme specializate sunt angajate pentru soluţionarea problemelor legate
de securitate, publicitate, asigurări, iar restul problemelor sunt rezolvate cu
salariaţii proprii ai caselor de modă şi a firmei organizatoare. Modalităţile de
securitate, asigurări, publicitate proprii caselor de modă, modelelor sau
agenţiilor de modele nu intră în proiectarea modelului.
Prezentările pot fi sponsorizate, considerându-se doar informaţiile
referitoare la persoane (fizice sau juridice) care au contribuit efectiv la
finanţarea prezentărilor de modă. Mai exact, nu sunt incluşi sponsorii posibili.
La aceste evenimente participă case de modă, care prezintă vestimentaţii
concepute de creatorii casei respective. Creatorii pot fi cei care concep
vestimentaţia (designeri) sau cei care o realizează efectiv, incluzând croitori,
lucrători care se ocupă cu broderia sau cu realizarea diverselor accesorii.
În cadrul prezentării de modă, vestimentaţiile sunt purtate de manechine
care aparţin anumitor agenţii de modele. Casele de modă angajează modele care
să le prezinte vestimentaţiile cu prilejul acestor evenimente. Modelul de date
prezintă şi un istoric al activităţii manechinelor (în cadrul diverselor agenţii).
Casele de modă angajează pentru o prezentare stilişti care se ocupă cu
machiajul şi coafura modelelor.
De asemenea, modelul analizează informaţii legate de localizarea şi
accesarea firmelor de publicitate, a persoanelor de contact din firmele
organizatoare, a caselor de modă, a agenţiilor şi a modelelor, a sponsorilor, a
societăţilor de asigurare şi a firmelor care asigură securitatea evenimentelor.
Modelul de date respectă anumite restricţii de funcţionare.
• Casele de modă pot fi organizatori de prezentări.
• Chiar dacă o casă de modă este organizator, ea apelează la serviciile
unei firme specializate în organizarea unor astfel de evenimente.
60 PROIECTAREA BAZELOR DE DATE
• Un model sau un stilist este angajat (temporar) pentru o prezentare, de
o singură casă de modă.
• O casă de modă poate angaja mai multe modele şi mai mulţi stilişti
pentru o prezentare.
• Orice prezentare de modă are un organizator unic, care poate apela la
serviciile altor instituţii specializate (securitate, asigurări, publicitate).
• Pentru organizator s-a considerat un singur cont în/din care se pot face
plăţile.
• O casă de modă poate avea mai mulţi designeri, dar un designer poate
lucra pentru o singură casă de modă.
• Pentru contactarea unei persoane fizice sau juridice s-a considerat câte
un singur număr de telefon fix, telefon mobil, fax şi o singură adresă de
mail.
• Pentru localizarea unei persoane fizice sau juridice s-a considerat o
singură adresă de bază.
• Sunt luaţi în considerare doar angajaţii firmei de pază şi protecţie care
participă efectiv la asigurarea securităţii prezentărilor de modă.
• Creatorii de accesorii pot fi angajaţi permanenţi ai unei case de modă.
Dacă pentru anumite vestimentaţii sunt necesare accesorii create de
specialişti care nu aparţin casei de modă, aceştia vor fi consideraţi
angajaţi special pentru evenimentul respectiv.
• S-a considerat că proprietarul unei case de modă fie este unic, fie, dacă
sunt mai mulţi, va fi considerat drept proprietar cel care deţine numărul
maxim de acţiuni.

Entitate
Entitatea este un obiect sau un concept, care este semnificativ pentru
modelul real analizat. O entitate poate fi dependentă (slabă), existenţa sa
depinzând de altă entitate sau independentă (tare), caz în care ea nu depinde de
existenţa altei entităţi.
Entitatea poate fi persoană, loc, concept, activitate etc. Prin urmare, ea
poate fi un obiect cu existenţă fizică, reală sau poate fi un obiect cu existenţă
conceptuală, abstractă.
Pentru o analiză didactică a problematicii abordate, construirea
diagramelor E/R, se vor considera şi aspecte ale modelului real analizat, care nu
apar în diagrama finală.
Pentru modelul de date referitor la prezentările de modă, structurile
PUBLICITATE, ORGANIZATOR, PERS_CONTACT, PREZENTARE,
SPONSOR, FIRMA_PUB, CASA_MODA, CREATOR, VESTIMENTATIE,
MODEL, ACCESORIU, LOCALIZARE, AGENTIE, ISTORIC, FIRMA_SEC,
ANGAJAT_SEC,SOCIETATE_ASIG, ANGAJAT_TEMP, INFO_CONTACT,
LOCATIE reprezintă entităţi.
Observaţii
• Entităţile devin tabele în modelele relaţionale.
• În general, entităţile se scriu cu litere mari.
Modelarea entitate-relaţie 61

• Entităţile sunt substantive, dar nu orice substantiv este o entitate.


Trebuie ignorate substantivele nerelevante.
• Cheia primară identifică unic o entitate şi face distincţie între valori
diferite ale entităţii. Aceasta trebuie să fie unică şi cunoscută la orice
moment. Cheia primară trebuie să fie controlată de administratorul
bazei, să nu conţină informaţii descriptive, să fie simplă, fără
ambiguităţi, să fie stabilă, să fie familiară utilizatorului astfel încât
acesta să o poată folosi cu uşurinţă.
• Pentru fiecare entitate este obligatoriu să se dea o descriere detaliată.
• Nu pot exista, în aceeaşi diagramă, două entităţi cu acelaşi nume, sau
o aceeaşi entitate cu nume diferite.
Vom prezenta entităţile modelului de date, dând o descriere completă a
fiecăreia. De asemenea, pentru fiecare entitate se va preciza cheia primară.
Toate entităţile care vor fi prezentate sunt independente, cu excepţia
entităţilor dependente ACCESORIU, ISTORIC şi a subentităţii MODEL.
ORGANIZATOR = firmă (persoană juridică) specializată, care se ocupă cu
organizarea şi buna desfăşurare a unei prezentări de modă. Ea poate apela la
societăţi specializate pentru rezolvarea problemelor ce apar în organizarea
prezentării de modă sau poate oferi servicii proprii pentru desfăşurarea optimă a
evenimentului. Cheia primară a entităţii este cod_organizator.
PERS_CONTACT = persoană fizică, aparţinând firmei organizatoare, care este
responsabilă cu un anumit domeniu de activitate specific organizării prezentării
de modă. Ea poate fi contactată pentru diversele probleme care privesc
prezentarea, fiind punctul de legătură dintre direcţiile din firma organizatoare şi
cele din societăţile externe, care se ocupă efectiv cu realizarea tuturor
problemelor ce apar în organizarea evenimentului. Atributul cod_pers_contact
reprezintă cheia primară a entităţii.
SPONSOR = persoană fizică sau juridică ce contribuie financiar sau în altă
manieră la desfăşurarea prezentării de modă. Cheia primară a acestei entităţi
este cod_sponsor.
FIRMA_PUB = persoană juridică ce asigură publicitatea evenimentului. Firma
organizatoare poate apela la mai multe firme de publicitate. Cheia primară a
acestei entităţi este cod_firma_pub.
PUBLICITATE = activitatea efectivă de publicitate asigurată de o firmă de
publicitate. Firmele de publicitate asigură diferite modalităţi de realizare a
publicităţii (presă, televiziune, radio etc.). Cheia primară a acestei entităţi este
cod_publicitate.
FIRMA_SEC = persoană juridică ce asigură securitatea prezentării de modă. Se
consideră că o singură firmă asigură securitatea evenimentului. Cheia primară a
acestei entităţi este cod_firma_sec.
62 PROIECTAREA BAZELOR DE DATE
ANGAJAT_SEC = persoană fizică, angajată a unei firme de securitate, care
participă efectiv la asigurarea serviciilor de pază şi protecţie a prezentărilor de
modă. Cheia primară a acestei entităţi este cod_angajat.
SOC_ASIG = persoană juridică responsabilă de asigurarea (din punctul de
vedere al societăţii organizatoare) tuturor activităţilor pe care le implică
prezentarea de modă. Se consideră că firma organizatoare apelează la o singură
societate de asigurări. Modelul de date nu ia în considerare asigurările făcute de
agenţiile de modele pentru angajatele sale, asigurările încheiate chiar de către
modele sau asigurările contractate de casele de modă. Cheia primară a acestei
entităţi este cod_soc_asig.
PREZENTARE = evenimentul efectiv al prezentării de modă. Modelul de date
consideră doar prezentări de modă semnificative din lumea caselor de modă.
Cheia primară a acestei entităţi este cod_prezentare.
CASA_MODA = persoană juridică a cărei activitate constă în crearea de
vestimentaţii şi accesorii pentru aceste vestimentaţii. Cheia primară a entităţii
este cod_casa_moda.
CREATOR = persoană fizică, angajată (permanent sau special) a unei case de
modă, care creează efectiv vestimentaţiile sau accesoriile acestora prezentate în
cadrul evenimentului respectiv. Cheia primară a entităţii este cod_creator.
VESTIMENTATIE = vestimentaţia concepută şi realizată de creatorii unei case
de modă. Cheia primară a entităţii este cod_vestimentatie.
ACCESORIU = entitate dependentă de VESTIMENTATIE, care conţine
informaţii referitoare la accesoriile unei anumite vestimentaţii. Cheia primară a
entităţii este compusă din cod_accesoriu şi cod_ vestimentatie.
ANGAJAT_TEMP = persoană fizică, angajată temporar pentru o anumită
prezentare de către o casă de modă, fie pentru realizarea machiajului şi a
coafurii modelelor care vor prezenta vestimentaţii în cadrul prezentării (stilist),
fie pentru a purta creaţiile acesteia la prezentarea respectivă (model). Cheia
primară a entităţii este cod_angajat_temp.
MODEL = subentitate a entităţii ANGAJAT_TEMP, ce conţine informaţii
specifice manechinelor. Cheia primară a entităţii este cod_angajat_temp.
AGENTIE = agenţia de modele care se ocupă cu gestionarea activităţilor
(participare la prezentări de modă, contracte pentru reclama diverselor produse
etc.) modelelor sale. Cheia primară a entităţii este cod_agentie.
ISTORIC = entitate dependentă de MODEL, care conţine istoricul angajărilor
unui model la diferite agenţii. Cheia primară a entităţii este compusă din
cod_model şi data_angajare.
LOCALIZARE = identifică localizarea unei persoane fizice (sponsor, persoană
de contact, model, creator, stilist), juridice (firmă de publicitate, securitate,
asigurări, organizator, casă de modă, agenţie de modele) sau eveniment
(prezentare de modă). Cheia primară a entităţii este cod_localizare.
Modelarea entitate-relaţie 63

LOCATIE = entitate care identifică locaţia în care se desfăşoară o anumită


prezentare de modă. Cheia primară a entităţii este cod_locatie.
INFO_CONTACT = identifică modalitatea de contact a unei persoane fizice
(sponsor, persoană de contact, angajat temporar, creator) sau juridice (firmă de
publicitate, securitate, asigurări, organizator, casă de modă, agenţie de modele).
Cheia primară a entităţii este cod_info_contact.

Relaţie
Relaţia (asocierea) este o comunicare între două sau mai multe entităţi. O
valoare a unei relaţii este o comunicare între valorile entităţilor pe care le leagă.
Relaţia exprimă un raport care există între aceste entităţi. Gradul unei
relaţii este dat de numărul de entităţi participante într-o relaţie (de exemplu,
relaţie binară, ternară, cvadruplă, n-ară).
Existenţa unei relaţii este subordonată existenţei entităţilor pe care le
leagă. Între două entităţi pot exista mai multe relaţii.
O relaţie în care aceeaşi entitate participă mai mult decât o dată în diferite
roluri defineşte o relaţie recursivă. Uneori, aceste relaţii sunt numite unare.
Observaţii
• În modelul relaţional, relaţiile devin tabele speciale sau coloane
speciale care referă chei primare.
• Relaţiile sunt verbe, dar nu orice verb este o relaţie.
• Pentru fiecare relaţie este important să se dea o descriere detaliată.
• În aceeaşi diagramă pot exista relaţii diferite cu acelaşi nume. În acest
caz, ele sunt diferenţiate de către entităţile care sunt asociate prin
relaţia respectivă.
• Pentru fiecare relaţie trebuie stabilită cardinalitatea (maximă şi
minimă) relaţiei, adică numărul de tupluri ce aparţin relaţiei.
Asupra entităţilor participante într-o relaţie pot fi impuse constrângeri
care trebuie să reflecte restricţiile care există în lumea reală asupra relaţiilor. O
clasă de constrângeri, numite constrângeri de cardinalitate, este definită de
numărul de înregistrări posibile pentru fiecare entitate participantă (raport de
cardinalitate). Cel mai întâlnit tip de relaţii este cel binar, iar în acest caz
rapoartele de cardinalitate sunt, în general, one-to-one (1:1), one-to-many (1:n)
sau many-to-many (m:n).
De exemplu, în modelul analizat este definită relaţia organizeaza care
leagă entităţile ORGANIZATOR şi PREZENTARE, relaţie care poate fi scrisă
sub forma ORGANIZATOR_organizeaza_PREZENTARE, pentru a percepe mai
uşor asocierile existente. Relaţia are cardinalitatea minimă 1:1 şi cardinalitatea
maximă 1:n.
Vom prezenta relaţiile modelului de date, dând o descriere completă a
fiecăreia. De fapt, denumirile acestor legături sunt sugestive, reflectând
64 PROIECTAREA BAZELOR DE DATE
conţinutul acestora şi entităţile pe care le leagă. Pentru fiecare relaţie se va
preciza cardinalitatea minimă şi maximă.
FIRMA_PUB_face_PUBLICITATE = relaţie care leagă entităţile FIRMA_PUB
şi PUBLICITATE, reflectând legătura dintre acestea (ce publicitate face o
anumită firmă de publicitate). Ea are cardinalitatea minimă 1:1 (o firmă de
publicitate trebuie să realizeze cel puţin o publicitate şi o publicitate trebuie
făcută de cel puţin o firmă de publicitate) şi cardinalitatea maximă 1:n (o firmă
de publicitate poate asigura mai multe publicităţi, iar o publicitate poate fi
făcută de o singură firmă specializată).
PUBLICITATE_se_face_PREZENTARE = relaţie care leagă entităţile
PUBLICITATE şi PREZENTARE, reflectând legătura dintre acestea (pentru o
prezentare, ce publicitate se face). Relaţia are cardinalitatea minimă 1:1 şi
cardinalitatea maximă 1:n.
ORGANIZATOR_are_PERS_CONTACT = relaţie dintre ORGANIZATOR şi
PERS_CONTACT, reflectând legătura dintre acestea (ce persoane din firma
organizatoare pot fi contactate pentru soluţionarea diverselor probleme). Ea are
cardinalitatea minimă 1:1 şi cardinalitatea maximă 1:n.
FIRMA_SEC_are_ANGAJAT_SEC = relaţie dintre entităţile FIRMA_SEC şi
ANGAJAT_SEC, reflectând legătura dintre acestea (ce angajaţi, implicaţi în
acţiunea de pază a prezentărilor de modă, au firmele de securitate). Ea are
cardinalitatea minimă 1:1 şi cardinalitatea maximă 1:n.
ANGAJAT_SEC_paza_PREZENTARE = relaţie de tip many-to-many dintre
entitatea PREZENTARE şi ANGAJAT_SEC, reflectând legătura dintre acestea
(ce angajaţi ai firmei de securitate asigură buna desfăşurare a prezentărilor de
modă). Ea are cardinalitatea minimă 1:1 şi cardinalitatea maximă m:n.
SOC_ASIG_asigura_PREZENTARE = relaţie dintre entitatea PREZENTARE şi
SOC_ASIG, reflectând legătura dintre acestea (ce societate este angajată pentru
asigurarea diverselor aspecte din cadrul prezentării de modă). Ea are
cardinalitatea minimă 1:1 şi cardinalitatea maximă 1:n.
CASA_MODA_participa_PREZENTARE = relaţie de tip many-to-many dintre
entităţile CASA_MODA şi PREZENTARE (ce case de modă participă la
prezentări). Ea arată şi dacă respectivele case participă, sau nu, ca organizator la
prezentari. Relaţia are cardinalitatea minimă 1:1 şi cardinalitatea maximă m:n.
CASA_MODA_lucreaza_CREATOR = relaţie dintre entităţile CASA_MODA şi
CREATOR (la ce case de modă lucrează creatorii). Relaţia are cardinalitatea
minimă 1:1 şi cardinalitatea maximă 1:n.
CREATOR_creeaza_VESTIMENTATIE = relaţie dintre entităţile CREATOR şi
VESTIMENTATIE (ce creatori realizează vestimentaţiile). Relaţia are
cardinalitatea minimă 1:0 şi cardinalitatea maximă1:n.
Modelarea entitate-relaţie 65

VESTIMENTATIE_are_ACCESORIU = relaţie dintre entităţile ACCESORIU şi


VESTIMENTATIE (ce accesorii au vestimentaţiile). Relaţia are cardinalitatea
minimă 1:0 şi cardinalitatea maximă 1:n.
MODEL_prezintă_VESTIMENTATIE = relaţie ce leagă entităţile MODEL şi
VESTIMENTATIE (ce vestimentaţii au fost purtate de modele). Relaţia are
cardinalitatea minimă 1:1 şi cardinalitatea maximă 1:n.
CREATOR_face_ACCESORIU = relaţie ce leagă entităţile CREATOR şi
ACCESORIU (ce creatori au realizat accesoriile). Relaţia are cardinalitatea
minimă 1:0 şi cardinalitatea maximă 1:n.
PREZENTARE_prezinta_VESTIMENTATIE = relaţie care leagă entităţile
PREZENTARE şi VESTIMENTATIE (ce vestimentaţii au fost prezentate la
evenimentele de modă). Relaţia are cardinalitatea minimă 1:1 şi cardinalitatea
maximă 1:n.
PREZENTARE_are_LOCATIE = relaţie ce leagă entităţile PREZENTARE şi
LOCATIE (ce prezentări de modă se desfăşoară într-o locaţie). Deoarece într-o
locaţie pot să fie mai multe prezentări, relaţia are cardinalitatea minimă 1:1 şi
cardinalitatea maximă n:1.
MODEL_lucreaza_AGENTIE = relaţie dintre entităţile MODEL şi AGENTIE
(la ce agenţie este angajat un model). Relaţia are cardinalitatea minimă 1:1 şi
cardinalitatea maximă n:1.
MODEL_are_ISTORIC = relaţie dintre entităţile MODEL şi ISTORIC (istoricul
activităţii unui model, prin diferite agentii). Relaţia are cardinaliatea minimă 1:0
şi cardinalitatea maximă 1:n.
ISTORIC_refera_AGENTIE = relaţie ce leagă entităţile ISTORIC şi AGENTIE
(la ce agenţie se referă fiecare înregistrare din istoricul unui model). Relaţia are
cardinalitatea minimă 1:1 şi cardinalitatea maximă 1:n.
SPONSOR_finanteaza_PREZENTARE = relaţie de tip many-to-many dintre
entităţile SPONSOR şi PREZENTARE, reflectând legătura dintre acestea (ce
sponsori finanţează prezentările de modă). Relaţia are cardinalitatea minimă 0:1
şi cardinalitatea maximă m:n.
PERS_CONTACT_are_LOCALIZARE = relaţie ce leagă entităţile
LOCALIZARE şi PERS_CONTACT (localizarea unei persoane de contact).
Ţinând cont de restricţiile impuse modelului, relaţia are cardinalitatea minimă
1:1 şi cea maximă 1:1. O astfel de relaţie este definită şi pentru entităţile
FIRMA_PUB, FIRMA_SEC, PREZENTARE, ORGANIZATOR,
CASA_MODA, SPONSOR, ANGAJAT_TEMP, SOC_ASIG, CREATOR,
LOCATIE şi AGENTIE, care sunt legate de entitatea LOCALIZARE,
permiţând astfel localizarea tuturor structurilor modelului.
PERS_CONTACT_are_INFO_CONTACT = relaţie care leagă
INFO_CONTACT şi PERS_CONTACT (modalitatea de accesare a unei
persoane de contact). Ţinând cont de restricţiile impuse modelului, relaţia are
cardinalitatea minimă 1:1 şi cea maximă 1:1. O astfel de relaţie este definită şi
66 PROIECTAREA BAZELOR DE DATE
pentru entităţile FIRMA_PUB, FIRMA_SEC, ORGANIZATOR,
CASA_MODA, SPONSOR, ANGAJAT_TEMP, SOC_ASIG, CREATOR,
LOCATIE şi AGENTIE, care sunt legate de entitatea INFO_CONTACT,
permiţând astfel accesarea tuturor structurilor modelului.
ANGAJAT_TEMP_primeste_la_PREZENTARE_de_la_CASA_MODA = relaţie
de tip 3 ce leagă entităţile ANGAJAT_TEMP, PREZENTARE şi
CASA_MODA, reflectând cine a fost angajat temporar, de ce casă de modă,
pentru ce prezentare. Denumirea acestei relaţii va fi primeste.
Atribut
Atributul este o proprietate descriptivă a unei entităţi sau a unei relaţii. De
exemplu, numele unei case de modă este un atribut al entităţii CASA_MODA,
iar data la care o casă de modă participă la o prezentare este un atribut al relaţiei
participă ce leagă entităţile PREZENTARE şi CASA_MODA.
Atributele pot fi simple (de exemplu, suma cu care este plătit un model de
către o casă de modă pentru o prezentare), compuse (de exemplu, adresa unei
firme de publicitate), cu valori multiple (de exemplu, numerele de telefon ale
unei persoane de contact), derivate (de exemplu, vârsta unei persoane se obţine
din data naşterii).
Observaţii
• Trebuie făcută distincţia între atribut care uzual devine coloană în
modelele relaţionale şi valoarea acestuia, care devine valoare în coloane.
• Atributele sunt substantive, dar nu orice substantiv este atribut.
• Fiecărui atribut trebuie să i se dea o descriere completă în
specificaţiile modelului (exemple, contraexemple, caracteristici).
• Pentru fiecare atribut trebuie specificat numele, tipul fizic (integer,
float, char etc.), valori posibile, valori implicite, reguli de validare,
constrângeri, tipuri compuse.
În continuare vor fi prezentate, parţial, atributele entităţilor şi relaţiilor
dând o descriere a fiecăruia, a caracteristicilor şi a constrângerilor pe care
trebuie să le îndeplinească. Semnificaţia unor atribute a căror denumire nu este
semnificativă sau care include mai multe caracteristici decât denumirea va fi
comentată pe parcursul lucrării.
Entitatea independentă ANGAJAT_TEMP are ca atribute:
cod_angajat_temp = variabilă de tip întreg, de lungime maximă 5, care
reprezintă codul unui angajat temporar.
nume = variabilă de tip caracter, de lungime maximă 25, care reprezintă numele
angajatului.
prenume = variabilă de tip caracter, de lungime maximă 25, care reprezintă
prenumele angajatului.
data_nastere = variabilă de tip dată calendaristică, care reprezintă data naşterii
angajatului respectiv.
sex = variabilă de tip caracter, luând valorile m sau f, de lungime 1, care
reprezintă sexul angajatului.
Modelarea entitate-relaţie 67

nationalitate = variabilă de tip caracter, de lungime maximă 12, care reprezintă


naţionalitatea unui angajat temporar.
cod_localizare = variabilă de tip întreg, de lungime maximă 5, care reprezintă
codul localizării angajatului. Atributul trebuie să corespundă la o valoare a cheii
primare din tabelul LOCALIZARE.
cod_info_acces = variabilă de tip caracter, de lungime maximă 5, care
reprezintă codul informaţiei de acces pentru angajatul respectiv. Atributul
trebuie să corespundă la o valoare a cheii primare din tabelul
INFO_CONTACT.
tip = variabilă de tip caracter, de lungime 10, care reprezintă funcţia pentru care
a fost angajată persoana respectivă. De exemplu, poate să fie model, stilist sau
eventual poate lua alte valori.
Subentitatea MODEL are ca atribute:
cod_angajat_temp = variabilă de tip întreg, de lungime maximă 5, care
reprezintă codul modelului.
cod_agentie = variabilă de tip întreg, de lungime maximă 5, care reprezintă
codul agenţiei la care este angajat în prezent modelul. Atributul trebuie să
corespundă la o valoare a cheii primare din tabelul AGENTIE.
inaltime = variabilă de tip numeric, de lungime 3, care reprezintă înălţimea
modelului în centimetri.
nr_pantof = variabilă de tip numeric (real), care reprezintă numărul pe care îl
poartă la pantof modelul respectiv.
info = variabilă de tip text, care include informaţii speciale despre model
(dimensiuni, greutate, preferinţe, elemente confidenţiale, palmares etc.).
Entitatea PUBLICITATE are atributele: cod_publicitate, cod_firma_pub,
cod_prezentare, tip, nume, suma, observatii. Atributul tip poate lua valorile
radio, televiziune, presa, panouri publicitare etc. Atributul nume este legat de
atributul tip în sensul că poate reprezenta numele postului de radio, al celui de
televiziune, al publicaţiei care face publicitatea.
Entitatea FIRMA_PUB are atributele: cod_firma_pub, nume, info, director,
observatii, nume_pers_contact, cod_localizare, cod_info_acces.
Entitatea ORGANIZATOR are atributele: cod_organizator, denumire, banca,
cont, informatii, cod_localizare, cod_info_acces.
Entitatea PERS_CONTACT are atributele: cod_pers_contact, cod_organizator,
nume, prenume, directie, cod_localizare, cod_info_acces.
Entitatea PREZENTARE are atributele: cod_prezentare, denumire, data_start,
data_final, cod_organizator, cod_soc_asig, cod_locatie.
Entitatea SPONSOR are atributele: cod_sponsor, tip, nume, info, cod_localizare,
cod_info_acces. Atributul tip poate lua valorile persoana fizică sau persoana
juridică. În primul caz, atributul nume va reprezenta numele şi prenumele
persoanei fizice, iar în cel de al doilea caz, va reprezenta numele societăţii.
68 PROIECTAREA BAZELOR DE DATE
Entitatea CASA_MODA are atributele: cod_casa_moda, nume, cifra_afaceri,
proprietar, director, istoric, data_creare, cod_localizare, cod_info_acces.
Entitatea CREATOR are atributele: cod_creator, nume, prenume, data_nastere,
data_angajare, cod_casa_moda, tip, mod_angajare, info, cod_localizare,
cod_info_acces. Atributul tip poate lua valorile designer, croitor, broder,
creator_accesorii. Atributul mod_angajare poate lua valorile permanent sau
special.
Entitatea VESTIMENTATIE are atributele: cod_vestimentatie, denumire,
valoare, descriere, cod_creator, cod_model, cod_prezentare.
Entitatea ACCESORIU are atributele: cod_vestimentatie, cod_accesoriu, tip,
descriere, valoare, cod creator.
Entitatea AGENTIE are atributele: cod_agentie, nume, data_creare, director,
cifra_afaceri, info, cod_localizare, cod_info_acces.
Entitatea ISTORIC are atributele: cod_model, data_angajare, data_final,
cod_agentie, conditii.
Entitatea LOCALIZARE are atributele: cod_localizare, adresa, cod_postal, oras,
tara.
Entitatea LOCATIE are atributele: cod_locatie, denumire, tip, capacitate,
cod_localizare, cod_info_acces. Atributul tip reprezintă tipul locaţiei respective
şi poate lua valorile: hotel, esplanadă, teatru, mall etc.
Entitatea INFO_CONTACT are atributele: cod_info_contact, telefon_mobil,
mail, telefon_fix, fax.
Entitatea FIRMA_SEC are atributele: cod_firma_sec, nume_firma, tip_servicii,
director, observatii, cod_localizare, cod_info_acces.
Entitatea ANGAJAT_SEC are atributele cod_angajat, nume, prenume,
data_nastere, specializare, nivel, observatii, cod_localizare, cod_firma_sec,
cod_info_acces.
Entitatea SOC_ASIG are atributele: cod_soc_asig, conditii, suma, director,
observatii, nume_pers_contact_firma, cod_localizare, cod_info_acces.
Relaţia CASA_MODA_participa_PREZENTARE are ca atribute:
cod_prezentare = variabilă de tip întreg, de lungime maximă 5, care reprezintă
codul prezentării. Atributul trebuie să corespundă la o valoare a cheii primare
din tabelul PREZENTARE.
cod_casa_moda = variabilă de tip întreg, de lungime maximă 5, care reprezintă
codul casei de modă. Atributul trebuie să corespundă la o valoare a cheii
primare din tabelul CASA_MODA.
tip = variabilă de tip caracter, de lungime maximă 15, care reprezintă
modalitatea în care o casă de modă participă la o prezentare, în sensul că poate
fi organizator sau neorganizator.
Modelarea entitate-relaţie 69

data = variabilă de tip dată calendaristică reprezentând ziua în care defilează


modelele casei de modă. Atributul nu este multiplu, deoarece s-a presupus că
defilarea unei case de modă are loc într-o singură zi.
Relaţia SPONSOR_finanteaza_PREZENTARE are ca atribute: cod_sponsor,
cod_prezentare, data_emitere, suma, banca, cont_emitent, cod_ordin_plata.
Relaţia ANGAJAT_SEC_paza_PREZENTARE are atributele: cod_angajat,
cod_prezentare, tip_paza, dotare, observaţii.
Relaţia ANGAJAT_TEMP_primeste_la_PREZENTARE_de_la_CASA_MODA
are ca atribute: cod_angajat_temp, cod_casa_moda, cod_prezentare suma,
data_achitare, cont, banca.
Nu s-au introdus atributele cont şi banca la entitatea ANGAJAT_TEMP,
deoarece modelul de date nu-şi propune să furnizeze informaţii complete
referitoare la toate conturile şi băncile modelelor, stiliştilor etc. Se consideră
doar banca şi contul în care casa de modă depune bani pentru prezentarea la
care aceştia au fost angajaţi.

2.3. Diagrama entitate- relaţie

Pentru proiectarea diagramei entitate-relaţie au fost stabilite anumite


reguli (care nu sunt unice):
• entităţile sunt reprezentate prin dreptunghiuri;
• relaţiile dintre entităţi sunt reprezentate prin arce neorientate;
• atributele care reprezintă chei primare trebuie subliniate sau marcate
prin simbolul „#“, plasat la sfârşitul numelui acestor atribute;
• cardinalitatea minimă este indicată în paranteze, iar cardinalitatea
maximă se scrie fără paranteze;
• nu este necesar să fie specificate, în cadrul diagramei, toate atributele.
Vom comenta câteva cazuri speciale de entităţi, relaţii, atribute şi modul
lor de reprezentare în cadrul diagramei entitate-relaţie.
• Dependenţa. Există entităţi, numite entităţi dependente care nu pot
exista în mod independent. De exemplu, se observă că entitatea
ACCESORIU depinde de VESTIMENTATIE, iar LOCATIE depinde
de entitatea PREZENTARE. Cheia primară a unei entităţi dependente
include cheia primară a sursei (cod_vestimentatie) şi cel puţin o
descriere a entităţii (cod_accesoriu). Entitatea dependentă se dese-
nează prin dreptunghiuri cu linii mai subţiri.
• Moştenirea atributelor. O subentitate (subclasă) este o submulţime
a unei alte entităţi, numită superentitate (superclasă). De exemplu,
ANGAJAT_TEMP este o superentitate pentru MODEL, iar MODEL
este o subentitate pentru ANGAJAT_TEMP. Subentitatea se
desenează prin dreptunghiuri incluse în superentitate. Există o relaţie
70 PROIECTAREA BAZELOR DE DATE
între o subentitate şi o superentitate, numită ISA, care are
cardinalitatea maximă 1:1 şi minimă 1:0.
• Cheile primare, atributele şi relaţiile unei superentităţi sunt valabile
pentru orice subentitate. Afirmaţia reciprocă este falsă. De exemplu,
un informatician, considerat ca subentitate a entităţii
PERS_CONTACT, poate avea ca atribute limbajele de programare
cunoscute şi nivelul de cunoaştere a acestora, dar aceste atribute nu
sunt semnificative pentru o persoană de contact care coordonează
asigurarea securităţii prezentării de modă. Cheia primară a subentităţii
INFORMATICIAN este cod_pers_contact, care este cheia primară a
superentităţii PERS_CONTACT.
• Specializare. După valorile unor atribute clasificatoare se pot
determina clase. Un grup de subentităţi reciproc exclusive defineşte o
clasă. Clasele se aliniază în desen vertical. De exemplu, pentru
entitatea PUBLICITATE, după valorile atributului tip, pot fi definite
subentităţile PANOURI_PUBLICITARE, PRESA, TELEVIZIUNE,
RADIO, fiecare având atributele sale proprii.
• Generalizare. Din entităţi similare care au mai multe atribute comune
se pot crea superentităţi. Aceste superentităţi conţin atributele comune,
iar atributele speciale sunt asignate la subentităţi. Pentru noile
superentităţi se introduc chei primare artificiale. De exemplu, din
entităţile FIRMA_PUB, FIRMA_SEC şi SOC_ASIG se poate crea
superentitatea FIRMA având drept atribute: cod_firma (cheie primară
artificială), informaţii de accesare, informaţii de localizare, director,
observatii.
• Într-o diagramă E/R se pot defini relaţii recursive. De exemplu, poate
fi definită relaţia PERS_CONTACT_supervizeaza_PERS_CONTACT.
• Unele relaţii sunt relative la două entităţi şi le numim de tip 2, iar dacă
relaţiile implică mai mult de două entităţi, le vom numi de tip 3. Trei
relaţii de tip 2 sunt diferite de o relaţie de tip 3. Rupând o relaţie de tip
3 în trei relaţii de tip 2, poate să apară informaţie incorectă.
• Trebuie excluse din model relaţiile indirecte pentru că ele pot conduce
la redundanţă în baza de date.
• Atributele derivabile trebuie eliminate şi introduse expresii prin care
aceste atribute pot fi calculate.
• Uneori apare o incertitudine referitoare la faptul că o anumită
informaţie poate fi considerată o relaţie sau un atribut. O relaţie poate
fi reprezentată ca un atribut, sau putem folosi relaţii în loc de atribute.
Dacă un atribut al unei entităţi reprezintă cheia primară a unei alte
entităţi, atunci el referă o relaţie.
• Uneori este greu de stabilit dacă informaţia analizată reprezintă o
entitate sau o relaţie. Dacă există o incertitudine, se cercetează cheia
primară. Dacă această cheie combină cheile primare a două entităţi,
atunci se defineşte o relaţie. Cheia primară a relaţiei organizeaza
Modelarea entitate-relaţie 71

combină atributele cod_organizator şi cod_prezentare, care reprezintă


cheile primare ale entităţilor ORGANIZATOR şi PREZENTARE.
Prin urmare, ORGANIZATOR_organizeaza_PREZENTARE va defini
o relaţie şi nu o entitate.
• Un atribut indirect este inoportun. El nu descrie real relaţia sau
entitatea. Prin urmare, atributele indirecte trebuie reasignate. De fapt,
un atribut indirect este un caz special de relaţie indirectă care trebuie
eliminată pentru că introduce redundanţă în date.
• Există atribute opţionale, a căror valoare este uneori necunoscută,
alteori neaplicabilă. Aceste atribute trebuie introduse la subentităţi.
Algoritmul pentru proiectarea diagramei E/R cuprinde următoarele etape:
1. identificarea entităţilor din cadrul sistemului analizat;
2. identificarea relaţiilor (asocierilor) dintre entităţi şi stabilirea cardi-
nalităţii;
3. identificarea atributelor aferente entităţilor şi asocierilor dintre
entităţi;
4. stabilirea atributelor de identificare a entităţilor, adică stabilirea
cheilor.
Relaţiile reflectă legături naturale care există între componentele
sistemului. Aceeaşi realitate poate fi însă percepută diferit de către diverşi
analişti pentru un acelaşi sistem, putând fi obţinute modele structurale distincte.
O diagramă E/R pentru modelul comentat în această secţiune este reprezentată
în figura 2.1. Diagrama este corectă, dar este optimizabilă.
Construirea diagramei conceptuale, obţinerea schemelor relaţionale şi
normalizarea acestora vor genera un model relaţional care va elimina anumite
clase de anomalii ce pot să apară în proiectarea modelului de date.

Deficienţe ale modelului E/R


În proiectarea unui model de date pot apărea diverse probleme datorită
unei interpretări eronate a sensului unei relaţii. Aceste probleme sunt denumite
capcane de conectare.
Unele dintre aceste capcane pot să nu fie semnificative pentru modelul
particular considerat, în timp ce altele cer restructurarea modelului. Există două
clase importante de capcane: de întrerupere şi în evantai.
O capcană de întrerupere poate să apară acolo unde modelul sugerează
existenţa unei relaţii între entităţi, dar nu există o cale între anumite apariţii ale
entităţilor. Această capcană poate să apară acolo unde există o relaţie cu
participare parţială (0 la cardinalitatea minimă), care face parte din calea dintre
entităţile ce sunt legate.
O capcană în evantai poate să apară acolo unde modelul ia în considerare
o relaţie între entităţi, dar calea dintre anumite apariţii ale entităţilor este
ambiguă. Aceste capcane apar când două sau mai multe relaţii one_to_many
provin din aceeaşi entitate.
72 PROIECTAREA BAZELOR DE DATE

INFO_CONTACT
1
FIRMA_PUB are
1 1
are M(1)
face ORGANIZATOR 1 PERS_CONTACT
1 M(1)
M(1) are
M(1)
PUBLICITATE 1
organizeaza LOCALIZARE
FIRMA SEC LOCATIE
1 se_face
1
are are
M(1) M(1) M(1)
M(1) paza M(1) 1 M(1) finanteaza M(0)
ANGAJAT SEC PREZENTARE SPONSOR
M(1) 1 M(1)

1 asigura participa
SOC ASIG

M(1)
CASA_MODA primeste
prezinta 1
lucreaza
ANGAJAT_TEMP
M(1)
1 CREATOR MODEL 1(0) ISA 1
1 1 1 M(1)
creeaza prezinta
lucreaza_la
M(1) M(0) 1
face VESTIMENTATIE M(1) are AGENTIE
1 1
are refera
M(0) M(0)
M(0) ISTORIC M(1)
ACCESORIU

Fig. 2.1. Diagrama E/R.

Practic, aceste capcane generează situaţiile în care, aşa cum a fost


proiectat modelul de date, el nu poate să răspundă la anumite interogări. De
exemplu, pentru a afla pentru ce prezentare de modă a fost creată o anumită
vestimentaţie, a fost necesară introducerea unei legături între entităţile
PREZENTARE şi VESTIMENTATIE, care însă a generat redundanţă în
modelul de date.
Modelul E/R extins
Conceptele de bază ale modelării entitate-relaţie nu sunt suficiente pentru
a reprezenta cerinţele aplicaţiilor actuale, care sunt mult mai complexe. Au fost
propuse, în acest sens, mai multe modele de date semantice. Modelul E/R
susţinut cu concepte semantice adiţionale defineşte modelul E/R extins (EER).
Modelarea entitate-relaţie 73

Acesta include toate conceptele modelului original, împreună cu conceptele


adiţionale de specializare, generalizare şi categorie. Aceste noi concepte au fost
deja nominalizate în acest capitol.
Superclasa (superentitatea) este o entitate care include subclase
(subentităţi) distincte, ce trebuie reprezentate în modelul de date. Subclasa are
un rol distinct şi, evident, este membră a unei superclase. O subclasă, fiind o
entitate, poate să posede propriile subclase. O entitate împreună cu subclasele
ei, subclasele acestora şi aşa mai departe defineşte o ierarhie de tip (ierarhie de
specializare). De exemplu, ANGAJAT_TEMP reprezintă o superclasă pentru
entitatea MODEL.
Specializarea este procesul de maximizare a diferenţelor dintre membrii
unei entităţi, prin identificarea caracteristicilor distinctive ale acestora.
Specializarea constituie o abordare de sus în jos în definirea unei mulţimi de
superclase şi a subclaselor lor. Pot exista diverse specializări ale aceleiaşi
entităţi, bazate pe diferite caracteristici de diferenţiere.
Dacă subclasele unei specializări sunt disjuncte, atunci o entitate poate fi
membră doar a unei subclase a acesteia (constrângere de disjuncţie).
O specializare cu participare totală specifică faptul că fiecare entitate din
superclasă trebuie să fie membră a unei subclase din specializare (constrângere
de participare).
De exemplu, specializarea contractelor de angajare poate fi cu participare
totală dacă fiecare angajat din PERS_CONTACT este fie angajat cu contract
permanent cu normă întreagă, fie cu contract temporar cu normă incompletă.
O specializare cu participare parţială specifică faptul că nu este necesar ca
o entitate să aparţină vreunei subclase a acesteia. De exemplu, există salariaţi în
PERS_CONTACT care nu aparţin niciunei subentităţi ale acesteia.
Generalizarea este procesul de minimizare a diferenţelor dintre entităţi,
prin identificarea caracteristicilor comune ale acestora. Generalizarea reprezintă
o abordare de jos în sus, care are ca rezultat identificarea unei superclase
generalizate din subclasele iniţiale.
Orice relaţie superclasă/subclasă (inclusiv cele ale unei subclase
partajate) dintr-o ierarhie de specializare/generalizare are o singură superclasă.
Totuşi, anumite situaţii necesită modelarea unei relaţii superclasă/subclasă cu
mai mult decât o superclasă distinctă. În acest caz, subclasa defineşte o
categorie. Categoria este procesul de modelare a unei singure subclase, cu o
relaţie care implică mai mult decât o singură superclasă distinctă.

2.4. Modelare orientată pe obiecte cu UML

Un limbaj de modelare reprezintă o modalitate de a comunica despre un


sistem şi de a exprima diversele modele produse în cadrul procesului de analiză
şi dezvoltare a sistemului. Limbajul furnizează o notaţie care permite
reprezentarea unui design.
74 PROIECTAREA BAZELOR DE DATE
Limbajul este format dintr-un set de concepte, principii şi reguli de
utilizare a acestora, cu scopul de a reprezenta modelele produse în diferite etape
de dezvoltare a sistemului. Fără un limbaj de modelare, este dificilă colaborarea
şi comunicarea dintre membrii echipei pe parcursul proiectării sistemului.
Ca orice limbaj, un limbaj de modelare are o sintaxă şi o semantică, iar
pentru semantica modelului trebuie aleasă sintaxa cea mai expresivă. De cele
mai multe ori, un limbaj de modelare este un limbaj grafic (diagramatic).
Dacă pentru utilizatori, limbajele de modelare uşurează munca de
realizare a sistemelor software, pentru realizatorii acestora sarcinile sunt
multiple şi dificile. Pentru ca un limbaj de modelare să se impună, el trebuie să
asigure o bună specificare a conceptelor sale şi a modului de reprezentare a
acestora. În acest scop, limbajele trebuie să asigure suport pentru modelatori, în
vederea rafinării treptate a soluţiei şi a captării semanticii procesului.
The Unified Modeling Language (UML) este, aşa cum semnifică şi
numele, un limbaj vizual de modelare şi de comunicare despre sistem. UML nu
este un limbaj de programare, deoarece nu dispune de întreg sprijinul semantic
şi vizual pentru a defini un astfel de limbaj. înlocui limbajele de programare.
UML este un limbaj pentru modelarea orientată pe obiecte, cu suport pentru
modelare vizuală, funcţionând ca o modalitate de a comunica şi de a exprima
cunoştinţe.
UML este un limbaj grafic de modelare pentru specificarea, vizualizarea,
construcţia şi documentarea componentelor unui sistem software (pentru
întreprinderi, telecomunicaţii, sisteme bancare şi financiare, transporturi etc.)
sau pentru modelarea organizaţională a unor sisteme non-software (din justiţie,
medicină, afaceri etc.).
UML nu este un limbaj de programare, dar modelele exprimate în UML
pot fi implementate uşor în limbaje de programare orientate pe obiecte (C++,
Java, C#) sau în baze de date relaţionale. Este posibilă nu numai generarea
codului dintr-un model UML, dar şi ingineria inversă, constând în construirea
dintr-un cod dat a unui model UML.
UML este un limbaj de modelare pentru documentare, deoarece permite
realizarea tuturor documentelor necesare înţelegerii modelului şi diagramelor
utilizate pe tot parcursul ciclului de viaţă al unui proces de realizare a unui
sistem. Documentele componentelor sistemului conţin specificarea cerinţelor,
arhitecturii şi proiectării sistemului; elaborarea codului sursă, planuri de
dezvoltare şi de management al proiectului.
În concluzie, UML nu este un limbaj de programare vizual, dar este un
model de limbaj de modelare vizual; nu este o metodologie, dar este o notaţie
pentru aceasta; nu este un proces, dar oferă suport complet pentru construcţia şi
dezvoltarea acestuia.
Este important de menţionat că UML este un limbaj de modelare, şi nu o
metodă. Majoritatea metodelor conţin atât un limbaj de modelare, cât şi un
proces. Limbajul de modelare furnizează, după cum am mai subliniat, doar
notaţia pentru reprezentarea unui design. Procesul cuprinde, însă, paşii care
trebuie să fie urmaţi pentru a realiza un design.
Modelarea entitate-relaţie 75

UML cuprinde tehnici specifice mai multor metode de dezvoltare


(proiectare) şi este suficient de logic, de expresiv pentru a putea fi utilizat
împreună cu orice metodă sau proces de dezvoltare.
Ca orice limbaj, UML are sintaxa şi semantica sa. Cu ajutorul alfabetului
şi al cuvintelor limbajului, se pot scrie propoziţii (fragmente din diagrame)
despre subiectul de analizat. Propoziţiile se pot grupa în paragrafe (diagrame
UML).
Paragrafele, la rândul lor, se pot grupa în secţiuni (moduri de vizualizare)
şi, în final, secţiunile se pot organiza în documente. Documentele UML sunt
modelele sistemului.
Sintaxa limbajului UML implică diagrame, în timp ce semantica lui se
bazează pe paradigma orientării pe obiecte. Din punct de vedere al modelării
orientate pe obiecte, entităţile (conceptele) se numesc clase, iar relaţiile dintre
ele se numesc asocieri.
Diagrama este o reprezentare grafică a unei mulţimi de elemente, de
obicei folosindu-se forme geometrice pentru a reprezenta entităţi şi linii pentru a
reprezenta asocieri. În UML, diagrama este o proiecţie a sistemului,
reprezentând o parte a sistemului sau chiar întregul sistem dintr-un anumit punct
de vedere. Acelaşi element poate apărea în toate diagramele, în câteva diagrame
sau în nicio diagramă.
UML conţine 9 tipuri de diagrame, fiecare reflectând una sau mai multe
dintre cele 5 tipuri de vizualizări posibile asupra unui sistem software.
• Diagrama claselor descrie structura unui sistem în general. În
componenţa ei intră clase, stereotipuri şi relaţiile dintre acestea.
• Diagrama obiectelor descrie structura unui sistem la un anumit
moment. Acest tip de diagramă este o variantă a diagramei claselor
care, în locul unei clase, prezintă mai multe instanţe ale ei, fiind
formată din obiecte şi legături dintre ele.
• Diagrama cazurilor de utilizare descrie funcţionalitatea unui sistem,
prezentând actorii externi, cazurile de utilizare identificate numai din
punct de vedere al actorilor (comportamentul sistemului, aşa cum este
perceput de utilizatorii lui), precum şi relaţiile dintre actori şi cazurile
de utilizare. Un actor poate fi orice sau oricine interacţionează cu
sistemul (trimite sau recepţionează mesaje de la sistem sau schimbă
informaţii cu acesta). Actorul are un rol în cadrul unui sistem, nu este
un utilizator individual al acestuia şi, din acest motiv, el este o entitate
(o clasă), nu o instanţă. Un caz de utilizare este iniţiat mereu de un
actor şi furnizează o valoare actorului.
• Diagrama componentelor (diagrama de implementare) descrie
structura fizică a codului în termenii componentelor de cod şi relaţiilor
dintre acestea.
• Diagrama de desfăşurare (de exploatare) indică arhitectura fizică pe
care este implementat sistemul, calculatoarele, nodurile sistemului şi
conexiunile dintre ele.
76 PROIECTAREA BAZELOR DE DATE
• Diagrama secvenţelor este o diagramă de interacţiune, care prezintă
colaborarea dinamică dintre un număr de obiecte, punând accentul pe
secvenţele de mesaje trimise între acestea pe măsura scurgerii
timpului.
• Diagrama de colaborare este tot o diagramă de interacţiune, dar care,
pe lângă interacţiunea dintre obiecte (schimbul de mesaje), prezintă
obiectele şi legăturile dintre ele.
• Diagrama de stare descrie ciclul de viaţă al unui element (al
obiectelor, subsistemelor şi sistemelor), prin specificarea stărilor în
care se găseşte elementul şi a evenimentelor care îi modifică starea.
• Diagrama de activitate prezintă activităţile şi responsabilităţile
elementelor sistemului, fiind utilizată pentru modelarea funcţiilor
sistemului. Ea are ca elemente constitutive stări de acţiune şi mesaje
care vor fi trimise sau recepţionate ca parte a acţiunii realizate.
În UML, diagramele fac parte din două categorii.
• Diagrame dinamice sau comportamentale – descriu comportamentul
şi interacţiunile dintre diverse entităţi ale sistemului informatic. Din
această categorie, fac parte diagramele de secvenţă, colaborare, stare şi
activitate.
• Diagrame statice sau structurale - descriu structura, responsabilităţile
sistemului informatic, componentele executabile ale sistemului,
locaţiile fizice de execuţie şi nodurile de stocare a datelor. Din această
categorie, fac parte diagramele claselor, obiectelor, cazurilor de
utilizare, componentelor şi diagramele de exploatare.
Pe lângă structura statică şi comportamentul dinamic, pentru
caracterizarea completă a unui sistem este necesară şi funcţionalitatea acestuia,
care poate fi analizată folosind diagramele cazurilor de utilizare.
Din punct de vedere al modelării sistemelor orientate pe obiecte din
perspectiva UML, aspectele statice sunt: clasele şi relaţiile dintre clase,
interfeţele, topologia hardware necesară execuţiei aplicaţiei.
Secţiunile UML sau modurile de vizualizare sunt grupuri de diagrame
care se adresează unei anumite mulţimi de entităţi. Toate diagramele UML pot
fi organizate în vizualizări. Fiecare vizualizare este descrisă folosind un număr
de diagrame ce conţin informaţii referitoare la un anumit aspect particular al
sistemului.
Există 5 tipuri importante de vizualizări asupra unui sistem software.
• Modul de vizualizare structural (logic) al arhitecturii unui sistem
se referă la cerinţele funcţionale ale acestuia, adică prezintă serviciile
furnizate de sistem utilizatorilor săi. Vizualizarea logică tratează din
interior sistemul şi descrie atât structura internă a acestuia, formată din
clase, obiecte şi relaţii, cât şi colaborările, legăturile care apar în urma
schimbului de mesaje între obiecte, pentru a realiza funcţionalitatea
dorită. Notaţia UML este dedicată, în mare parte, reprezentării
Modelarea entitate-relaţie 77

arhitecturii logice (clase, asocieri, obiecte, legături, generalizări,


polimorfism, pachete etc.)
• Modul de vizualizare a componentelor sistemului (implementare)
se concentrează pe descrierea componentelor care implementează
sistemul, dependenţele care există între ele, resursele alocate acestora,
precum şi rezolvarea unor probleme legate de reutilizarea,
portabilitatea codului şi informaţii administrative.
• Modul de vizualizare a cazurilor de utilizare surprinde
funcţionalitatea sistemului, aşa cum este ea percepută de actorii
externi care interacţionează cu sistemul, precum şi de utilizatorii
acestuia, de diferiţi membri ai echipei realizatoare sau de către alte
sisteme. În componenţa acestui mod intră diagramele cazurilor de
utilizare pentru descrierea statică a aspectului funcţional şi ocazional.
Se pot folosi şi diagrame de activitate pentru a încapsula latura
dinamică a funcţionalităţii.
• Modul de vizualizare comportamental este util pentru gestionarea
eficientă a resurselor, pentru execuţii paralele şi tratări asincrone ale
unor evenimente din sistem, precum şi pentru rezolvarea unor
probleme legate de comunicare şi sincronizare.
• Modul de vizualizare a desfăşurării (mediu) se referă la
desfăşurarea fizică a sistemului, indicând ce calculatoare şi ce tipuri de
noduri vor fi folosite pentru implementarea sistemului, cum sunt
acestea conectate, precum şi ce procese se vor executa în fiecare nod.
UML oferă, pe lângă elementele de bază, şi unele facilităţi care permit
organizarea şi extinderea diagramelor. Aceste facilităţi pot fi simple notaţii sau
pot fi elemente de extindere a limbajului UML. Dintre facilităţile cele mai
importante se remarcă pachetele, notele, stereotipurile şi proprietăţile.
• Pachetul reprezintă un mecanism de grupare a elementelor de
modelare. În UML, un pachet defineşte un mecanism de organizare a
elementelor în grupuri legate semantic.
• Nota cuprinde ipotezele şi deciziile aplicate în timpul analizei şi al
proiectării. Notele sunt corespondentul comentariilor din limbajele de
programare.
• Stereotipul este un concept introdus în UML, care permite extinderea
elementelor de bază pentru a crea noi elemente. Un stereotip
reprezintă un înţeles specific asociat unui element.
• Proprietatea este un element de extindere UML, care lărgeşte
proprietăţile şi semantica unui element UML.
Modelarea unui sistem priveşte modelarea aspectelor sale funcţionale,
statice şi dinamice. Pentru ca un sistem să aibă succes, în primul rând trebuie ca
cerinţele sistemului să fie exprimate într-o manieră care să permită o uşoară
înţelegere, indiferent de nivelul de pregătire informatică a celor implicaţi în
78 PROIECTAREA BAZELOR DE DATE
proiect, iar în al doilea rând trebuie ca membrii echipei de dezvoltare să poată
asimila cu uşurinţă modificările care apar pe parcurs în cerinţe.
Aceste condiţii sunt rezolvate în diagrama cazurilor de utilizare, care are
rolul de a reprezenta în formă grafică funcţionalităţile pe care trebuie să le
îndeplinească sistemul în faza sa finală. Pentru crearea modelului cazurilor de
utilizare, trebuie identificaţi actorii, cazurile de utilizare, relaţiile dintre actori şi
relaţiile dintre cazurile de utilizare. Realizarea acestor faze presupune discuţii
între utilizatori şi analiştii de sistem.
Cazul de utilizare poate fi privit ca un instrument de stimulare a
posibililor utilizatori în exprimarea propriilor puncte de vedere. Adeseori,
utilizatorii ştiu mai multe decât pot să explice şi nu le este uşor să se pronunţe
clar cum vor folosi sistemul. Cazurile de utilizare ajută la îndepărtarea acestui
impediment.
Discuţiile iniţiale trebuie să ducă la descoperirea actorilor şi a cazurilor
de utilizare care descriu cerinţele funcţionale în termeni generali şi care pot
stabili frontierele domeniului studiat. Următoarele discuţii au ca scop
înţelegerea, în detaliu, a domeniului studiat, ceea ce duce la evitarea introducerii
unor cazuri de utilizare, care ar îngreuna procesul de analiză.
Un caz de utilizare este o descriere a unei funcţionalităţi pe care o oferă
sistemul, o colecţie de scenarii referitoare la utilizarea unui sistem. Un scenariu
descrie o succesiune de evenimente introduse de un actor, care poate fi o
persoană, un dispozitiv hardware sau chiar trecerea timpului. Deci, actorii sunt
entităţile care iniţiază o secvenţă de evenimente (un scenariu). Rezultatul
secvenţei de evenimente trebuie să fie concretizat în ceva utilizabil de către
actorul ce a iniţiat secvenţa sau de către alt actor.
Diagrama cazurilor de utilizare are ca elemente de modelare actorii,
cazurile de utilizare, relaţiile dintre cazurile de utilizare.
Detaliile despre fiecare caz de utilizare pot fi date în documente text sau
pot fi folosite tehnici noi, de modelare dinamică, de exemplu diagramele de
activitate sau diagramele de interacţiune, pentru a specifica secvenţele de paşi
ale cazului de utilizare.
Construirea unei diagrame a cazurilor de utilizare are drept obiective:
• să capteze şi să descrie cerinţele funcţionale ale sistemului, cerinţe
rezultate în urma discuţiilor purtate de clienţi şi/sau utilizatori ai
sistemului cu dezvoltatorii acestuia;
• să ofere o descriere clară şi consistentă a ceea ce va trebui să facă
sistemul, adică folosirea modelului pentru comunicarea cerinţelor
tuturor persoanelor implicate în construirea sistemului, şi să constituie
un punct de plecare pentru alte activităţi (design, testare şi
implementare);
• să constituie o bază pentru realizarea textelor de verificare, ce decid
dacă funcţionalitatea finală concordă cu cerinţele iniţiale ale
sistemului;
Modelarea entitate-relaţie 79

• să permită transformarea cerinţelor funcţionale în viitoare clase şi


operaţii.
Diagramele UML pot fi desenate şi administrate utilizând un utilitar
CASE (Computer Edit Software Engineering). Aceste utilitare sunt deosebit de
utile în cazul unor diagrame complexe. Totuşi, dacă diagrama este prea
complicată, atunci este necesară partiţionarea ei în mai multe diagrame sau
reprezentarea la un nivel superior de abstractizare.
Exemple de utilitare CASE care permit realizarea diagramelor UML sunt
reprezentate de: Microsoft Office Visio, IBM Rational Rose Professional Data
Modeler, Altova UModel, Borland Together, Visual Paradigm for UML,
ArgoUML etc.
Interesul pentru suportul modelării bazelor de date cu ajutorul UML a
condus la crearea unor profile specifice. Un profil constituie o propunere a unei
comunităţi şi regrupează o mulţime de elemente UML care se aplică unui
context particular şi care conservă metamodelul UML. IBM Rational Rose
include un astfel de profil adaptat bazelor de date.
Există o diferenţă între un model (de exemplu, modelul conceptual de
date) şi un formalism (în care este descris un model). Astfel, putem vorbi despre
modelarea conceptuală a datelor urmând formalismul entitate-relaţie sau
formalismul UML. Notaţia exprimă doar aspectul referitor la reprezentare.
Pe lângă formalismul entitate-relaţie, considerat standardul de facto
pentru modelarea datelor, o opţiune alternativă este oferită de către UML.
Acesta include primitive pentru modelarea datelor, iniţial concepute pentru
reprezentarea structurii claselor unei aplicaţii orientate obiect, dar care pot fi
folosite pentru specificarea modelului de date al domeniului unei aplicaţii. În
particular, diagramele de clase UML pot fi utilizate ca alternativă la diagramele
entitate-relaţie.
Diferenţa majoră dintre o diagramă de clase UML şi o diagramă entitate-
relaţie este reprezentată de diferenţa dintre o clasă şi o entitate: o clasă este o
generalizare a noţiunii de entitate, care permite proiectantului să specifice nu
numai atribute, ci şi funcţii (numite metode) aplicabile instanţelor clasei. Astfel,
această diferenţă face ca UML să fie mai general decât modelul entitate-relaţie,
iar proiectantul poate exploata diagramele de clase UML pentru a realiza
aceeaşi specificaţie pe care o poate obţine cu ajutorul modelului entitate-relaţie.
80 PROIECTAREA BAZELOR DE DATE

Fig. 2.2. Diagrama de clase corespunzătoare unei restricţii a modelului.


Diagramele de clase UML au mai multe caracteristici decât diagramele
entitate-relaţie, cum ar fi posibilitatea de a specifica reguli de derivare pentru
atribute şi relaţii utilizând limbajul OCL (Object Constraint Language).
Pentru exemplificarea utilizării formalismului UML, vom considera o
restricţie a modelului utilizat pe parcursul acestei lucrări şi vom construi
diagrama de clase corespunzătoare. Construcţia diagramei a fost realizată cu
ajutorul programului Microsoft Visio şi este prezentată în figura 2.2 . Din
motive de spaţiu, a fost redus numărul de atribute precizate pentru fiecare clasă
din cadrul diagramei.
Modelarea entitate-relaţie 81

Prezentăm câteva observaţii referitoare la construcţia acestui model


utilizând o diagramă de clase UML. Unele observaţii au caracter general,
amintind anumite noţiuni UML necesare înţelegerii construcţiei modelului.
• Tabelul următor stabileşte echivalenţele dintre formalismele
modelului entitate-relaţie şi al notaţiei UML:

Entitate-relaţie UML
Tip entitate Clasă
Asociere (relaţie) Asociere (relaţie)
Entitate Obiect
Cardinalitate Multiplicitate
Model conceptual de Diagramă de clase
date

• Descrierea claselor în UML se divide în trei compartimente care


conţin respectiv numele clasei, atributele acesteia şi signatura
metodelor clasei. În cazul reprezentării unui model relaţional de date
nu există metode, deci al treilea compartiment este vid.
• Cardinalităţile din modelul entitate-relaţie propus de Chen şi
multiplicităţile din formalismul UML sunt poziţionate identic pe axa
de reprezentare a relaţiei.
• Asocierile dispun de anumite caracteristici, dintre care se remarcă:
nume, roluri, clase de asociere.
• Numele unei asocieri este dat de o formă verbală activă sau pasivă.
Acest nume este plasat în mijlocul liniei reprezentând relaţia
respectivă. De exemplu, asocierea organizeaza dintre clasele
Organizator şi Prezentare este reprezentată în diagrama de clase prin
acest nume plasat pe linia care conectează cele două clase.
• Numele asocierii poate fi însoţit de un triunghi îndreptat către clasa
desemnată de forma verbală, cu scopul de a indica sensul de citire a
relaţiei. De exemplu, în cazul asocierii creeaza se precizează că relaţia
se citeşte dinspre clasa Creator către clasa Vestimentatie.
• Extremitatea unei asocieri poate indica un rol. Acesta descrie modul în
care clasele sunt percepute prin intermediul relaţiei respective. Un rol
este în general desemnat printr-o formă nominală sau verbală. De
exemplu, asocierea lucreaza dintre clasele Casa_moda şi Creator este
reprezentată atât prin nume, cât şi prin rolurile angajat şi firma.
• În UML, asocierile one to one (1:1) au multiplicitatea 0..1 sau 1 la
fiecare extremitate; asocierile one to many (1:N) au multiplicitatea *
sau 1..* la o extremitate şi 0..1 sau 1 la cealaltă extremitate; asocierile
many to many (N:N) au multiplicitatea * sau 1..* la fiecare
extremitate.
82 PROIECTAREA BAZELOR DE DATE
• O asociere many to many cu atribute este reprezentată în UML printr-o
clasă de asociere. Aceasta conţine atributele asocierii şi este conectată
printr-o linie punctată la linia reprezentând relaţia. De exemplu,
asocierii dintre clasele Sponsor şi Prezentare îi este ataşată clasa de
asociere Finanteaza.
• Între clasele Angajat_temp şi Model există o asociere de generalizare,
corespunzătoare relaţiei ISA („is a”). Generalizarea este reprezentată
printr-o săgeată, al cărei vârf este un triunghi gol, dinspre subclasă
către superclasă.
• Între clasele Vestimentatie şi Accesoriu există o relaţie de agregare
compusă. Agregarea reprezintă în UML o asociere care nu este
simetrică şi pentru care o extremitate are un rol predominant faţă de
cealaltă. Această asociere priveşte un singur rol al său. Agregarea
aparţine mai degrabă etapei de concepţie detaliată decât celei de
modelare. Astfel, ea se va traduce la nivelul codului SQL prin
declanşatori sau constrângeri.
• Există două forme de agregare: compusă şi partajată. Compunerea
exprimă o relaţie de apartenenţă mai puternică, apărând atunci când
relaţia este de tipul „compune” sau „face parte din”. Reprezentarea
compunerii se face prin intermediul unui romb plin, poziţionat lângă
clasa care reprezintă întregul. Multiplicitatea extremităţii agregat nu
poate depăşi 1.
• Agregarea partajată presupune că un obiect poate face parte din mai
multe agregate, iar întregul se poate modifica în timp.O astfel de
relaţie se reprezintă prin intermediul unui romb gol, poziţionat lângă
clasa care reprezintă întregul.
• Relaţiile de grade strict mai mari decât 2 sunt reprezentate în UML cu
ajutorul unui romb (ca în figura 2.2) sau prin intermediul unei clase cu
stereotip. Stereotipurile constituie un mecanism de extensibilitate al
UML. Ele permit extinderea vocabularului UML astfel încât să poată
fi definite noi elemente ale modelului, derivate din cele existente dar
cu proprietăţi specifice domeniului problemei. Reprezentarea grafică a
unui stereotip se face prin plasarea numelui său, încadrat între
caracterele „<<” şi „>>” deasupra numelui unui alt element.
• În exemplul considerat, asocierea primeste este ternară, constituind
totodată o clasă de asociere. Reprezentarea acestei relaţii de gradul 3
prin intermediul unei clase cu stereotip are forma indicată în figura
2.3.
Modelarea entitate-relaţie 83

Fig. 2.3. Asociere UML de tipul 3 cu stereotip.


Diagrame entitate-relaţie
Diagrama E/R – model neformalizat pentru reprezentarea unui
sistem din lumea reală. Este un model de date conceptual de nivel înalt
dezvoltat de Chen (1976) pentru a facilita proiectarea bazelor de date.
Modelul de date conceptual este independent de:
• tipul SGBD-ului;
• platforma hardware utilizata.
Modelul conceptual este constituit din concepte care descriu:
• structura bazei de date;
• tranzactii de regasire si reactualizare asociate.

Entitate: persoană, loc, concept, activitate, eveniment care este


semnificativ pentru ceea ce modelăm.

DEPARTAMENT

SARCINA
lucreaza_in conduce
apartine_la

atasat_la
SALARIAT PROIECT

Observaţii:
• Entităţile devin tabele în modelele relaţionale.
• În general, entităţile se scriu cu litere mari.
• Entităţile sunt substantive, dar nu orice substantiv este o entitate.
• Pentru fiecare entitate este obligatoriu să se dea o descriere
detaliată.
• Nu pot exista, în aceeaşi diagramă, două entităţi cu acelaşi nume,
sau o aceeaşi entitate cu nume diferite.
Cheia primară este un identificator unic în cadrul entităţii, făcând
distincţie între valori diferite ale acesteia.
2

Cheia primară:
• trebuie să fie unică şi cunoscută la orice moment;
• trebuie să fie controlată de administratorul bazei;
• trebuie să nu conţină informaţii descriptive, să fie simplă, fără
ambiguităţi;
• să fie stabilă;
• să fie familiară utilizatorului.

Relaţie (asociere): o comunicare între două sau mai multe entităţi.


Existenţa unei relaţii este subordonată existenţei entităţilor pe care le leagă.
Gradul (tipul) unei relatii este dat de numarul entitatilor participante la
relatia respectiva.
Observaţii:
• În modelul relaţional, relaţiile devin tabele speciale sau coloane
speciale care referă chei primare.
• Relaţiile sunt verbe, dar nu orice verb este o relaţie.
• Pentru fiecare relaţie este important să se dea o descriere
detaliată.
• În aceeaşi diagramă pot exista relaţii diferite cu acelaşi nume. În
acest caz, le diferenţiază entităţile care sunt asociate prin relaţia
respectivă.
• Pentru fiecare relaţie trebuie stabilită cardinalitatea (maximă şi
minimă) relaţiei, adică numărul de tupluri ce aparţin relaţiei.
Se pot afla cardinalitatile cu verbele :
poate (cardinalitate maximă)  trebuie (cardinalitate minima)
Exemplu:
Câţi salariaţi pot lucra într-un departament? Mulţi!
În câte departamente poate lucra un salariat? In cel mult unul!

Relaţia SALARIAT_lucreaza_in_DEPARTAMENT are cardinalitatea
maximă many-one (n:1).
Exemplu:
Câţi salariaţi trebuie să conducă un departament? Cel puţin unul!
Câte departamente trebuie să conducă un salariat? Zero!

Relaţia SALARIAT_conduce_DEPARTAMENT are cardinalitatea minimă
one-zero (1:0).
3

Atribut: proprietate descriptivă a unei entităţi sau a unei relaţii.


Atributele pot fi simple, compuse, cu valori multiple, derivate.
Observaţii:
• Trebuie făcută distincţia între tipul atributului (devine coloană în
modelele relaţionale) şi valoarea acestuia (devine valoare în
coloane).
• Atributele sunt substantive, dar nu orice substantiv este atribut.
• Fiecărui atribut trebuie să i se dea o descriere completă (exemple,
contraexemple, caracteristici).
• Pentru fiecare atribut trebuie specificat numele, tipul fizic
(integer, float, char etc.), valori posibile, valori implicite, reguli
de validare, tipuri compuse.

Pentru proiectarea diagramei entitate-relaţie au fost stabilite


anumite reguli (nu sunt unice):
1. entităţile sunt reprezentate prin dreptunghiuri;
2. relaţiile dintre entităţi sunt reprezentate prin arce neorientate;
3. atributele care reprezintă chei primare trebuie subliniate sau
marcate prin simbolul „#“, plasat la sfârşitul numelui acestor
atribute;
4. cardinalitatea minimă este indicată în paranteze, iar cardinalitatea
maximă se scrie fără paranteze;
5. nu trebuie specificate toate atributele.

SALARIAT PROIECT
cod_salariat nr_proiect
nume M(0) atasat_la M(0) descriere
prenume buget_alocat
data_initiala
sex
functia
salariu 1

1 M(0)
apartine_la
conduce lucreaza_in

1(0) 1 M
DEPARTAMENT SARCINA
cod_departament nr_proiect
nume nr_sarcina
nr_cladire data_inceperii
stare

Diagrama E/R.
4

Cazuri speciale de entităţi, relaţii, atribute şi modul lor de


reprezentare în cadrul diagramei entitate-relaţie.
1. Entitate dependentă – nu poate exista în mod independent
(SARCINA depinde de PROIECT). Cheia primară a unei entităţi
dependente include cheia primară a sursei (nr_proiect) şi cel puţin o
descriere a entităţii (nr_sarcina). Entitatea dependentă se desenează
prin dreptunghiuri cu linii mai subţiri.
2. Moştenirea atributelor. Subentitate (subclasă) – submulţime a unei
alte entităţi, numită superentitate (superclasă) (SALARIAT < –– >
PROGRAMATOR). Subentitatea se desenează prin dreptunghiuri
incluse în superentitate. Există o relaţie între o subentitate şi o
superentitate, numită ISA, care are cardinalitatea maximă 1:1 şi
minimă 1:0. Cheile primare, atributele şi relaţiile unei superentităţi
sunt valabile pentru orice subentitate. Afirmaţia reciprocă este falsă.
3. Generalizare. Din entităţi similare care au mai multe atribute comune
se pot crea superentităţi. Aceste superentităţi conţin atributele
comune, iar atributele speciale sunt asignate la subentităţi. Pentru
noile superentităţi se introduc chei primare artificiale.
4. Specializare. După valorile unor atribute clasificatoare se pot
determina clase. Un grup de subentităţi reciproc exclusive defineşte o
clasă. Clasele se aliniază în desen vertical.
5. Într-o diagramă E/R se pot defini relaţii recursive.
6. Unele relaţii sunt relative la două entităţi şi le numim de tip 2, iar
dacă relaţiile implică mai mult de două entităţi, le vom numi de tip 3.
Trei relaţii de tip 2 sunt diferite de o relaţie de tip 3. Rupând o relaţie
de tip 3 în trei relaţii de tip 2, pot apărea informaţii incorecte.
7. Trebuie excluse din model relaţiile indirecte deoarece ele pot conduce
la redundanţă în baza de date.
8. Atributele derivabile trebuie eliminate şi introduse expresii prin care
aceste atribute pot fi calculate.
9. Relaţie sau atribut? Dacă un atribut al unei entităţi reprezintă cheia
primară a unei alte entităţi, atunci el referă o relaţie (cod_departament
în tabelul SALARIAT).
10. Entitate sau relaţie? Se cercetează cheia primară. Dacă aceasta
combină cheile primare a două entităţi, atunci este vorba de o relaţie.
(cheia primară a relaţiei asociat_la combină cod_salariat cu
nr_proiect, prin urmare, SALARIAT_asociat la_PROIECT va defini o
relaţie şi nu o entitate).
5

11. Un atribut indirect este inoportun. El nu descrie real relaţia sau


entitatea. Prin urmare, atributele indirecte trebuie reasignate. De fapt,
un atribut indirect este un caz special de relaţie indirectă care trebuie
eliminată pentru că introduce redundanţă în date (numărul clădirii în
care lucrează un salariat este un atribut al entităţii DEPARTAMENT
şi nu este o caracteristică a entităţii SALARIAT).
12. Există atribute opţionale, a căror valoare este uneori necunoscută,
alteori neaplicabilă. Aceste atribute trebuie introduse la subentităţi
(comisionul pentru deplasare şi zona de lucru sunt atribute specifice
unui agent teritorial şi trebuie introduse la subentitatea
AGENT_TERITORIAL).

Algoritmul pentru proiectarea diagramei entitate-relaţie:


1. identificarea entităţilor din cadrul sistemului analizat;
2. identificarea relaţiilor dintre entităţi şi stabilirea cardinalităţii;
3. identificarea atributelor aferente entităţilor şi asocierilor dintre
entităţi;
4. stabilirea atributelor de identificare a entităţilor (stabilirea
cheilor).

SALARIAT
cod_salariat PROIECT
nume job_cod nr_proiect
atasat_la descriere
M(0) M(0) buget_alocat
ISA AGENT_TERITORIAL
zona data_initiala
1 1(0) comision 1
functia

PROGRAMATOR apartine_la
ISA limbaj
nivel 1(0)
1 1(0)
M(1)
SARCINA
1 M(0) 1(0) nr_proiect
nr_sarcina
data_inceperii
conduce lucreaza_in stare
casatorit
1(0) 1
DEPARTAMENT
cod_departament
nume
nr_cladire

Diagrama E/R.
6

Modelul EER (modelul E/R extins) = Diagrama E/R + concepte


aditionale (subclasă, superclasă, moştenire, specializare, generalizare).

Gestiunea activităţilor de împrumut dintr-o bibliotecă

S-a presupus (restrictiv) că într-o zi un cititor nu poate împrumuta,


de mai multe ori, aceeaşi carte. Modelul prezintă anomalii (de exemplu,
cheia primară de la entitatea carte)! A fost gândit în această manieră cu
scop pur didactic.
Entităţile şi relaţiile care intervin în acest model sunt următoarele:
1. CARTE (entitate independentă) – orice carte care se găseşte în
inventarul bibliotecii. Cheia primară este atributul codel.
2. CITITOR (entitate independentă) – orice cititor care poate
împrumuta cărţi. Cheia primară este atributul codec.
3. DOMENIU (entitate independenta) – domeniul căruia îi aparţine
o carte. Cheia primară este atributul coded.
4. IMPRUMUTA – relaţie având cardinalitatea m:m care leagă
entităţile CITITOR şi CARTE.
5. APARTINE – relaţie care leagă atributele CARTE şi
DOMENIU. Relaţia are cardinalitatea maximă m:1, iar
cardinalitatea minimă 1:1.

CITITOR
CARTE M(1) M(0)
codec#
codel# imprumuta nume
titlu dep
autor
pret
nrex
1 DOMENIU
M(0)
coded#
apartine intdom
7

Gestiunea activităţilor de editare dintr-o editură


Se analizeaza activitatea dintr-o editură referitoare la culegerea
textelor, realizarea elementelor grafice, machetarea unor publicaţii.

FRAME
SALARIAT nr_publicatie#
cod_salariat# nr_capitol#
nume job tip nr_frame#
M(1) M(0)

ISA GRAFICIAN scrie M(0)


tip include
1 1(0) 1

CAPITOL
TEHNOREDACTOR 1 M(0) nr_publicatie#
ISA tip_editor nr_capitol#
1 1(0)
1 realizează
M(1)
cuprinde
1
ISA
1 1(0) REDACTOR_SEF 1 M(0) PUBLICATIE
experienta coordoneaza nr_publicatie#
stil
limba

Gestiunea activităţilor unei firme de construcţii


Baza de date construită prin acest model, furnizează informaţii legate
de obiective de execuţie, investitori, executanţi, şantiere, contracte etc.
necesare unui manager al unei firme de construcţii
8

SANTIER
CONTRACTANT nr_santier#
cod_contractant# specialitate
adresa sef
telefon
cont 1
executa
banca
tip_contractant
M(0)
executa
SUBANTREPENOR LUCRARE
nume 1 M( cod_obiectiv#
nume_adm 1) cod_lucrare#
functie_adm adresa
1 ISA 1(0) M(1)

INVESTITOR necesita
tip_investitor
1
investeste_in
PERS_FIZICA OBIECTIV_
nume INVESTITIE
prenume 1 M(1) cod_obiectiv#
ISA
bi denumire
1 ISA adresa
1(0)

atasat_la

PERS_JURIDICA 1
tip_juridic
incheie CONTRACT
ISA nume
nr_contract#
functie
1 M(1) tip_contract
data_avans

Tabelele din cursurile Oracle Education. Tabelele emp, dept,


salgrade modelează gestiunea salariaţilor unei firme.
Tabelul emp(empno#, ename, job, mgr, hiredate, sal, com, deptno)
conţine informaţii despre salariaţii unei firme. Pentru fiecare salariat sunt
definite următoarele atribute: empno: codul salariatului; ename: numele
salariatului; job: funcţia; mgr: codul şefului; hiredate: data angajării; sal:
salariul; com: comisionul; deptno: codul departamentului în care lucrează.
Tabelul dept (deptno#, dname, loc) conţine informaţii despre
departamentele în care lucrează salariaţii. Atributele sale reprezintă:
deptno: codul departamentului; dname: numele departamentului; loc:
localitatea unde funcţionează departamentul.
Tabelul salgrade(grade#, losal, hisal) conţine informaţii despre
grilele de salarizare. Atributele tabelului au următoarea semnificaţie: grade:
codul grilei de salarizare; losal: limita inferioară a grilei de salarizare;
hisal: limita superioară a grilei de salarizare.
9

Ordonarea informaţiilor cu privire la descoperirile de


monede antice din Romania

petrecut_in EVENIMENT
PUNCT

gasita_in

stantata_cu
ARTICOL publicata MONEDA STANTA

inclusa_in

pastrata_la

TEZAUR MUZEU

STANŢA (nr_stanţă, împărat emitent, valoare nominală, an emitere,


monetăria, legenda de pe avers, legenda de pe revers) == > atribute ale
entităţii STANTA

Completaţi cardinalitatea!

Evidenţa şcolilor de şoferi din Romania

SCOALA CLIENT
cod_scoala# cod_client#

INSTRUCTOR EXAMEN
cod_instructor# cod_examen#

EXAMINATOR
MASINA cod_examinator#
cod_masina#

Completaţi relaţiile (lucreaza_la, conduce, sustine, asista, instruieste) dintre


entităţi şi specificaţi cardinalitatea!
10

Campionatele de fotbal ale diferitelor ţări

ECHIPA
M(1) sustine M(1) SPONSOR
Cod_echipa#
Nume Cod_sponsor#
Oras Nume

joaca

M(1)

MECI
Tara#
Nr_etapa#
Cod_meci#

M(1)

apartine_de

ETAPA
Tara
Nr_etapa

M(1)

atasata_la

CAMPIONAT
Tara#
11

Modelul relaţional
Modelul relaţional a fost conceput şi dezvoltat de E.F. Codd. El este
un model formal de organizare conceptuală a datelor, destinat reprezentării
legăturilor dintre date, bazat pe teoria matematică a relaţiilor. Modelul
relaţional este alcătuit numai din relaţii şi prin urmare, orice interogare
asupra bazei de date este tot o relaţie.
Calităţi:
• este simplu;
• riguros din punct de vedere matematic;
• nu este orientat spre sistemul de calcul.
Modalităţi pentru definirea unui SGBD relaţional:
• prezentarea datelor în tabele supuse anumitor operaţii de tip
proiecţie, selecţie, reuniune, compunere, intersecţie etc.
• un sistem de baze de date ce suportă un limbaj de tip SQL –
Structured Query Language;
• un sistem de baze de date care respectă principiile modelului
relaţional introdus de E.F. Codd.
Caracteristicile unui model relaţional:
• structura relaţională a datelor;
• operatorii modelului relaţional;
• regulile de integritate care guvernează folosirea cheilor în model.
Aceste trei elemente corespund celor trei componente ale ingineriei
software: informaţie, proces, integritate.
Structura datelor
Definirea noţiunilor de domeniu, relaţie, schemă relaţională, valoare
null şi tabel vizualizare (view).
Conceptele utilizate pentru a descrie formal, uzual sau fizic
elementele de bază ale organizării datelor sunt date în următorul tabel:
Formal Uzual Fizic
relaţie tablou fişier
tuplu linie înregistrare
atribut coloană câmp
domeniu tip de dată tip de dată
12

Domeniu – mulţime de valori care poate fi definită fie enumerând


elementele componente, fie definind o proprietate distinctivă a domeniului
valorilor.
Fie D1, D2, ..., Dn domenii finite, nu neapărat disjuncte. Produsul
cartezian D1 × D2 × ... × Dn al domeniilor D1, D2, ..., Dn este definit de
mulţimea tuplurilor (V1, V2, ..., Vn), unde V1 ∈ D1, V2 ∈ D2, ..., Vn ∈ Dn.
Numărul n defineşte aritatea tuplului.
O relaţie R pe mulţimile D1, D2, ..., Dn este o submulţime a produsului
cartezian D1 × D2 × ... × Dn, deci este o mulţime de tupluri. Caracteristicile
unei relaţii  comentat curs!
Caracteristicile unei relatii:
• are o denumire unica;
• fiecare celula contine o valoare atomica;
• fiecare atribut are nume unic;
• toate valorile unui atribut apartin aceluiasi domeniu;
• ordinea atributelor nu are importanta;
• nu exista dubluri ale tuplurilor;
• teoretic, ordinea tuplurilor nu are importanta.
Definirea unei relaţii se referă la mulţimi care variază în timp. Pentru a
caracteriza o relaţie este necesară existenţa un element invariant în timp:
structura relaţiei (schema relaţională). Mulţimea numelor atributelor
corespunzătoare unei relaţii R defineşte schema relaţională a relaţiei
respective. Vom nota schema relaţională prin R(A1, A2, ..., An). Exemplu!
Putem reprezenta o relaţie printr-un tabel bidimensional în care fiecare
linie corespunde unui tuplu şi fiecare coloană corespunde unui domeniu din
produsul cartezian. O coloană corespunde de fapt unui atribut. Numărul
atributelor defineşte gradul (aritatea) relaţiei, iar numărul de tupluri din
relaţie defineşte cardinalitatea relaţiei.
Exemplu (crearea unui tabel în SQL):
CREATE TABLE salariat (
cod_salariat SMALLINT,
nume VARCHAR(25),
prenume VARCHAR(20),
sex CHAR(1),
salariu INTEGER,
sot SMALLINT,
job_cod VARCHAR(6),
cod_departament SMALLINT );
13

Când se inserează tupluri într-o relaţie, de multe ori un atribut este


necunoscut sau neaplicabil. Pentru a reprezenta acest atribut a fost
introdusă o valoare convenţională în relaţie, şi anume valoarea null.
Tabelul vizualizare (view, filtru, relaţie virtuală, vedere) constituie
un filtru relativ la unul sau mai multe tabele, care conţine numai informaţia
necesară unei anumite abordări sau aplicaţii.
Vizualizarea este virtuală deoarece datele pe care le conţine nu sunt
în realitate memorate într-o bază de date. Este memorată numai definiţia
vizualizării. Vizualizarea nu este definită explicit, ca relaţiile de bază, prin
mulţimea tuplurilor componente, ci implicit, pe baza altor relaţii prin
intermediul unor expresii relaţionale. Stabilirea efectivă a tuplurilor care
compun vizualizarea se realizează prin evaluarea expresiei atunci când
utilizatorul se referă la acest tabel.
Exemplu (crearea unei vizualizări în SQL):
CREATE VIEW programator(nume,departament)
AS SELECT nume,cod_departament
FROM salariat
WHERE job_cod=’programator’;

Reguli de integritate  aserţiuni pe care datele conţinute în baza


de date trebuie să le satisfacă.
Trebuie făcută distincţia între:
• regulile structurale inerente modelării datelor;
• regulile de funcţionare specifice unei aplicaţii particulare.
Există trei tipuri de constrângeri structurale (de cheie, de referinţă, de
entitate) ce constituie mulţimea minimală de reguli de integritate pe care
trebuie să le respecte un SGBD relaţional. Restricţiile de integritate
minimale sunt definite în raport cu noţiunea de cheie a unei relaţii.
O mulţime minimală de atribute ale căror valori identifică unic un
tuplu într-o relaţie reprezintă o cheie pentru relaţia respectivă.
Fiecare relaţie are cel puţin o cheie. Una dintre cheile candidat va fi
aleasă pentru a identifica efectiv tupluri şi ea va primi numele de cheie
primară. Cheia primară nu poate fi reactualizată. Atributele care reprezintă
cheia primară sunt fie subliniate, fie urmate de semnul #.
O cheie identifică linii şi este diferită de un index care localizează
liniile. O cheie secundară este folosită ca index pentru a accesa tupluri. Un
grup de atribute din cadrul unei relaţii care conţine o cheie a relaţiei poartă
numele de supercheie.
14

Fie schemele relaţionale R1(P1, S1) şi R2(S1, S2), unde P1 este cheie
primară pentru R1, S1 este cheie secundară pentru R1, iar S1 este cheie
primară pentru R2. În acest caz, vom spune că S1 este cheie externă (cheie
străină) pentru R1.
Modelul relaţional respectă trei reguli de integritate structurală.
 Regula 1 – unicitatea cheii. Cheia primară trebuie să fie unică şi
minimală.
 Regula 2 – integritatea entităţii. Atributele cheii primare trebuie
să fie diferite de valoarea null.
 Regula 3 – integritatea referirii. O cheie externă trebuie să fie ori
null în întregime, ori să corespundă unei valori a cheii primare
asociate.
Proiectarea modelului relaţional (exemple  curs!)
Transformarea entităţilor
 Entităţile independente devin tabele independente. Cheia
primară nu conţine chei externe.
 Entităţile dependente devin tabele dependente. Cheia primară a
entităţilor dependente conţine cheia primară a entităţii de care
depinde (cheie externă) plus unul sau mai multe atribute
adiţionale.
 Subentităţile devin subtabele. Cheia externă se referă la
supertabel, iar cheia primară este această cheie externă (cheia
primară a subentităţii PROGRAMATOR este cod_salariat care
este o cheie externă).

Transformarea relaţiilor
 Relaţiile 1:1 şi 1:n devin chei externe. Relaţia conduce devine
coloană în tabelul DEPARTAMENT, iar relaţia lucreaza_in
devine coloană în tabelul SALARIAT. Simbolul „ד indică
plasamentul cheii externe, iar simbolul „ד exprimă faptul că
această cheie externă este conţinută în cheia primară. Relaţia 1:1
plasează cheia externă în tabelul cu mai puţine linii.
 Relaţia m:n devine un tabel special, numit tabel asociativ, care
are două chei externe pentru cele două tabele asociate. Cheia
primară este compunerea acestor două chei externe plus
eventuale coloane adiţionale. Tabelul se desenează punctat.
15

 Relaţiile de tip trei devin tabele asociative. Cheia primară este


compunerea a trei chei externe plus eventuale coloane adiţionale.

Transformarea atributelor
 Un atribut singular devine o coloană.
 Atributele multiple devin tabele dependendente ce conţin cheia
primară a entităţii şi atributul multiplu. Cheia primară este o
cheie externă, plus una sau mai multe coloane adiţionale.
 Entităţile devin tabele, iar atributele lor devin coloane în aceste
tabele. Ce devin atributele relaţiilor? Pentru relaţii 1:1 şi 1:n,
atributele relaţiilor vor aparţine tabelului care conţine cheia
externă, iar pentru relaţii m:n şi de tipul trei, atributele vor fi
plasate în tabelele asociative.
SALARIAT
cod_salariat#
PROIECT
nr_proiect#

conduce lucreaza_in apartine_la

DEPARTAMENT
cod_departament#
SARCINA
nr_proiect#
nr_sarcina#

atasat_la
SALARIAT cod_salariat# PROIECT
cod_salariat# nr_proiect#
nr_proiect#

TELEFON
cod_salariat#
SALARIAT nr_telefon#
cod_salariat#

Cele patru tipuri de tabele (independente, dependente, subtabele şi


asociative) se deosebesc prin structura cheii primare.
16

Tabel Reprezintă Cheie primară


Independent entitate independentă nu conţine chei externe
Subtabel subentitate o cheie externă
entitate dependentă o cheie externă şi una sau mai
Dependent
atribute multiple multe coloane adiţionale
relaţie m:n două sau mai multe chei externe
Asociativ
relaţii de tip 3 şi (opţional) coloane adiţionale

Diagrama conceptuală pentru proiectarea modelului relaţional


comentat a fost construită din diagrama E/R prin adăugarea tabelelor
asociative şi prin marcarea cheilor externe.

SALARIAT
cod_salariat# PROIECT
salariu job_cod nr_proiect#
nume ATASAT_LA descriere
sex AGENT_TERITORIAL cod_salariat# buget_alocat
zona nr_proiect#
comision functie

PROGRAMATOR
limbaj
nivel

apartine_la

conduce lucreaza_in casatorit SARCINA


nr_proiect#
nr_sarcina#
data_inceperii
DEPARTAMENT TELFON stare
cod_departament# cod_salariat#
nume nr_telefon#
nr_cladire

Schemele relaţionale corespunzătoare acestei diagrame conceptuale


sunt următoarele:
– SALARIAT(cod_salariat#, nume, prenume, sex, job_cod, cod_sot,
forma_plata, nr_depart);
17

– DEPARTAMENT(cod_departament#, nume, numar_cladire,


cod_sal);
– ATASAT_LA(cod_salariat#, nr_proiect#, functia);
– PROIECT(nr_proiect#, descriere, buget_alocat);
– SARCINA(nr_proiect#, nr_sarcina, data_inceperii, stare);
– AGENT_TERITORIAL(cod_salariat#, zona, comision);
– PROGRAMATOR(cod_salariat#, limbaj, nivel);
– TELEFON(cod_salariat#, nr_telefon#).

Gestiunea activităţilor unei firme de construcţii


CONTRACTANT(cod_contractant#, adresa, telefon, cont, banca,
tip_contractant);
SUBANTREPRENOR(cod_contractant#, nume, nr_reg_comert,
nume_adm, functie_adm);
INVESTITOR(cod_contractant#, tip_investitor);
PERS_FIZICA(cod_contractant#, nume, prenume, bi);
PERS_JURIDICA(cod_contractant#, tip_juridic, nume, reprez_legal,
functie);
CONTRACT(nr_contract#, tip_contract, data_incheiere, garantie,
val_investitie, durate_executie, cont, banca, perioada, avans, data_avans,
cod_contractant);
SANTIER(nr_santier#, specialitate, sef);
OBIECTIV_INVESTITIE(cod_obiectiv#, denumire, adresa, adc,
nr_cert_urb, nr_aut_constr, nr_contract, cod_contractant);
LUCRARE(cod_lucrare#, cod_obiectiv#, tip_lucrare, nume, data_inc,
data_sf, nr_santier, cod_contractant);
18

CONTRACTANT

cod_contractant#
adresa
telefon
cont
banca tip_contractant

LUCRARE ŞANTIER
SUBANTREPENOR cod_lucrare# nr_şantier#
nume executa cod_obiectiv# executa specialitate şef
nume_adm
funcţie_adm

necesita

INVESTITOR
tip_investitor OBIECTIV_INVESTITIE

cod_obiectiv#
denumire
PERS_FIZICA
adresa
investeste_in
nume
prenume
bi

atasat_la

CONTRACT
PERS_JURIDICA nr_contract#
tip_contract
tip_juridic data_avans
nume incheie
functie
19

Gestiunea activităţilor de editare dintr-o editură

REALIZEAZA FRAME
SALARIAT cod_salariat# nr_publicatie#
cod_salariat# nr_publicatie# nr_capitol#
nume job nr_capitol# nr_frame#
nr_frame# tip
GRAFICIAN
tip include
TEHNOREDACTOR CAPITOL
tip_editor scrie nr_publicatie#
nr_capitol#
REDACTOR_SEF dimensiune
experienta

coordoneaza cuprinde
PUBLICATIE
TELEFON LIMBA nr_publicatie#
cod_salariat# cod_salariat# stil
nr_telefon# limba_cun#

SALARIAT(cod_salariat#, nume, prenume, vechime, salariu, job);


GRAFICIAN(cod_salariat#, tip);
TEHNOREDACTOR(cod_salariat#, tip_platforma, tip_editor, viteza);
REDACTOR_SEF(cod_salariat#, experienta);
LIMBA(cod_salariat#, limba_cunos#);
TELEFON(cod_salariat#, nr_telefon#);
REALIZEAZA(cod_salariat#, nr_frame#, nr_publicatie#, nr_capitol#,
data_inc, data_lim);
FRAME(nr_frame#, nr_publicatie#, nr_capitol#, tip, dim, format);
CAPITOL(nr_publicatie#, nr_capitol#, dimensiune, cod_salariat);
PUBLICATIE(nr_publicatie#, stil, beneficiar, autor, cod_salariat, cost,
titlu, limba).
20

Algebra relaţională
Limbajul de definire a datelor (LDD) precizează entităţile, relaţiile
dintre ele, atributele, structura atributelor, cheile, constrângerile, prin
urmare defineşte structura obiectelor bazei de date (schema bazei).
Limbajul de prelucrare a datelor (LMD) dintr-o bază de date
relaţionale cuprinde aspecte referitoare la introducerea, eliminarea,
modificarea şi căutarea datelor.
• Introducerea datelor – permite adăugarea de tupluri la o relaţie.
Tuplurile pot fi introduse de utilizator sau pot fi obţinute din alte
relaţii existente în baza de date.
• Eliminarea datelor – permite ştergerea tuplurilor ce satisfac
condiţii date.
• Modificarea datelor – permite reactualizarea tuplurilor ce
satisfac condiţii date cu noi valori ale atributelor sau cu rezultate
ale unor operaţii aritmetice efectuate asupra unor valori existente.
• Căutarea datelor – permite găsirea tuplurilor sau a unor părţi ale
tuplurilor ce satisfac condiţii date.
Modelul relaţional oferă două mulţimi de operatori pe relaţii:
• algebra relaţională (filtrele se obţin aplicând operatori specializaţi
asupra uneia sau mai multor relaţii din cadrul bazei relaţionale);
• calculul relaţional (filtrele se obţin cu ajutorul unor formule
logice pe care tuplurile rezultatului trebuie să le satisfacă).

Algebra relaţională a fost introdusă de E.F. Codd ca o mulţime de


operaţii formale acţionând asupra unor relaţii şi având ca rezultat alte
relaţii. Baza teoretică pentru limbajele de interogare relaţionale o constituie
operatorii introduşi de Codd pentru prelucrarea relaţiilor.
Operatorii modelului relaţional definesc operaţiile care se pot efectua
asupra relaţiilor în scopul realizării funcţiilor de prelucrare asupra BD.
Operatorii sunt numai pentru citire (nu actualizeaza operanzi)!!!
Scopul fundamental al algebrei relationale este de a permite scrierea
expresiilor relationale. Expresiile servesc ca o reprezentare de nivel
superior, simbolică, a intenţiilor utilizatorului şi pot fi supuse unei
diversităţi de reguli de transformare (optimizare).

Relaţiile sunt închise faţă de algebra relaţională (operanzii şi


21

rezultatele sunt relaţii  ieşirea unei operaţii poate deveni intrare pentru
alta)  posibilitatea imbricării expresiilor în algebra relaţională).
Operatorii algebrei relaţionale sunt:
• operatori tradiţionali pe mulţimi (UNION, INTERSECT,
PRODUCT, DIFFERENCE);
• operatori relaţionali speciali (PROJECT, SELECT, JOIN,
DIVISION).
Calculul relaţional reprezintă o adaptare a calculului predicatelor la
domeniul bazelor de date relaţionale. Ideea de bază este de a identifica o
relaţie cu un predicat. Pe baza unor predicate iniţiale, prin aplicarea unor
operatori ai calculului cu predicate (conjuncţia, disjuncţia, negaţia,
cuantificatorul existenţial şi cel universal) se pot defini noi relaţii.
Calculul relaţional poate să fie orientat pe tupluri sau orientat pe
domenii.
Echivalenţa dintre algebra relaţională şi calculul relaţional a fost
demonstrată de J.D.Ullman. Această echivalenţă arată că orice relaţie
posibil de definit în algebra relaţională poate fi definită şi în cadrul calcului
relaţional, şi reciproc.
Operatorii (unari sau binari) algebrei relaţionale realizează
următoarele funcţii:
• SELECT (selecţie) – extrage tupluri ce satisfac o condiţie specificată;
• PROJECT (proiecţie) – extrage atributele specificate;
• DIFFERENCE (diferenţă) – extrage tupluri care apar într-o relaţie, dar
nu apar în cealaltă;
• PRODUCT (produs cartezian) – generează toate perechile posibile de
tupluri, primul element al perechii fiind luat din prima relaţie, iar cel de-
al doilea element din cealaltă relaţie;
• UNION (reuniune) – reuneşte două relaţii;
• INTERSECT (intersecţie) – extrage tupluri care apar în ambele relaţii;
• DIVISION (diviziune) – extrage valorile atributelor dintr-o relaţie, care
apar în toate valorile atributelor din cealaltă relaţie;
• JOIN (compunere) – extrage tupluri din mai multe relaţii corelate:
• NATURAL JOIN (compunere naturală) – combină tupluri din două
relaţii, cu condiţia ca atributele comune să aibă valori identice;
• SEMI-JOIN (semi-compunere) – selectează tupluri ce aparţin unei
singure relaţii, care sunt corelate cu tupluri din cea de a doua relaţie;
22

• Θ-JOIN (Θ-compunere) – combină tupluri din două relaţii (nu neaparat


corelate), cu condiţia ca valorile atributelor specificate să satisfacă o
anumită condiţie;
• OUTER JOIN (compunere externă) – combină tupluri din două relaţii,
astfel încât condiţiile de corelare să fie satisfăcute. Tuplurile din orice
relaţie care nu satisfac aceste condiţii sunt completate cu valori null.
Pentru operatorii UNION, INTERSECT şi DIFFERENCE, se
presupune că sunt aplicaţi numai la relaţii având aceeaşi aritate, iar ordinea
(nu numele) atributelor este aceeaşi.

Operatorul PROJECT
Proiecţia este o operaţie unară care elimină anumite atribute ale unei
relaţii producând o submulţime „pe verticală“ a acesteia. Suprimarea unor
atribute poate avea ca efect apariţia unor tupluri duplicate, care trebuie
eliminate.
Prin proiecţie se construieşte dintr-o relaţie R, o nouă relaţie:
a) ştergând din R atributele care nu sunt menţionate în parametrii
proiecţiei;
b) eliminând dublurile care apar după ştergere.

Pentru a reprezenta operatorul proiecţie sunt utilizate diferite notaţii:


ΠA1, ..., Am (R) PROJECT (R, A1, ..., Am)
R[A1, ..., Am]
unde A1, A2, ..., Am sunt parametrii proiecţiei relativ la relaţia R.
Exemplu. Să se obţină o listă ce conţine numele, prenumele şi sexul
angajaţilor.
1. Proiecţie în algebra relaţională:

Rezultat = PROJECT(SALARIAT, nume, prenume, sex)


2. Proiecţie cu dubluri în SQL:
SELECT nume, prenume, sex
FROM salariat;
3. Proiecţie fără dubluri în SQL:
SELECT DISTINCT nume, prenume, sex
FROM salariat;
23

Operatorul SELECT
Selecţia (restrictia) este o operaţie unară care produce o submulţime
pe „orizontală“ a unei relaţii R. Această submulţime se obţine prin
extragerea tuplurilor din R care satisfac o condiţie specificată.
Sunt utilizate diferite notaţii:
σcondiţie(R) R[condiţie]
SELECT(R, condiţie) RESTRICT(R, condiţie).
Exemplu. Să se obţină informaţii complete despre angajaţii de sex
masculin.
1. Selecţie în algebra relaţională:
Rezultat = SELECT(SALARIAT, sex = ‘m’)
2. Selecţie în SQL:
SELECT *
FROM salariat
WHERE sex = ’m’;

Operatorul UNION
Reuniunea a două relaţii R şi S este mulţimea tuplurilor aparţinând
fie lui R, fie lui S, fie ambelor relaţii.
Sunt utilizate notaţiile:
R∪S
UNION(R, S)
OR(R, S)
APPEND(R, S).
Exemplu. Să se obţină lista cu numele persoanelor fizice şi a
subantreprenorilor.
SELECT nume
FROM subantreprenor
UNION
SELECT nume
FROM pers_fizica;
24

Operatorul DIFFERENCE
Diferenţa a două relaţii R şi S este mulţimea tuplurilor care aparţin
lui R, dar nu aparţin lui S. Diferenţa este o operaţie binară necomutativă
care permite obţinerea tuplurilor ce apar numai într-o relaţie.
Sunt utilizate diferite notaţii:
R–S
DIFFERENCE(R, S)
REMOVE(R, S)
MINUS(R, S).
Exemplu. Să se obţină lista cu numărul contractului, tipul
contractului, valoarea investiţiei şi durata lucrării pentru contractele de
subantrepriză pentru care valoarea investiţiei nu depăşeşte 60000$.
1. Diferenţă în algebra relaţională:
R=PROJECT(SELECT(CONTRACT, tip_contract=T),
nr_contract, tip_contract, val_investitie, durata_lucrare);
S=PROJECT(SELECT(CONTRACT, val_investitie > 60000),
nr_contract, tip_contract, val_investitie, durata_lucrare);
Rezultat = DIFFERENCE(R, S)
2. Diferenţa în SQL:
SELECT nr_contract,tip_contract,
val_investitie,durata_lucrare
FROM contract
WHERE tip_contract
MINUS
SELECT nr_contract,tip_contract,
val_investitie,durata_lucrare
FROM contract
WHERE val_investitie>60000;
Evident diferenţa se poate referi la tabele diferite! Implementaţi
cererea prin care se listează toate oraşele în care se află o filială, dar nici o
proprietate.

Operatorul INTERSECT
Intersecţia a două relaţii R şi S este mulţimea tuplurilor care aparţin
şi lui R şi lui S. Operatorul INTERSECT este un operator binar, comutativ,
derivat:
25

R ∩ S = R – (R – S)
R ∩ S = S – (S – R).
Sunt utilizate diferite notaţii:
INTERSECT(R, S)
R∩S
AND(R, S).
În anumite dialecte SQL există operator special (INTERSECT), care
realizează această operaţie. Operatorii INTERSECT şi DIFFERENCE pot
fi simulaţi în SQL (în cadrul comenzii SELECT) cu ajutorul opţiunilor
EXISTS, NOT EXISTS, IN, != ANY.
Exemplu. Utilizând tabelele agent_teritorial şi programator să se
obţină lista codurilor salariaţilor care sunt programatori, dar care lucrează şi
ca agenţi teritoriali.
1. Intersecţie în algebra relaţională:
R = PROJECT(AGENT_TERITORIAL, cod_salariat);
S = PROJECT(PROGRAMATOR, cod_salariat),
Rezultat = INTERSECT(R, S).
2. Intersecţie în SQL:
SELECT cod_salariat
FROM agent_teritorial
INTERSECT
SELECT cod_salariat
FROM programator;
3. Simularea intersecţiei în SQL:
SELECT cod_salariat
FROM programator p
WHERE EXISTS
(SELECT cod_salariat
FROM agent_teritorial a
WHERE p.cod_salariat=a.cod_salariat);

Operatorul PRODUCT
Fie R şi S relaţii de aritate m, respectiv n. Produsul cartezian al lui R
cu S este mulţimea tuplurilor de aritate m + n unde primele m componente
formează un tuplu în R, iar ultimele n componente formează un tuplu în S.
Sunt utilizate diferite notaţii:
26

R×S
PRODUCT(R, S)
TIMES(R, S).
Exemplu. Să se obţină lista tuturor posibilităţilor de investiţie în
diverse obiective de către o firmă care este persoană juridică.
1. Produs cartezian în algebra relaţională:
R = PROJECT(PERS_JURIDICA, nume, cod_contractant);
S = PROJECT(OBIECTIV_INVESTITIE, denumire);
Rezultat = PRODUCT(R, S).
2. Produs cartezian în SQL:
SELECT cod_contractant, nume, denumire
FROM obiectiv_investitie, pers_juridica;
Operatorul DIVISION
Diviziunea este o operaţie binară care defineşte o relaţie ce conţine
valorile atributelor dintr-o relaţie care apar în toate valorile atributelor din
cealaltă relaţie.
Sunt utilizate diferite notaţii:
DIVIDE(R, S)
DIVISION(R, S)
R ÷ S.
Diviziunea conţine acele tupluri de dimensiune n – m la care, adăugând
orice tuplu din S, se obţine un tuplu din R.
Operatorul diviziune poate fi exprimat formal astfel:
R(n) ÷ S(m) = {t(n-m)  ∀ s ∈ S, (t, s) ∈ R} unde n > m şi S ≠ ∅.
Operatorul DIVISION este legat de cuantificatorul universal (∀) care
nu există în SQL. Cuantificatorul universal poate fi însă simulat cu ajutorul
cuantificatorului existenţial (∃) utilizând relaţia:
∀x P(x) ≡ ¬ ∃ x ¬ P(x).
Prin urmare, operatorul DIVISION poate fi exprimat în SQL prin
succesiunea a doi operatori NOT EXISTS.
Exemplu. Să se obţină codurile salariaţilor ataşaţi tuturor proiectelor
pentru care s-a alocat un buget egal cu 1000.
1. Diviziune în algebra relaţională:
27

R = PROJECT(ATASAT_LA, cod_salariat, nr_proiect);


S = PROJECT(SELECT(PROIECT, buget = 1000), nr_proiect);
Rezultat = DIVISION(R, S).
2. Diviziune în SQL:
SELECT UNIQUE cod_salariat
FROM atasat_la sx
WHERE NOT EXISTS
(SELECT *
FROM proiect pp
WHERE proiect.buget=’1000’
AND NOT EXISTS
(SELECT *
FROM atasat_la bb
WHERE pp.nr_proiect=bb.nr_proiect
AND bb.cod_salariat=sx.cod_salariat));
3. Simularea diviziunii cu ajutorul funcţiei COUNT:
SELECT cod_salariat
FROM atasat_la
WHERE nr_proiect IN
(SELECT nr_proiect
FROM proiect
WHERE buget=1000)
GROUP BY cod_salariat
HAVING COUNT(nr_proiect)=
(SELECT COUNT(*)
FROM proiect
WHERE buget=1000);

Operatorul JOIN
Operatorul de compunere (uniune) permite regăsirea informaţiei din
mai multe relaţii corelate. Operatorul combină produsul cartezian, selecţia
şi proiecţia.

Operatorul NATURAL JOIN


Operatorul de compunere naturală (NATURAL JOIN) combină
tupluri din două relaţii R şi S, cu condiţia ca atributele comune să aibă
valori identice.
Algoritmul care realizează compunerea naturală este următorul:
1. se calculează produsul cartezian R × S;
28

2. pentru fiecare atribut comun A care defineşte o coloană în R şi o


coloană în S, se selectează din R × S tuplurile ale căror valori
coincid în coloanele R.A şi S.A (atributul R.A reprezintă numele
coloanei din R × S corespunzătoare coloanei A din R);
3. pentru fiecare astfel de atribut A se proiectează coloana S.A, iar
coloana R.A se va numi A.
Operatorul NATURAL JOIN poate fi exprimat formal astfel:
JOIN(R, S) = Πi1,...,im σ(R.A1 = S.A1)∧ ... ∧(R.Ak = S.Ak)(R × S),
unde A1, ..., Ak sunt atributele comune lui R şi S, iar i1, ..., im reprezintă lista
componentelor din R × S (păstrând ordinea iniţială) din care au fost
eliminate componentele S.A1, ..., S.Ak.
Exemplu. Să se obţină informaţii complete despre angajaţi şi
departamentele în care lucrează.
1. Operatorul de compunere naturală în algebra relaţională:
Rezultat = JOIN(SALARIAT, DEPARTAMENT).
2. Operatorul de compunere naturală în SQL:
SELECT *
FROM salariat, departament
WHERE nr_depart = cod_departament;

Operatorul θ-JOIN
Operatorul θ-JOIN combină tupluri din două relaţii (nu neapărat
corelate) cu condiţia ca valorile atributelor specificate să satisfacă o
anumită condiţie specificată explicit în cadrul operaţiei.
Operatorul θ-JOIN este un operator derivat, fiind o combinaţie de
produs scalar şi selecţie:
JOIN(R, S, condiţie) = σcondiţie (R × S)
Exemplu. Să se afişeze pentru fiecare salariat, codul acestuia şi grila
sa de salarizare.
SELECT empno, level
FROM salgrade, emp
WHERE sal BETWEEN losal AND hisal;
Exemplu. Să se obţină informaţii despre contractanţi (codul şi banca)
şi obiectivele de investiţie asociate acestora (denumire, număr certificat de
urbanizare) cu condiţia ca obiectivele să nu fie la aceeaşi adresă ca şi
contractanţii.
29

1. Operatorul θ-JOIN în algebra relaţională:


R = PROJECT(CONTRACTANT, cod_contractant, banca);
S = PROJECT(OBIECTIV_INVESTITIE, denumire, nr_cert_urb);
Rezultat = JOIN(R, S, OBIECTIV_INVESTITIE.adresa <>
CONTRACTANT.adresa).
2. Opratorul θ-JOIN în SQL:
SELECT cod_contractant,banca, nr_cert_urb,
denumire
FROM contractant a,obiectiv_investitie b
WHERE b.adresa <> a.adresa;

Operatorul SEMI-JOIN
Operatorul SEMI-JOIN conservă atributele unei singure relaţii
participante la compunere şi este utilizat când nu sunt necesare toate
atributele compunerii. Operatorul este asimetric.
Tupluri ale relaţiei R care participă în compunerea (naturală sau
θ-JOIN) dintre relaţiile R şi S.
SEMI-JOIN este un operator derivat, fiind o combinaţie de proiecţie
şi compunere naturală sau proiecţie şi θ-JOIN:
SEMIJOIN(R, S) = ΠM (JOIN(R, S))
SEMIJOIN(R, S, condiţie) = ΠM (JOIN(R, S, condiţie)),
unde am notat prin M atributele relaţiei R.
Exemplu. Să se obţină informaţii referitoare la persoanele fizice
(nume, buletin) care investesc în obiective cu caracter recreativ.
1. Operatorul SEMI-JOIN în algebra relaţională:
R = SELECT(OBIECTIV_INVESTITIE, denumire = ’cabana’ OR
denumire = ’casa de vacanta’)
S = JOIN(PERS_FIZICA, R)
Rezultat = PROJECT(S, nume, buletin).
2. Operatorul SEMI-JOIN în SQL:
SELECT nume,bi
FROM pers_fizica a,obiectiv_investitie b
WHERE a.cod_contractant = b.cod_contractant
AND (denumire=’cabana’)OR (denumire= ’casa
de vacanta’);
30

Operatorul OUTER JOIN


Operaţia de compunere externă combină tupluri din două relaţii
pentru care sunt satisfăcute condiţiile de corelare. În cazul aplicării
operatorului JOIN se pot pierde tupluri, atunci când există un tuplu în una
din relaţii pentru care nu există nici un tuplu în cealaltă relaţie, astfel încât
să fie satisfăcută relaţia de corelare.
Operatorul elimină acest inconvenient prin atribuirea valorii null
valorilor atributelor care există într-un tuplu din una dintre relaţiile de
intrare, dar care nu există şi în cea de-a doua relaţie.
Practic, se realizează compunerea a două relaţii R şi S la care se
adaugă tupluri din R şi S, care nu sunt conţinute în compunere, completate
cu valori null pentru atributele care lipsesc.
Compunerea externă poate fi: LEFT, RIGHT, FULL. De exemplu,
OUTER JOIN LEFT reprezintă compunerea în care tuplurile din R, care nu
au valori similare în coloanele comune cu relaţia S, sunt de asemenea
incluse în relaţia rezultat.
Exemplu. Să se obţină informaţii referitoare la persoanele fizice care
sunt investitori (chiar dacă nu au investit în obiective industriale) şi la
obiectivele de investiţie industriale (chiar şi cele care nu sunt construite de
persoane fizice).
R = SELECT(OBIECTIV_INVESTITIE, denumire = 'industrial')
Rezultat = OUTERJOIN(PERS_FIZICA, R).
Operatorii algebrei relaţionale pot fi reprezentaţi grafic cu ajutorul
unor simboluri speciale.  curs!
Operaţii adiţionale: complement, despicare, închidere tranzitivă.
Funcţii asociate: MIN, MAX, COUNT, AVG, SUM, VAR, STD etc.
31

Evaluarea şi optimizarea interogărilor


Procesarea interogărilor
O expresie a algebrei relaţionale este constituită din relaţii legate
prin operaţii din algebra relaţională. O expresie se poate reprezenta grafic
cu ajutorul unui arbore, numit arbore algebric, în care nodurile corespund
operatorilor din cadrul expresiei respective.
Evaluarea unei expresii presupune efectuarea prelucrărilor indicate
de operatorii din expresie în ordinea apariţiilor sau în ordinea fixată prin
paranteze. Rezultatul evaluării unei expresii este o relaţie derivată din
relaţiile menţionate ca operanzi în cadrul expresiei.
Două expresii sunt echivalente, dacă în urma evaluării lor se obţine
ca rezultat aceeaşi relaţie.

Exemple referitoare la moduri echivalente de exprimare a unei cereri


(vor fi rezolvate la curs!).
1. Informaţii despre salariaţii care nu contribuie la machetarea nici
unei publicaţii, dar au retribuţia mai mare decât o valoare dată.
2. Codul şi numele subantreprenorilor care au realizat lucrări
specializate la obiective case de vacanţă sau cabane.
3. Codurile şi telefoanele investitorilor, valoarea si durata de execuţie
a investitiilor a caror valoare este între două limite specificate.
4. Perioada de desfăşurare şi preţul ofertelor care încep după 1
ianuarie 2003 şi sunt:
• sejururi la munte;
• excursii în care autocarele sunt conduse de şoferi angajaţi după 1
mai 1987 şi supravegheate de ghizi ce cunosc limba engleză care
au făcut specializare în Suedia.
În majoritatea sistemelor de gestiune, şi în special în cele relaţionale,
interfaţa cu utilizatorul este de tip neprocedural. Utilizatorul defineşte datele
pe care doreşte să le vizualizeze fără a da algoritmii de acces. Sistemul
trebuie să convertească cererea utilizatorului:
• într-o cerere optimală;
• în proceduri de acces optimal la datele fizice.
Garantarea absolută a performanţelor optime pentru procesorul
limbajului relaţional este imposibilă. Corectă ar fi utilizarea cuvântului
„ameliorare“ în locul cuvântului „optimizare“.
32

Evaluarea unei interogări se efectuează în trei etape.


 Analiza cererii presupune studierea sintactică şi semantică a cererii
pentru a verifica corectitudinea sa şi a simplifica criteriul de
căutare.
 Ordonanţarea presupune descompunerea cererii într-o mulţime de
operaţii elementare şi determinarea unei ordini optimale a acestor
operaţii. Operaţiile sunt, în general, cele ale algebrei relaţionale. La
sfârşitul etapei se obţine un plan de execuţie pentru cerere.
 Execuţia presupune efectuarea (paralel şi/sau secvenţială)
operaţiilor elementare furnizate de planul de execuţie pentru a
obţine rezultatul cererii.

Presupunem că utilizatorul transmite sistemului de gestiune o cerere


exprimată prin ordine SQL. Pentru a răspunde cererii, SGBD-ul trebuie să
înţeleagă cererea utilizatorului. Cererea trebuie să fie corectă sintactic, datele
trebuie să fie disponibile utilizatorului şi trebuie localizate analizând diferite
drumuri de acces la ele. Aceste funcţii sunt realizate de SGBD cu ajutorul a
două module funcţionale care comunică permanent:
• analizorul cererilor, care asigură verificarea sintactică şi
semantică a cererii, localizarea datelor implicate în cerere (găsirea
adresei blocurilor ce conţin datele), furnizarea planului de execuţie.
• administratorul datelor (executorul), care execută efectiv cererea
(primeşte planurile de execuţie furnizate de modulul de optimizare
şi le execută). Execuţia presupune căutarea blocurilor ce conţin
datele şi transferul blocurilor în memoria cache.

Ideea generală:
cerere arbore algebric (nu este unic)  plan de executie  optimizare
Un plan de execuţie implică o secvenţă de paşi pentru evaluarea cererii
(în mod obişnuit, fiecare pas din planul de execuţie corespunde unei operaţii
relaţionale) precum şi metoda care va fi folosită pentru evaluarea operaţiei.
De obicei, pentru o operaţie relaţională dată, există mai multe metode ce pot
fi folosite pentru evaluarea acesteia.
Două planuri de execuţie diferite care au întotdeauna acelaşi rezultat se
numesc echivalente. Planuri de execuţie echivalente pot avea diferite
costuri. Scopul optimizării cererilor este de a găsi, printre diversele planuri
de execuţie echivalente, pe acela de cost minim. Într-un sistem centralizat,
costul evaluării unei cereri este suma a două componente, costul I/O
(transferuri de date) şi costul CPU (verificare de condiţii, operaţii join etc.).
33

Ordinea de execuţie a operaţiilor


O interogare constă dintr-un număr de operaţii. Ordinea în care se
efectuează operaţiile are un rol important în evaluarea costului necesar
realizării interogării.
Există două modalităţi de abordare pentru a determina ordinea de
execuţie a operaţiilor:
• algebric;
• bazat pe estimarea costului.
Ambele folosesc o mulţime de reguli care permit transformarea unui
plan de execuţie (reprezentat ca o expresie scrisă în termenii algebrei
relaţionale) în altul, echivalent.
Optimizarea cererilor bazată pe algebra relaţională se realizează în
două etape:
• se exprimă cererile sub forma unor expresii algebrice relaţionale;
• se aplică acestor expresii transformări algebrice care conduc la
expresii echivalente, dar care vor fi executate mai eficient.
Procesul de transformare a cererilor se realizează conform unei
strategii de optimizare care poate să fie:
• independentă de modul de memorare a datelor (strategie generală);
• dependentă de modul de memorare (strategie specifică unui anumit
SGBD).

Proprietăţile operatorilor algebrei relaţionale


Proprietatea 1. Comutativitatea operaţiilor de join şi produs cartezian:
JOIN(R1, R2) = JOIN(R2, R1)
R1 × R2 = R2 × R1

Proprietatea 2. Asociativitatea operaţiilor de join şi produs cartezian:


JOIN(JOIN(R1, R2), R3) = JOIN(R1, JOIN(R2, R3))
(R1 × R2) × R3 = R1 × (R2 × R3)

Proprietatea 3. Compunerea proiecţiilor:


ΠA1,...,Am (ΠB1,...,Bn (R)) = ΠA1,...,Am (R),
unde {A1, A2,...,Am } ⊆ {B1, B2,...,Bn}.

Proprietatea 4. Compunerea selecţiilor:


σcond1 (σcond2 (R)) = σcond1∧cond2 (R) = σcond2 (σcond1 (R)),
unde am notat prin cond condiţia după care se face selecţia.
34

Proprietatea 5. Comutarea selecţiei cu proiecţia:


ΠA1,...,Am (σcond (R)) = σcond (ΠA1,...,Am (R)),
unde condiţia după care se face selecţia implică numai atributele A1,...,Am.
Dacă condiţia implică şi atributele B1,...,Bn, care nu aparţin mulţimii
{A1,...,Am}, atunci:
ΠA1,...,Am (σcond (R)) = ΠA1,...,Am (σcond (ΠA1,...,Am,B1,...,Bn (R)))

Proprietatea 6. Comutarea selecţiei cu produsul cartezian:


Dacă toate atributele menţionate în condiţia după care se face selecţia
sunt atribute ale relaţiei R1, atunci:
σcond (R1 × R2) = σcond (R1) × R2
Dacă condiţia este de forma cond1∧cond2 şi dacă cond1 implică
numai atribute din R1, iar cond2 implică numai atribute din R2, atunci
σcond (R1 × R2) = σcond1 (R1) × σcond2 (R2)
Dacă cond1 implică numai atribute din R1, iar cond2 implică atribute
atât din R1 cât şi din R2, atunci:
σcond (R1 × R2) = σcond2 (σcond1 (R1) × R2)

Proprietatea 7. Comutarea selecţiei cu reuniunea:


σcond (R1 ∪ R2) = σcond (R1) ∪ σcond (R2)

Proprietatea 8. Comutarea selecţiei cu diferenţa:


σcond (R1 – R2) = σcond (R1) – σcond (R2)
Proprietatea 9. Comutarea proiecţiei cu reuniunea:
ΠA1,...,Am (R1 ∪ R2) = ΠA1,...,Am (R1) ∪ ΠA1,...,Am (R2)
Proprietatea 10. Comutarea proiecţiei cu produsul cartezian:
Dacă A1,...,Am este o listă de atribute ce apar în schemele relaţionale R1
şi R2 şi dacă lista este formată din atribute aparţinând lui R1 (notate prin
B1,...,Bn) şi din atribute aparţinând lui R2 (notate prin C1,...,Ck) atunci:
ΠA1,...,Am (R1 × R2) = ΠB1,...,Bn (R1) × ΠC1,...,Ck (R2)

Proprietatea 11. Compunerea proiecţiei cu operaţia join:


Dacă A1,...,Am este o listă de atribute ce apar în schemele relaţionale R1
şi R2 şi dacă lista este formată din atribute aparţinând lui R1 (notate prin
B1,...,Bn) şi din atribute aparţinând lui R2 (notate prin C1,...,Ck) atunci:
ΠA1,...,Am (JOIN(R1,R2,D)) = ΠA1,...,Am (JOIN(ΠD,B1,...,Bn(R1), ΠD,C1,...,Ck(R2),D),
unde am notat prin JOIN(R1, R2, D) operaţia de compunere naturală între R1
şi R2 după atributul comun D.
35

Proprietatea 12. Compunerea selecţiei cu operaţia join:


σcond (JOIN (R1, R2, D)) = σcond (JOIN (ΠD,A (R1), ΠD,A (R2), D)),
unde A reprezintă atributele care apar în condiţia după care se face selecţia.

Reguli de optimizare frecvent folosite:


Regula de optimizare 1. Selecţiile se execută cât mai devreme
posibil. Motivaţia acestei reguli este că selecţiile reduc substanţial
dimensiunea relaţiilor. Regula de transformare 4 poate fi folosită
pentru a separa două sau mai multe selecţii în selecţii individuale
care pot fi distribuite join-ului sau produsului cartezian folosind
comutarea selecţiei cu join-ul.
Regula de optimizare 2. Produsurile carteziene se înlocuiesc cu join-
uri, ori de câte ori este posibil. Un produs cartezian între două relaţii
este de obicei mult mai scump (ca şi cost) decât un join între cele
două relaţii, deoarece primul generează concatenarea tuplurilor în
mod exhaustiv şi poate genera un rezultat foarte mare. Această
transformare se poate realiza folosind legătura dintre produs
cartezian, join şi selecţie.
Regula de optimizare 3. Dacă sunt mai multe join-uri atunci cel care
se execută primul este cel mai restrictiv. Un join este mai restrictiv
decât altul dacă produce o relaţie mai mică. Se poate determina care
join este mai restrictiv pe baza factorului de selectivitate sau cu
ajutorul informaţiilor statistice. Algebric, acest lucru se poate realiza
folosind regula de transformare 2.
Regula de optimizare 4. Proiecţiile se execută la început pentru a
îndepărta atributele nefolositoare. Dacă un atribut al unei relaţii nu
este folosit în operaţiile ulterioare atunci trebuie îndepărtat. În felul
acesta se va folosi o relaţie mai mică în operaţiile ulterioare. Aceasta
se poate realiza folosind comutarea proiecţiei cu join-ul.
Exemple curs!!!
36

Regulile lui Codd


Caracteristici ale modelului relaţional:
• nu există tupluri identice;
• ordinea liniilor şi a coloanelor este arbitrară;
• articolele unui domeniu sunt omogene;
• fiecare coloană defineşte un domeniu distinct şi nu se poate repeta în
cadrul aceleiaşi relaţii;
• toate valorile unui domeniu corespunzătoare tuturor cazurilor nu mai
pot fi descompuse în alte valori (sunt atomice).

Avantajele modelului relaţional:


• fundamentare matematică riguroasă;
• independenţă fizică a datelor;
• posibilitatea filtrărilor;
• existenţa unor structuri de date simple;
• realizarea unei redundanţe minime;
• supleţe în comunicarea cu utilizatorul neinformatician.

Ca limite ale modelului relaţional putem menţiona:


• rămâne totuşi redundanţă,
• ocupă spaţiu,
• apar fenomene de inconsistenţă,
• nu există mecanisme pentru tratarea optimă a cererilor recursive,
• nu lucrează cu obiecte complexe,
• nu există mijloace perfecţionate pentru exprimarea constrângerilor de
integritate,
• nu realizează gestiunea totala a datelor distribuite,
• nu realizează gestiunea cunoştinţelor.

În anul 1985, E.F. Codd a publicat un set de 13 reguli în raport cu


care un sistem de gestiune a bazelor de date poate fi apreciat ca relaţional.
Nici un sistem de gestiune a bazelor de date pus în vânzare pe piaţa
comercială nu respectă absolut toate regulile definite de Codd, dar acest
lucru nu împiedică etichetarea acestor sisteme drept relaţionale.
37

Nu trebuie apreciat un SGBD ca fiind relaţional sau nu, ci măsura în


care acesta este relaţional, deci numărul regulilor lui Codd pe care le
respectă.
Regula 1 – regula gestionării datelor. Un SGBD relaţional trebuie să
fie capabil să gestioneze o bază de date numai prin posibilităţile sale
relaţionale.
Regula 2 – regula reprezentării informaţiei. Într-o bază de date
relaţională, informaţia este reprezentată la nivel logic sub forma unor
tabele ce poartă numele de relaţii.
Regula 3 – regula accesului garantat la date. Fiecare valoare dintr-o
bază de date relaţională trebuie să poată fi adresată în mod logic printr-o
combinaţie formată din numele relaţiei, valoarea cheii primare şi numele
atributului.
Regula 4 – regula reprezentării informaţiei necunoscute. Un sistem
relaţional trebuie să permită utilizatorului definirea unui tip de date numit
„null“ pentru reprezentarea unei informaţii necunoscute la momentul
respectiv.
Regula 5 – regula dicţionarelor de date. Asupra descrierii bazelor de
date (informaţii relative la relaţii, vizualizări, indecşi etc.) trebuie să se
poată aplica aceleaşi operaţii ca şi asupra datelor din baza de date.
Regula 6 – regula limbajului de interogare. Trebuie să existe cel
puţin un limbaj pentru prelucrarea bazei de date.
Regula 7 – regula de actualizare a vizualizării. Un SGBD trebuie să
poată determina dacă o vizualizare poate fi actualizată şi să stocheze
rezultatul interogării într-un dicţionar de tipul unui catalog de sistem.
Regula 8 – regula limbajului de nivel înalt. Regulile de prelucrare
asupra unei relaţii luată ca întreg sunt valabile atât pentru operaţiile de
regăsire a datelor, cât şi asupra operaţiilor de inserare, actualizare şi
ştergere a datelor.
Regula 9 – regula independenţei fizice a datelor: Programele de
aplicaţie şi activităţile utilizatorilor nu depind de modul de depunere a
datelor sau de modul de acces la date.
Regula 10 – regula independenţei logice a datelor. Programele de
aplicaţie trebuie să fie transparente la modificările de orice tip efectuate
asupra datelor.
Regula 11 – regula independenţei datelor din punct de vedere al
integrităţii. Regulile de integritate trebuie să fie definite într-un sublimbaj
relaţional, nu în programul de aplicaţie.
38

Regula 12 – regula independenţei datelor din punct de vedere al


distribuirii. Distribuirea datelor pe mai multe calculatoare dintr-o reţea de
comunicaţii de date, nu trebuie să afecteze programele de aplicaţie.
Regula 13 – regula versiunii procedurale a unui SGBD. Orice
componentă procedurală a unui SGBD trebuie să respecte aceleaşi
restricţii de integritate ca şi componenta relaţională.
Deoarece regulile lui Codd sunt prea severe pentru a fi respectate de
un SGBD operaţional, s-au formulat criterii minimale de definire a unui
sistem de gestiune relaţional.
Un SGBD este minimal relaţional dacă:
• toate datele din cadrul bazei sunt reprezentate prin valori în tabele;
• nu există pointeri observabili de către utilizator;
• sistemul suportă operatorii relaţionali de proiecţie, selecţie şi
compunere naturală, fără limitări impuse din considerente interne.
Un SGBD este complet relaţional dacă este minimal relaţional şi
satisface în plus condiţiile:
• sistemul suportă restricţiile de integritate de bază (unicitatea cheii
primare, constrângerile referenţiale, integritatea entităţii).
• sistemul suportă toate operaţiile de bază ale algebrei relaţionale.

NORMALIZAREA RELAŢIILOR
În procesul modelării unei baze de date relaţionale, o etapă importantă
o reprezintă normalizarea relaţiilor conceptuale (Codd, 1972), adică
obţinerea de relaţii „moleculare“fără a pierde nimic din informaţie pentru a
elimina:
• redundanţa;
• anomaliile reactualizării informaţiilor.
Tehnica normalizării permite obţinerea unei scheme conceptuale
rafinate printr-un proces de ameliorare progresivă a unei scheme conceptuale
iniţiale a bazei de date relaţionale. După fiecare etapă de ameliorare, relaţiile
bazei de date ating un anumit grad de perfecţiune, deci se află într-o anumită
formă normală. Trecerea unei relaţii dintr-o formă normală în alta, presupune
eliminarea unei anumit tip de dependenţe nedorite, care sunt transformate în
dependenţe admisibile, adică dependenţe care nu provoacă anomalii.
39

Procesul de ameliorare a schemei conceptuale trebuie:


• să garanteze conservarea datelor, adică în schema conceptuală
finală trebuie să figureze toate datele din cadrul schemei iniţiale;
• să garanteze conservarea dependenţelor dintre date, adică în
schema finală fiecare dependenţă trebuie să aibă determinantul şi
determinatul în schema aceleiaşi relaţii;
• să reprezinte o descompunere minimală a relaţiilor iniţiale,
adică nici una din relaţiile care compun schema finală nu trebuie
să fie conţinută într-o altă relaţie din această schemă.
Există două metode pentru a modela baze de date relaţionale fără
anomalii sau pierderi de informaţie.
• Schema descompunerii pleacă de la o schemă relaţională
universală ce conţine toate atributele BD. Schema se descompune
prin proiecţii succesive în subrelaţii. Descompunerea se opreşte
când continuarea ei ar duce la pierderi de informaţie. Algoritmii
de descompunere se bazează, în general, pe descrierea formală a
dependenţei dintre atribute.
• Schema sintezei pleacă de la o mulţime de atribute
independente. Utilizând proprietăţi de semantică şi legături între
atribute se pot compune noi relaţii, astfel încât, acestea să nu
sufere de anumite anomalii. Algoritmii se bazează, în general, pe
teoria grafurilor pentru a reprezenta legătura între atribute.

Dependenţe funcţionale
O relaţie universală este o relaţie ce grupează toate atributele care
modelează sistemul real cercetat. Fie E, mulţimea dependenţelor
considerate de proiectantul bazei pentru o schemă relaţională sau pentru o
relaţie universală. Plecând de la o mulţime de proprietăţi formale ale
dependenţelor, proprietăţi considerate drept reguli de deducţie (axiome),
poate fi obţinută mulţimea maximală de dependenţe asociate lui E. Această
mulţime defineşte închiderea lui E.
Fie E mulţimea dependenţelor unei relaţii şi p1, p2, ..., pr, r ≥ 1,
proprietăţi formale ale acestor dependenţe. Dacă există o mulţime E′, astfel
încât orice dependenţă a mulţimii E este derivabilă din E′ prin aplicarea
proprietăţilor p1, p2, ..., pr, atunci mulţimea E′ defineşte acoperirea lui E
pentru proprietăţile p1, p2, ..., pr.
E′ este o acoperire minimală pentru E, dacă nu există nici o
submulţime proprie, nevidă a lui E′ care să fie o acoperire pentru E.
40

Evident, E şi E′ au închideri identice, deci dispun de acelaşi potenţial


informaţional!
Fie R(A1, A2, ..., An) o schemă relaţională şi fie X, Y submulţimi de
atribute ale lui R. X determină funcţional Y sau Y depinde funcţional (FD)
de X, dacă pentru orice relaţie r (valoare curentă a lui R) nu există două
tupluri care să aibă aceleaşi valori pentru atributele lui X şi să aibă valori
diferite pentru cel puţin un atribut din Y. Cu alte cuvinte, o valoare a lui X,
determină unic o valoare a lui Y.
Notaţia utilizată pentru desemnarea dependenţei funcţionale este X
→ Y. X este numit determinant, iar Y este numit determinat (sau
dependent). Dependenţa funcţională X → Y este trivială dacă Y ⊆ X.
Comparând toate submulţimile de atribute ale unei relaţii şi
determinând legăturile dintre ele, se pot obţine toate dependenţele
funcţionale pe care o relaţie le satisface. Această abordare nu este eficientă,
consumând mult timp.
Există posibilitatea ca, ştiind anumite dependenţe funcţionale şi
utilizând reguli de deducţie, să fie obţinute toate dependenţele funcţionale.
Fie X, Y, Z, W mulţimi de atribute ale unei scheme relaţionale R şi fie
următoarele axiome:
Ax1 – reflexivitate. X → X. Mai general, dacă Y ⊆ X, atunci X → Y.
Ax2 – creşterea determinantului. Pot fi considerate următoarele
formulări echivalente pentru această axiomă.
1. Dacă X → Y şi X ⊆ Z, atunci Z → Y.
2. Dacă X → Y şi W ⊆ Z, atunci X ∪ Z → Y ∪ W.
3. Dacă X → Y atunci X ∪ Z → Y ∪ Z.
4. Dacă X → Y atunci X ∪ Z → Y.
Ax3 – tranzitivitate. Dacă X → Y şi Y → Z, atunci X → Z.
O mulţime de axiome este completă dacă şi numai dacă plecând de
la o mulţime de dependenţe E se pot obţine toate dependenţele închiderii
lui E, utilizând axiomele mulţimii.
O mulţime de axiome este închisă dacă şi numai dacă plecând de la
o mulţime de dependenţe E, nu poate fi dedusă cu ajutorul axiomelor o
dependenţă care nu aparţine închiderii lui E. (nu obţin altele!)
Ullman a demonstrat că axiomele Ax1 – Ax3, numite axiomele lui
Amstrong, reprezintă o mulţime închisă şi completă de axiome. Consecinţa
41

acestui rezultat este că închiderea lui E reprezintă mulţimea


dependenţelor deduse din E, prin aplicarea axiomelor lui Amstrong!!!
Nu toate dependenţele funcţionale sunt folositoare pentru modelarea
relaţională. O dependenţă funcţională X → Y se numeşte dependenţă
funcţională totală (FT), dacă şi numai dacă nu există nici o submulţime
proprie X′ ⊂ X, astfel încât X′ → Y. Dacă există o submulţime proprie X′ ⊂
X, astfel încât X′ → Y, atunci dependenţa funcţională X → Y este parţială.
În axioma Ax2, dependenţa Z → Y este o dependenţă funcţională parţială.
În cazul dependenţei funcţionale totale, axiomele lui Amstrong se
reduc la o axiomă unică şi anume pseudo-tranzitivitatea:
dacă X → Y şi W ∪ Y → Z, atunci W ∪ X → Z.
Această axiomă este o regulă de deducţie completă pentru total
dependenţe:
• pseudo-tranzitivitatea implică tranzitivitatea (W = ∅);
• reflexivitatea nu poate fi utilizată pentru a obţine dependenţe
totale;
• reflexivitatea şi pseudo-tranzitivitatea implică creşterea.
Dacă F este o mulţime de dependenţe funcţionale totale, atunci
închiderea pseudo-tranzitivă F+ a acestei mulţimi este reuniunea
mulţimilor dependenţelor funcţionale totale care pot fi obţinute din F
folosind axioma de pseudo-tranzitivitate.
Două mulţimi de dependenţe funcţionale totale sunt echivalente
dacă au închideri pseudo-tranzitive identice. Pentru a modela scheme
relaţionale se consideră mulţimi minimale de dependenţe funcţionale totale,
capabile să genereze toate închiderile pseudo-tranzitive. Aceste mulţimi
definesc acoperiri minimale.
O mulţime de dependenţe funcţionale totale F* asociată unei mulţimi
de atribute A defineşte o acoperire minimală dacă satisface următoarele
proprietăţi:
• nici o dependenţă funcţională din F* nu este redundantă;
• toate dependenţele funcţionale totale între submulţimi ale lui A
sunt în închiderea pseudo-tranzitivă a lui F*.
Orice mulţime de dependenţe totale are cel puţin o acoperire minimală.
Alegerea acoperirii minimale este punctul de start în modelarea schemelor
relaţionale.
42

Dependenţele funcţionale între atributele bazei pot fi reprezentate


grafic. Fie A = {A1, A2, ..., An} o mulţime de atribute şi fie o mulţime de
dependenţe funcţionale {Xi → Aj}, unde Xi este o submulţime a lui A.
Graful dependenţelor funcţionale este un graf direcţionat bipartit,
definit astfel:
1. pentru fiecare atribut Aj există un singur nod având eticheta Aj;
2. pentru fiecare dependenţă funcţională de forma Ai → Aj, există un
arc de la Ai la Aj;
3. pentru fiecare dependenţă funcţională de forma Xi → Aj, unde
mulţimea Xi este definită de Xi = {Ai1, ..., Aip} cu p > 1, există un
nod auxiliar etichetat prin Xi şi o mulţime de arce plecând de la
Ai1, ..., Aip pentru a obţine pe Xi şi printr-un arc adiţional de la Xi la
Aj. Nodurile Xi se reprezintă prin dreptunghiuri.
Exemplu:
1. Graful dependenţelor funcţionale pentru schema relaţională
CONSUMATOR_DE_VIN(W#, localitate, varsta, calitate, regiune, tara, D#,
nume, data, cantitate) şi acoperirea minimală.

localitate

W#
calitate
varsta
regiune
tara

data cantitate

D#

nume

localitate

W#
calitate
varsta
43

regiune
tara

data cantitate

D#

nume
2. Graful dependenţelor funcţionale pentru schema relaţională
OBIECTIV_INVESTITIE. Dependentele sunt deduse din regulile impuse de
beneficiar!
aria_construita
denumire
nr_certificat_urbanizare
cod_obiectiv# adresa
nr_aut_construtie
nr_contract cod_contractant

Necesitatea normalizării

Anomaliile care apar în lucrul cu baza de date se produc datorită


dependenţelor care există între datele din cadrul relaţiilor bazei de date.
Dependenţele sunt plasate greşit în tabele!!!
Avion
A# nume capacitate localitate
1 AIRBUS 250 PARIS
2 AIRBUS 250 PARIS
3 AIRBUS 250 LONDRA
4 CAR 100 PARIS
5 B707 150 LONDRA
6 B707 150 LONDRA

Constrângere:
toate avioanele cu acelaşi nume au aceeaşi capacitate.
Datorită dependenţei introduse pot exista: anomalii la inserare,
modificare sau ştergere, redundanţă în date, probleme de reconexiune.
44

1. Redundanţă logică. Cuplul (AIRBUS, 250) apare de trei ori.


2. Anomalie la inserţie. S-a cumpărat un B727 cu 150 locuri. El
poate fi inserat în relaţia AVION doar dacă se defineşte o nouă
valoare pentru cheia primară.
3. Anomalie la ştergere. Dacă este ştearsă înregistrarea pentru care
A# este 4, atunci se pierde informaţia că un avion CAR are
capacitatea 100.
4. Anomalie la modificare. Dacă se modifică capacitatea lui B707
de la 150 la 170, atunci costul modificării este mare pentru a
modifica toate înregistrările, iar dacă se modifică doar o
înregistrare atunci constrângerea nu va mai fi verificată.
5. Problema reconexiunii. Considerăm schemele relaţionale:
AVION1 = PROJECT(AVION, A#, nume)
AVION22 = PROJECT(AVION, nume, capacitate, localitate)
AVION3 = JOIN(AVION1, AVION2).
Se observă că schema AVION3 este diferită de AVION.
Apare un tuplu nou: (3, AIRBUS, 250, PARIS).

Anomaliile au apărut datorită dependenţei funcţionale (constrângerii)


introduse anterior!!!
Normalizarea are drept scop:
• suprimarea redundanţei logice,
• evitarea anomaliilor la reactualizare,
• rezolvarea problemei reconexiunii.
Există o teorie matematică a normalizării al cărei autor este E.F.
Codd. Soluţia: construirea unor tabele standard (forme normale).
Normalizarea este procesul reversibil de transformare a unei relaţii, în
relaţii de structură mai simplă. Procesul este reversibil în sensul că nici o
informaţie nu este pierdută în timpul transformării. O relaţie este într-o formă
normală particulară dacă ea satisface o mulţime specificată de constrângeri.
Procesul normalizării se realizează plecând de la o relaţie universală ce
conţine toate atributele sistemului de modelat, plus o mulţime de anomalii.
Orice formă normală se obţine aplicând o schemă de descompunere. Există
două tipuri de descompuneri.
• Descompuneri ce conservă dependenţele. Această
descompunere presupune desfacerea relaţiei R în proiecţiile R1,
R2, ..., Rk, astfel încât dependenţele lui R sunt echivalente (au
45

închideri pseudo-tranzitive identice) cu reuniunea dependenţelor


lui R1, R2, ..., Rk.
• Descompuneri fără pierderi de informaţie (L-join). Această
descompunere presupune desfacerea relaţiei R într-o mulţime de
proiecţii R1, R2, ..., Rj, astfel încât pentru orice realizare a lui R
este adevărată relaţia:
R = JOIN(ΠB1 (R), ΠB2 (R), ...,ΠBj (R))
unde, pentru 1 ≤ k ≤ j, Bk reprezintă mulţimea atributelor corespunzătoare
proiecţiei Rk (Rk = ΠBk (R)). Prin urmare, relaţia iniţială poate fi reconstruită
considerând compunerea naturală a relaţiilor obţinute prin descompunere.
Formele normale sunt obţinute prin descompuneri fără pierderi de
informaţie.
O descompunere fără pierdere de informaţie, utilizată în procesul
normalizării, este dată de regula Casey-Delobel:
Fie R(A) o schemă relaţională şi fie α, β, γ o partiţie a lui A.
Presupunem că α determină funcţional pe β. Atunci:
R(A) = JOIN(Πα∪β(R), Πα∪γ(R)).
α∪β  mulţimea atributelor care intervin în dependenţele funcţionale;
α∪γ  reprezintă reuniunea determinantului cu restul atributelor lui A.

Relatia universala

FN1
FN2
FN3
BCNF
FN4
FN5

Pentru exemplul analizat anterior:


α = {nume},
β = {capacitate},
γ = {A#, localitate}.
Aplicând Casey-Delobel se obţin schemele:
AVION1(nume#, capacitate)
AVION2)A#, nume, localitate).
46

Se observă că anomaliile comentate au dispărut!


AVION1
Nume Capacitate
AIRBUS 150
CAR 100
B707 150

AVION2
A# Nume Localitate
1 AIRBUS PARIS
2 AIRBUS PARIS
3 AIRBUS LONDRA
4 CAR PARIS
5 B707 LONDRA
6 B707 LONDRA

Forma normală (FN1)


O relaţie este în prima formă normală dacă fiecărui atribut care o
compune îi corespunde o valoare indivizibilă (atomică).
Exemplu: variante pentru a implementa FN1 pentru tabelul MASINA:
Persoana Vehicul
Eu R25 - W14 - R21
Tu 205
El R5 - 305
noi BX - 305 - R12 - R25
Varianta 1
Persoana Vehicul
Eu R25
Eu W14
Eu R21
Tu 205
El R5
El 305
Noi BX
Noi 305
Noi R12
Noi R25
47

Varianta 2

Persoana Prima Doi Trei Patru


Eu R25 W14 R21
Tu 205
El R5 305
Noi BX 305 R12 R25
Varianta 3 (4 tabele)
Masina 31 (similar se definesc Masina_32, Masina_33, Masina_34)..

Persoana Vehicul
Eu R25
Tu 205
El R5
Noi BX
Masina_34

Persoana Vehicul
Noi R25

Forma normală 2 (FN2)


O relaţie R este în a doua formă normală dacă şi numai dacă:
• relaţia R este în FN1;
• fiecare atribut care nu este cheie (nu participă la cheia primară)
este dependent de întreaga cheie primară.
atasat_la
Cod_salariat# Job_cod Nr_proiect# Functia Suma
S1 Programator P1 Supervizor 60
S1 Programator P2 Cercetator 25
S1 Programator P3 Auxiliar 10
S3 Vanzator P3 Supervizor 60
S5 Inginer P3 Supervizor 60

atasat_2a
Cod_salariat# Nr_proiect# Functia Suma
S1 P1 Supervizor 60
S1 P2 Cercetator 25
S1 P3 Auxiliar 10
S3 P3 Supervizor 60
48

S5 P3 Supervizor 60

atasat_2b
Cod_salariat# Job_cod
S1 Programator
S3 Vanzator
S5 Inginer

A doua condiţie exprimă necesitatea total dependenţei de cheia


primară. Această formă normală interzice manifestarea unor dependenţe
funcţionale parţiale în cadrul relaţiei R!!!
Pentru a obţine o relaţie FN2 se poate aplica regula Casey-Delobel.
Fie relaţia R(K1, K2, X, Y), unde K1 şi K2 definesc cheia primară, iar X şi Y
sunt mulţimi de atribute, astfel încât K1 → X. Din cauza dependenţei
funcţionale K1 → X care arată că R nu este în FN2, se înlocuieşte R (fără
pierdere de informaţie) prin două proiecţii R1(K1, K2, Y) şi R2(K1, X).

K1 K2

Exemplu. Presupunem că un şantier poate executa mai multe lucrări


de bază şi că o lucrare poate fi executată de mai multe şantiere.
LUCRARE(cod_obiectiv#, cod_lucrare#, nume);
SANTIER(nr_santier#, specialitate, sef);
EXECUTA(cod_obiectiv#, cod_lucrare#, nr_santier#, descriere,
functie, conducator, data_inceput, data_sfarsit).
Pentru relaţia EXECUTA sunt evidente dependenţele:
{cod_obiectiv#, cod_lucrare#} → {data_inceput, data_sfarsit},
{cod_obiectiv#, cod_lucrare#, nr_santier#} → {descriere, functie,
conducator}.
49

Relaţia EXECUTA este în FN1, dar nu este în FN2 deoarece


atributele data_inceput şi data_sfarsit nu depind de numărul şantierului,
deci nu depind de întreaga cheie primară. Pentru a obţine o relaţie în FN2
se aplică regula Casey Delobel şi relaţia EXECUTA se desface în:
EXECUTA_1(cod_obiectiv#, cod_lucrare#, nr_santier#, descriere,
functie, conducator)
EXECUTA_2(cod_obiectiv#, cod_lucrare#, data_inceput,
data_sfarsit).
Forma normală 3 (FN3)
Intuitiv, o relaţie R este în a treia formă normală dacă şi numai dacă:
• relaţia R este în FN2;
• fiecare atribut care nu este cheie (nu participă la o cheie) depinde
direct de cheia primară.
Fie R o relaţie, X o submulţime de atribute ale lui R şi A un atribut al
relaţiei R. A este dependent tranzitiv de X dacă există Y astfel încât X → Y
şi Y → A (A nu aparţine lui Y şi Y nu determină pe X). X nu este dependent
funcţional de Y sau A!
De exemplu, dacă K1, K2, K3 → A1 şi dacă K1, K2, A1 → A2, atunci
K1, K2, K3 → K1, K2, A1 şi K1, K2, A1 → A2. Prin urmare, A2 este dependent
tranzitiv de K1, K2, K3.
Formal, o relaţie R este în a treia formă normală dacă şi numai dacă:
• relaţia R este în FN2;
• fiecare atribut care nu este cheie (nu participă la o cheie) nu este
dependent tranzitiv de nici o cheie a lui R.
O relaţie este în FN3 dacă şi numai dacă fiecare atribut (coloană)
care nu este cheie, depinde de cheie, de întreaga cheie şi numai de cheie.
Pentru a obţine o relaţie FN3 se poate aplica regula Casey-Delobel.
Fie relaţia R(K, X1, X2, X3), unde atributul X2 depinde tranzitiv de K,
iar K este cheia primară a lui R. Presupunem că K → X1 → X2. Din cauza
dependenţei funcţionale X1 → X2 care arată că R nu este în FN3, se
înlocuieşte R (fără pierdere de informaţie) prin două proiecţii R1(K, X1, X3)
şi R2(X1, X2).

K X1 X2

X3
50

Exemplu: Tabelul atasat_2a nu este in FN3. De ce?


atasat_3a
Cod_salariat# Nr_proiect# Functia
S1 P1 Supervizor
S1 P2 Cercetator
S1 P3 Auxiliar
S3 P3 Supervizor
S5 P3 Supervizor
atasat_3b
Functia Suma
Supervizor 60
Cercetator 25
Auxiliar 10
Exemplu. În tabelul EXECUTA1(cod_obiectiv#, cod_lucrare#,
nr_santier#, descriere, functie, conducator) continuă să existe redundanţă în
date.
Atributul conducator depinde indirect de cheia primară prin
intermediul atributului functie. Între atributele relaţiei există dependenţele:
{cod_obiectiv#, cod_lucrare#, nr_santier#} → {descriere},
{cod_obiectiv#, cod_lucrare#, nr_santier#} → {functie} → {conducator}.
Pentru a aduce relaţia EXECUTA_1 în FN3 se aplică regula Casey-
Delobel. Relaţia se desface, prin eliminarea dependenţelor funcţionale
tranzitive, în proiecţiile:
EXECUTA11(cod_obiectiv#, cod_lucrare#, nr_santier#, descriere, functie)
EXECUTA12(functie, conducator).

Schema de sinteză pentru obţinerea lui FN3


Algoritmul de sinteză construieşte o acoperire minimală F a
dependenţelor funcţionale totale. Se elimină atributele şi dependenţele
funcţionale redundante. Mulţimea F este partiţionată în grupuri Fi, astfel
încât în fiecare grup Fi sunt dependenţe funcţionale care au acelaşi membru
stâng şi nu există două grupuri având acelaşi membru stâng. Fiecare grup Fi
produce o schemă FN3. Algoritmul realizează o descompunere ce conservă
dependenţele.
Algoritm SNF3 (aducerea unei relaţii în FN3 prin utilizarea unei
scheme de sinteză):
51

1. Se determină F o acoperire minimală a lui E (mulţimea


dependenţelor funcţionale).
2. Se descompune mulţimea F în grupuri notate Fi, astfel încât în
cadrul fiecărui grup să existe dependenţe funcţionale având
aceeaşi parte stângă.
3. Se determină perechile de chei echivalente (X, Y) în raport cu F
(două mulţimi de atribute X, Y sunt chei echivalente dacă în
mulţimea de dependenţe E există atât dependenţa X Y, cât şi
dependenta Y  X).
4. Pentru fiecare pereche de chei echivalente: se identifică grupurile
Fi şi Fj care conţin dependenţele funcţionale cu partea stângă X şi
respectiv Y; se formează un nou grup de dependenţe Fi j, care va
conţine dependenţele funcţionale având membrul stâng (X, Y); se
elimină grupurile Fi şi Fj, iar locul lor va fi luat de grupul Fi j.
5. Se determină o acoperire minimală a lui F, care va include toate
dependenţele X → Y, unde X şi Y sunt chei echivalente (celelalte
dependenţe sunt redundante).
6. Se construiesc relaţii FN3 (câte o relaţie pentru fiecare grup de
dependenţe funcţionale).

Se observă că algoritmul solicită


• determinarea unei acoperiri minimale (algoritmii EAR şi EDF);
• determinarea închiderii (A + ) unei mulţimi de atribute A în raport
cu mulţimea de dependenţe funcţionale E (algoritm AIDF).
Determinarea acoperirii minimale presupune eliminarea atributelor şi
dependenţelor redundante. Acoperirea minimală nu este unică şi depinde de
ordinea în care sunt eliminate aceste atribute şi dependenţe redundante.

Algoritm EAR (elimină atributele redundante din determinantul


dependenţelor funcţionale)
Pentru fiecare dependenţă funcţională din E şi pentru fiecare atribut
din partea stângă a unei dependenţe funcţionale:
Pas1. Se elimină atributul considerat.
Pas2. Se calculează închiderea părţii stângi reduse.
Pas3. Dacă închiderea conţine toate atributele din determinantul
dependenţei, atunci atributul eliminat la pasul 1 este redundant şi rămâne
eliminat. În caz contrar, atributul nu este redundant şi se reintroduce în
partea stângă a dependenţei funcţionale.
52

Algoritm EDF (elimină dependenţele funcţionale redundante din E)


Pentru fiecare dependenţă funcţională X Y din E:
Pas1. Se elimină dependenţa din E.
Pas2. Se calculează închiderea X + , în raport cu mulţimea redusă de
dependenţe.
Pas3. Dacă Y este inclus în X + , atunci dependenţa X Y este
redundantă şi rămâne eliminată. În caz contrar, se reintroduce în E.

Algoritm AIDF (determină închiderea lui A)


Pas1. Se caută dacă există în E dependenţe X Y pentru care
determinantul X este o submulţime a lui A, iar determinatul Y nu este
inclus în A.
Pas2. Pentru fiecare astfel de dependenţă funcţională se adaugă
mulţimii A atributele care constituie determinatul dependenţei.
Pas3. Dacă nu mai există dependenţe funcţionale de tipul de la pasul
1, atunci A + = A.
Exemplu:
Fie dependenţele funcţionale:
f1: F  N; f2: F  P; f3: P, F, N  U;
F4: P  C; f5: P  T; f6: C  T; f7: N  F.
Pas1 (suprimarea atributelor redundante). Atributul A i este
redundant în dependenţa funcţională A 1 , A 2 , …A i , …A n  Z, dacă
dependenţa funcţională A1 , A 2 , …A i − 1 , A i + 1 …A n  Z poate fi
generată plecând de la mulţimea iniţială de dependenţe (E) şi de la
axiomele considerate.
f1: F  N; f3: P, F, N  U sau N, P, F  U;
Aplicând axioma de pseudotranzitivitate se obţine:
F, P, F  U  P, F  U

Pas2 (suprimarea dependenţelor funcţionale redundante).


Dependenţa funcţională f este redundantă în E dacă E + = (E - f) + , unde E +
reprezintă închiderea lui E.
Se observă că f5 este redundantă (poate fi obţinută din f4 şi f6). La
sfârşitul etapei se obţine:
f1: F  N; f2: F  P; f3: P, F  U; P este redundant =>F-->U
53

f4: P  C; f6: C  T; f7: N  F.

Pas3 (gruparea dependenţelor având acelaşi membru stâng).


F1 = {f1, f2, f3}; F2 = {f4}; F3 = {f6}; F4 = {f7}

Pas4 (regruparea mulţimilor F i si F j dacă există dependenţe de


forma X  Y şi Y  X, unde X reprezinta partea stanga a dependenţei lui
F i şi Y este partea stângă a dependenţei lui F j .
Din F1 şi F4 se obţine:
G1 = {f1, f2, f3, f7}; G2 = {f4}; G3 = {f6}.
Pas5 (generarea relaţiilor FN3).
R1(F#, N, P, U); R2(P#, C); R3(C#, T).
De remarcat: R1 nu este in BCNF! De ce? Exista dependenta N -->F.
Exerciţiu:
Presupunem că o parte din activităţiile de pe un aeroport sunt
caracterizate de atributele:
A -- număr zbor;
B -- tip avion;
C -- aeroport plecare;
D -- aeroport sosire;
E -- linia aeriană;
F -- ora plecării;
G -- capacitate;
H -- număr locuri rezervate;
I -- data;
J -- tarif;
K -- prestaţii la bord.
Între aceste atribute există legături exprimate prin dependenţele:
A  BEFG
ACDI  H
CD  J
CDF  K
BG
CF  ABE
AC  D
ABD  C
EG  B
54

Aplicând algoritmul de sinteză se obţin relaţiile:


R1(B#, G)
R2(E#, G#, B)
R3(A#, B, E, F)
R4(C#, D#, J)
R5(A#, C#, I#, H)
R6(A, C, D, F, K) în care cheile primare pot să fie oricare dintre:
AD sau AC sau CF.
Încercaţi să justificaţi acest rezultat!!!
Forma normală Boyce-Codd (BCNF)
Determinantul este un atribut sau o mulţime de atribute
neredundante, care constituie un identificator unic pentru alt atribut sau altă
mulţime de atribute ale unei relaţii date.
Intuitiv, o relaţie R este în forma normală Boyce-Codd dacă şi
numai dacă fiecare determinant este o cheie candidat.
Formal, o relaţie R este în forma normală Boyce-Codd dacă şi
numai dacă pentru orice dependenţă funcţională totală X → A, X este o
cheie (candidat) a lui R.

Regula Casey Delobel pentru R(K1#, K2#, X) presupunând că există


dependenţa: X  K2.  R1(K1#, X) şi R2(X#, K2)
K1 K2

X
Exemplu:
ADRESA(cod_parsoana#, telefon#, adresa)

cod_persoana

adresa
55

telefon

În dependenţa adresa  telefon se observă că determinantul nu este


o cheie candidat. Relaţia ADRESA se desface în:
ADRESA_1(cod_persoana#, adresa);
ADRESA_2(adresa#, telefon).
Relaţiile sunt în BCNF, se conservă datele, dar nu se conservă
dependenţele (s-a pierdut cod_persoana, telefon  adresa).
Exemplu:
Relaţia INVESTESTE_IN leagă entităţile INVESTITOR şi
OBIECTIV_INVESTITIE. Ea are schema relaţională:
INVESTESTE_IN(cod_contractant#, cod_obiectiv#, nr_contract,
cota_parte). Între atributele relaţiei există dependenţele:
{cod_contractant#, cod_obiectiv#} → {nr_contract, cota_parte},
{nr_contract} → {cod_obiectiv}.
Se aplică regula Casey-Delobel şi se aduce relaţia în BCNF.
INVESTESTE_IN_1(cod_obiectiv, nr_contract#);
INVESTESTE_IN_2(cod_contractant#, nr_contract, cota_parte).
Pentru ca o relaţie să fie adusă în BCNF nu trebuie în mod
obligatoriu să fie în FN3. Se pot aduce în BCNF şi relaţii aflate în FN1 sau
FN2. Acest lucru este posibil întrucât dependenţele funcţionale parţiale şi
cele tranzitive sunt tot dependenţe noncheie, adică dependenţe ai căror
determinanţi nu sunt chei candidat. Presupunem că R este o relaţie ce
conţine atributele A.
Algoritm TFBCNF (aducerea unei relaţii R din FN1 în BCNF)
1. Dacă relaţia conţine cel mult două atribute, atunci R este în
BCNF şi algoritmul s-a terminat.
2. Dacă relaţia conţine mai mult de două atribute, se consideră toate
perechile (X, Y) de atribute distincte din A.
3. Se determină A1 , închiderea mulţimii A1 = A – {X, Y}.
+

4. Dacă pentru orice pereche (X, Y), X ∉ A1 atunci relaţia R este în


+

BCNF şi algoritmul s-a terminat.


5. În caz contrar (pentru cel puţin o pereche (X, Y), X aparţine lui
A1+), relaţia R nu este în BCNF.
56

6. Se reduce progresiv schema relaţiei şi se reia algoritmul,


exploatând relaţia redusă. Orice relaţie obţinută prin reducerea lui
R şi care este în BCNF se consideră ca făcând parte din
descompunerea lui R în procesul aducerii sale în BCNF.

Forma normală 4 (FN4)


FN4 elimină redundanţele datorate relaţiilor m:n, adică datorate
dependenţei multiple.
Intuitiv, o relaţie R este în a patra formă normală dacă şi numai dacă
relaţia este în BCNF şi nu conţine relaţii m:n independente.
Fie R o relaţie definită pe o mulţime de atribute A = {A1, A2, ..., An}
şi fie X, Y, Z ⊂ A. Se spune că X multidetermină pe Z sau că Z este
multidependent de X :
• dacă pentru fiecare valoare a lui Z în R există numai o valoare
pentru perechea (X, Y);
• dacă valoarea lui Z depinde numai de valoarea lui X.
Acest tip de dependenţă, numită şi multivaloare sau multidependenţă
(MVD) se notează prin X →→ Z.
Intuitiv, multidependenţa reprezintă situaţia în care valoarea
unui atribut (sau a unei mulţimi de atribute) determină o mulţime de
valori a altui atribut (sau mulţimi de atribute)!!!
Multidependenţa X →→ Y poate fi gândită ca o regulă de deducţie:
dacă tuplurile <x, y, z> şi <x, y′, z′> sunt în relaţie la un moment r, atunci la
momentul r sunt în relaţie şi tuplurile <x, y, z′> şi <x, y′, z>.

x y z

x y' z'

x y z'
x y' z

Orice dependenţă funcţională este o multidependenţă. Afirmaţia


inversă nu este adevărată. Dacă X → Y (FD), atunci pentru oricare două
57

tupluri <x, y, z> şi <x, y′, z′>, se obţine y = y′. Prin urmare în relaţie apar
tuplurile <x, y′, z> şi <x, y, z′> şi deci X →→ Y (MVD).
Fie W, V, X, Y şi Z submulţimi de atribute ale unei scheme relaţionale
R. Fiind dată o mulţime T de multidependenţe există o mulţime completă
de axiome (Ax1–Ax8) care permit obţinerea tuturor multidependenţelor ce
se pot deduce din mulţimea T:
Ax1. Dacă Y ⊂ X, atunci X → Y.
Ax2. Dacă X → Y, atunci X ∪ Z → Y ∪ Z.
Ax3. Dacă X → Y şi Y → Z, atunci X → Z.
Ax4. Dacă X →→ Y, atunci X →→ R – {X ∪ Y}.
Ax5. Dacă X →→ Y şi V ⊂ W, atunci W ∪ X →→ V ∪ Y.
Ax6. Dacă X →→ Y şi Y →→ Z, atunci X →→ (Z – Y).
Ax7. Dacă X → Y, atunci X →→ Y.
Ax8. Dacă X →→ Y, Z → W, W ⊂ Y şi Y ∩ Z = ∅, atunci X → W.
O multidependenţă elementară este o multidependenţă care are
părţi stângi şi drepte minimale (nu există X′ ⊂ X şi Y′ ⊂ Y a.i. X′ →→ Y′).
Formal, relaţia R este în a patra formă normală dacă şi numai dacă:
• R este în BCNF;
• orice dependenţă multivaloare este o dependenţă funcţională.
O relaţie BCNF este în FN4 dacă pentru orice multidependenţă
elementară de forma X →→ Y, X este o supercheie a lui R. Aducerea
relaţiilor în FN4 presupune eliminarea dependenţelor multivaloare atunci
când sunt mai mult de una în cadrul unei relaţii.
Regula de descompunere în relaţii FN4. Fie R(X, Y, Z) o schemă
relaţională care nu este în FN4 şi fie X →→ Y o multidependenţă
elementară care nu este de forma „CHEIE →→ atribut“. Această relaţie
este descompusă prin proiecţie în două relaţii:
R = JOIN(ΠX∪Y(R), ΠX∪Z(R)).
Aplicând recursiv această regulă, se obţin relaţii FN4.
Exemplu. Fie relaţia INVESTITIE(cod_contractant#, denumire,
telefon) şi presupunem că un investitor poate avea mai multe numere de
telefon şi că poate investi în mai multe obiective. Între atributele relaţiei
există multidependenţele:
cod_contractant# →→ denumire;
cod_contractant# →→ telefon.
58

Relaţia INVESTITIE este în BCNF. Pentru a aduce relaţia în FN4 o


vom descompune prin proiecţie în două relaţii:
INVESTITIE_1(cod_contractant#, denumire),
INVESTITIE_2(cod_contractant#, telefon).
INVESTITIE = JOIN(INVESTITIE_1, INVESTITIE_2).

Forma normală 5 (FN5)


FN5 îşi propune eliminarea redundanţelor care apar în relaţii m:n
dependente. În general, aceste relaţii nu pot fi descompuse. S-a arătat că o
relaţie de tip 3 este diferită de trei relaţii de tip 2. Există totuşi o excepţie, şi
anume, dacă relaţia este ciclică
Intuitiv, o relaţie R este în forma normală 5 dacă şi numai dacă:
1. relaţia este în FN4;
2. nu conţine dependenţe ciclice.

Dependenţa funcţională şi multidependenţa permit descompunerea


prin proiecţie, fără pierdere de informaţie, a unei relaţii în două relaţii.
Regulile de descompunere (FN1 – FN4) nu dau toate descompunerile
posibile prin proiecţie ale unei relaţii. Există relaţii care nu pot fi
descompuse în două relaţii dar pot fi descompuse în trei, patru sau mai
multe relaţii fără a pierde informaţii. Pentru a obţine descompuneri L-join
în trei sau mai multe relaţii, s-a introdus conceptul de join-dependenţă sau
dependenţă la compunere (JD).
Fie {R1, R2, ..., Rp} o mulţime de scheme relaţionale care nu sunt
disjuncte şi a căror reuniune este R.
R satisface join-dependenţa *{R1, R2, ..., Rp} dacă la fiecare moment
al lui R are loc egalitatea:
R = JOIN(Πα1(R), Πα2(R), ..., Παp(R))
unde αk reprezintă mulţimea atributelor corespunzătoare lui Rk(1 ≤ k ≤ p).
Join-dependenţa *{R1, R2, ..., Rp} are loc în R, dacă R1, R2, ..., Rp este
o descompunere L-join a lui R. Pentru p = 2 se regăseşte multidependenţa.
O join-dependenţă *{R1, R2, ..., Rp} în care una dintre Ri este chiar R,
defineşte o join-dependenţă trivială.
Join-dependenţa generalizează multidependenţa. Într-adevăr,
multidependenţa X →→ Y în relaţia R(X, Y, Z) (deci şi X →→ Z),
corespunde join-dependenţei *{X ∪ Y, X ∪ Z}. Invers, join-dependenţa
*{R1, R2} corespunde multidependenţei R1 ∩ R2 →→ R1 – (R1 ∩ R2).
59

Formal, o relaţie R este în FN5 dacă şi numai dacă orice join-


dependenţă *{R1, R2, ..., Rp} care are loc în R fie este trivială, fie conţine o
supercheie a lui R (adică, o anumită componentă Ri este o supercheie a lui
R). Cu alte cuvinte, o relaţie R este în FN5 dacă orice join-dependenţă
definită pe R este implicată de cheile candidat ale lui R.
Între mulţimile de atribute X, Y şi Z din cadrul relaţiei R există o join-
dependenţă dacă există multidependenţe între fiecare dintre perechile de
mulţimi (X, Y), (Y, Z) şi (X, Z).
Aducerea în FN5 prin eliminarea join dependenţelor!
Exemplu.
Fie schema R(furnizor, cod_consumabil, cantitate, pret).
Reguli:
• un furnizor produce mai multe consumabile;
• nu toţi furnizorii produc aceleaşi consumabile;
• preţul unui consumabil de la un furnizor este variabil şi nu
depinde de cantitate.

Furnizor Cod_consumabil Cantitate Pret


F1 1 500 100
F2 1 100 80
F2 1 500 100
F2 2 500 100

Relaţia este în FN4, dar există redundanţă în date. Relaţia se


descompune prin proiecţie în:
R1(furnizor#, cod_consumabil#)
R2(furnizor#, cantitate, pret)
R3(cod_consumabil#, cantitate, pret).
S-au eliminat redundanţele:
(F2,1) pentru R1;
(F2, 500, 100) pentru R2;
(1, 500, 100) pentru R3.
Se observă că:
JOIN(R1, R2) ≠ R;
JOIN(R1, R3) ≠ R;
JOIN(R3, R2) ≠ R;
JOIN(R1, R2, R3) = JOIN(R1, JOIN(R2, R3)) = R
60

Există join dependenţa:


*{R1(furnizor, cod_consumabil), R2(furnizor, cantitate, pret),
R3(cod_consumabil, cantitate, pret)}

Exemplu.
Fie schema relaţională:
EXECUTANT(nr_santier#, cod_obiectiv#, cod_lucrare#, data_inceput,
data_sfarsit). Un şantier poate executa mai multe lucrări referitoare la
acelaşi obiectiv sau poate executa o lucrare pentru un obiectiv în intervale
de timp distincte. Se presupune că mai multe şantiere pot executa aceeaşi
lucrare, în acelaşi interval de timp sau în intervale de timp distincte.
Relaţia, datorită dependenţelor formulate anterior, nu este în FN5. Ea
se poate desface prin proiecţie în trei relaţii:
EX1(nr_santier#, cod_obiectiv#, cod_lucrare#);
EX2(nr_santier#, data_inceput, data_sfarsit);
EX3(cod_obiectiv#, cod_lucrare#, data_inceput, data_sfarsit).
Sunt evidente relaţiile:
EXECUTANT ≠ JOIN(EX1, EX2),
EXECUTANT ≠ JOIN(EX1, EX3),
EXECUTANT ≠ JOIN(EX2, EX3),
EXECUTANT = JOIN(JOIN(EX1, EX2), EX3).

Concluzii:
1. FN1 → FN2 elimină redundanţele datorate dependenţei netotale
a atributelor care nu participă la o cheie, faţă de cheile lui R. Se
suprimă dependenţele funcţionale care nu sunt totale.
2. FN2 → FN3 elimină redundanţele datorate dependenţei
tranzitive. Se suprimă dependenţele funcţionale tranzitive.
3. FN3 → BCNF elimină redundanţele datorate dependenţei
funcţionale. Se suprimă dependenţele în care partea stângă nu
este o supercheie.
4. BCNF → FN4 elimină redundanţele datorate multidependenţei.
Se suprimă toate multidependenţele care nu sunt şi dependenţe
funcţionale.
61

5. FN4 → FN5 elimină redundanţele datorate dependentei. ciclice.


Se suprimă toate join-dependenţele care nu sunt implicate de o
cheie.
6. BCNF, FN4 şi FN5 corespund la regula că orice determinant este
o cheie, dar de fiecare dată dependenţa cu care se defineşte
determinantul este alta şi anume dependenţa funcţională,
multidependenţa sau join-dependenţa).
7. Descompunerea unei relaţii FN2 în FN3 conservă datele şi
dependenţele, pe când descompunerea unei relaţii FN3 în BCNF
şi, respectiv, a unei relaţii BCNF în FN4 conservă doar datele.

Cateva observaţii şi concluzii referitoare la


PROIECTAREA BAZELOR DE DATE
Proiectarea conceptuală a bazei de date -- construirea
reprezentării conceptuale a bazei de date, care include identificarea tipurilor
importante de entităţi, relaţii, atribute.
1) identificarea tipurilor de entităţi (E);
2) identificarea tipurilor de relaţii (R);
3) identificarea şi asocierea atributelor (A) cu tipurile de E sau R;
4) determinarea domeniilor atributelor;
5) determinarea atributelor chei candidat şi chei primare;
6) specializarea şi generalizarea tipurilor de entităţi;
7) desenarea diagramei E/R;
8) revizuirea modelului de date conceptual local, împreună cu
utilizatorul, pentru a garanta că modelul este o reprezentare
corectă a punctului de vedere al utilizatorului asupra sistemului
real analizat.

Proiectarea logică a bazei de date -- transpunerea reprezentării


conceptuale în structura logică a BD, care include proiectarea relaţiilor.
1) transpunerea modelului conceptual local în modelul de date logic
local:
62

− eliminarea relaţiilor M:N (înlocuirea prin relaţii de tip 1:M sau


prin tabele asociative);
− eliminarea relaţiilor complexe (înlocuirea prin relaţii de tip
1:M);
− eliminarea relaţiilor recursive (înlocuirea prin relaţii
dependente);
− eliminarea atributelor multiple (înlocuirea prin relaţii
dependente;
− reexaminarea relaţiilor 1:1 (sunt într-adevăr 2 relaţii distincte?);
− eliminarea relaţiilor redundante.
2) extragerea relaţiilor din modelul de date logic local pentru a
reprezenta entităţile şi relaţiile (legăturile);
3) normalizarea relaţiilor;
4) validarea modelului conform tranzacţiilor utilizatorului pentru a
garanta că acesta acceptă şi rezolvă operaţiile cerute de către
model (se verifică faptul că modelul furnizează toate informaţiile
cerute de fiecare tranzacţie şi se reprezintă schematic calea
urmată de fiecare tranzacţie, direct în diagrama E/R);
5) desenarea diagramei conceptuale;
6) definirea constrîngerilor de integritate;
7) revizuirea modelului de date conceptual local, împreună cu
utilizatorii;
8) construirea şi validarea modelului de date logic global prin
combinarea modelelor locale:
– îmbinarea modelelor locale (revizuirea E, R, A, CP, CE,
constrîngeri, revizuirea denumirilor, căutarea entităţilor şi
relaţiilor care lipsesc, reactualizarea documentaţiei);
– normalizarea modelului;
– validarea modelului conform tranzacţiilor utilizatorului;
– verificarea în vederea dezvoltării ulterioare;
– desenarea diagramei conceptuale finale;
– revizuirea modelului de date conceptual global, împreună cu
utilizatorii.
Modalităţi pentru asigurarea integrităţii refenţiale!!!
Se specifică constrângeri de existenţă care definesc condiţiile în care
o cheie candidat sau o cheie externă poate fi inserată, ştearsă sau
reactualizată.
63

Exemplu: DOMENIU_contine_CARTE (1:M)


1) Inserare în relaţia "copil" (carte) - se verifică dacă domeniul cărţii
inserate este null sau corespunde unui domeniu existent.
2) Ştergerea în relaţia "copil" (fără probleme).
3) Reactualizarea în relaţia "copil" (similar cazului 1).
4) Inserarea în relaţia "părinte" (domeniu) se face fără probleme.
5) Reactualizarea cheii primare în relaţia "părinte" (dacă există o
apariţie în tabelul "copil" care face referinţă la vechea valoare a
cheii, atunci se pierde integritatea refenţială). Se pot aplica
strategii pentru a asigura integritatea refenţială (vezi 6).
6) Ştergerea unei apariţii din relaţia "părinte" (se pierde integritatea
referenţială dacă se şterge un domeniu de carte, dar există cel
puţin o carte din domeniul respectiv). Există 5 strategii care pot fi
luate în considerare.
− NO ACTION (nici o acţiune)- nu se poate şterge un domeniu
dacă există o carte în domeniul respectiv;
− CASCADE - se şterge domeniul şi automat se şterg toate cărţile
din domeniu ş.a.m.d.;
− SET NULL - se şterge domeniul, iar toate cărţiile din domeniul
respectiv vor avea codul domeniului setat null;
− SET DEFAULT - setare la o valoare prestabilită;
− NO CHECK - când este şters un domeniu de carte, nu se face
nimic pentru a garanta că integritatea refenţială este menţinută
(nici o verificare).

Proiectarea fizică a bazei de date -- implementarea fizică a structurii


logice într-o capacitate de stocare secundară corespunzătoare SGBD-ului
ţintă. Se descriu structurile de stocare şi metodele de acces utilizate pentru
realizarea unui acces eficient la date.
1) Transformarea relaţiilor extrase din modelul de date logic global
într-o formă care să poată fi implementată în SGBD-ul relaţional
ţintă (LDD).
2) Proiectarea (definirea) constrângerilor sistemului real modelat în
SGBD-ul ţintă (CONSTRAINT, declanşatori).
3) Proiectarea reprezentării fizice - determinarea organizării
fişierelor şi a metodelor de acces (indecşi) care vor fi utilizate
pentru a stoca relaţiile de bază (modul în care relaţiile şi tuplurile
vor fi păstrate în cadrul capacităţii de stocare secundare).
64

4) Introducerea unei redundanţe controlate (denormalizarea).


5) Estimarea necesarului de spaţiu pe disc cerut de baza de date.
6) Proiectarea mecanismelor de securitate:
− proiectarea vizualizărilor (VIEW);
− proiectarea regulilor de acces la relaţiile de bază şi la vizualizări
(privilegii, role-uri).
7) Monitorizarea neîntreruptă şi reglarea sistemului operaţional
pentru obţinerea unor performanţe maxime (micşorarea
configuraţiei hardware, timpi de răspuns mai scăzuţi, transfer
eficient etc.).

Comentăm pasul 4 referitor la considerarea introducerii unei


redundanţe controlate (denormalizare). NU există reguli fixe!!! Pasul 4
presupune:
• considerarea datelor derivate (calculate);
• considerarea dublării atributelor şi grupării relaţiilor.

Considerarea datelor derivate


De exemplu, în relaţia PROPRIETATE_DE INCHIRIAT apare drept
câmp, codul persoanei care a tranzacţionat închirierea. Prin urmare, s-ar
putea calcula pentru fiecare angajat, câte proprietăţi a închiriat SAU se poate
introduce în tabelul PERSONAL, un câmp calculat (derivat) ce conţine
numărul proprietăţilor închiriate de acesta.
Considerarea dublării atributelor şi grupării relaţiilor
Dublarea atributelor sau gruparea relaţiilor are ca scop reducerea
numărului de join-uri necesare pentru efectuarea unei interogări.
FILIALA (nr_fil#, strada, zona, oras, codpostal, tel, fax)
Relaţia nu este în FN3 deoarece codpostal determină funcţional
atributele zona şi oras. Aplic FN3 şi se obţine:
FIL(nr_fil#, strada, codpostal, tel, fax
COD_P(zona, oras, codpostal#)
Nu este convenabil, deoarece rareori vom accesa adresa filialei, fără
informaţii referitoare la zona şi oraş. Prin urmare, preferăm FN2.
Vom analiza câteva situaţii concrete de denormalizare.
• combinarea relaţiilor de tip 1:1
• dublarea atributelor care nu sunt chei în relaţii 1:M
65

SELECT p.*, ptr.nume


FROM proprietate_de_inchiriat p, proprietar ptr
WHERE p.nrptr=ptr.nrptr AND nrfil='S3';
Atributul nrptr este codul proprietarului. Dacă se va dubla atributul
nume din relaţia proprietate_de_inchiriat, atunci interogarea devine:
SELECT p.*
FROM proprietate_de_inchiriat p
WHERE nrfil='S3';
Avantaje sau dejavantaje ?!? Depinde de problemele care pot apărea.
• tabele de referinţă (tabele de căutare)
Acestea conţin, de obicei, un cod şi o descriere. De exemplu se poate
defini un tabel căutare "părinte" pentru tipul de proprietate şi modifica
tabelul proprietate_de_inchiriat ("copil") astfel:
TIP_PROPRIETATE(tip, descriere)
PROPRIETATE_DE_INCHIRIAT(nrpte, strada, zona, oras,
coppostal, tipul, nrcamere, chirie, nrptr, nrfiliala, nrpersonal)
Avantaje:
– dacă este modificată descrierea, atunci se va modifica o singură
dată, în tabelul de căutare;
– se reduce dimensiunea relaţiei "copil";
• dublarea atributelor cheii externe într-o relaţie de tip 1:M
pentru simplificarea join-urilor
Să se enumere proprietarii de proprietăţi de închiriat dintr-o filială.
SELECT ptr.nume
FROM proprietate_de_inchiriat p, proprietar ptr
WHERE p.nrptr=ptr.nrptr AND p.nrfil='S3';
Dacă se dublează cheia externă nrfiliala în relaţia PROPRIETAR,
adică se introduce o relaţie directă între FILIALA şi PERSONAL, atunci
cererea devine:
SELECT p.nume
FROM proprietar p
WHERE nrfil='S3';
ATENŢIE! Sunt necesare constrângeri suplimentare asupra cheilor
externe. De exemplu, dacă un proprietar ar închiria prin mai multe filiale
(atribut multiplu), atunci modificările nu mai sunt valabile.
De remarcat că singurul motiv pentru care relaţia
proprietate_de_inchiriat conţine atributul nrfiliala constă în faptul că este
66

posibil ca o proprietate să nu aibă alocat un membru de personal, mai ales la


început, când este preluată iniţial de către agenţie.
• Dublarea atributelor în relaţiile de tip M:N, pentru reducerea
join-urilor.
Presupunem că relaţia M:N dintre chirias şi proprietate_de_inchiriat
a fost descompusă prin introducerea relaţiei intermediare VIZITARE.
Care sunt chiriaşii care au vizitat proprietăţi, dar mai au de făcut
comentarii asupra uneia dintre ele? Personalul de la agenţie are nevoie de
atributul strada atunci când vorbeşte cu chiriaşii.
SELECT p.strada, c.*, v.data
FROM chirias c, vizitare v, proprietate_de_inchiriat p
WHERE v.nrpte = p.nrpte
AND c.nrch = v.nrch AND comentarii IS NULL;
Atributul nrpte este codul proprietăţii, iar nrch este codul chiriaşului.
Dacă se introduce atributul strada în relaţia VIZITARE, atunci
cererea devine:
SELECT v.strada, c.*, v.data
FROM chirias c, vizitare v
WHERE c.nrch = v.nrch AND comentarii IS NULL;

Comentăm pasul 3! Proiectarea reprezentării fizice


Scopul este de a stoca datele în mod eficient. Pentru măsurarea
eficienţei poate fi analizată:
• capacitatea de stocare pe disc;
• timpul de răspuns;
• transferul de tranzacţii (numărul de tranzacţii care pot fi efectuate
într-un anumit interval de timp).
Pentru îmbunătăţirea performanţelor trebuie ca proiectantul să
cunoască cum interacţionează cele 4 componente hardware (memoria
principală, CPU, discul I/O, reţeaua) şi modul cum acestea afectează
performanţele sistemului.
Principiile de bază ale distribuirii datelor pe unităţile de disc:
• fişierele sistemului de operare să fie separate de cele ale BD;
• fişierele principale ale BD să fie separate de fişierele de indexare;
• fişierul jurnalului de recuperare să fie separat de restul BD.
În această etapă se face şi analizarea tranzacţiilor, adică cunoaşterea
funcţionalităţii acestora şi analizarea celor mai importante dintre acestea.
67

Pentru fiecare tranzacţie trebuie detrminat:


• frecvenţa estimată cu care va fi rulată;
• relaţiile şi atributele accesate;
• tipul de acces (inserare, interogare, ştergere sau rectualizare);
• atributele care apar în predicate (condiţii);
• atributele care apar în join-uri;
• constrângerile de timp impuse tranzacţiilor.

Limbaje pentru prelucrarea datelor relaţionale


Unul dintre cele mai mari merite ale modelului relaţional este că prin
intermediul multiplelor sale limbaje de interogare (neprocedurale) permite
utilizatorului, chiar şi neinformatician, să indice rezultatul care îl
interesează, fără a preciza modul în care este obţinut acest rezultat.
O relaţie poate fi definită ca o mulţime, sau ca un predicat. Conform
dualităţii definiţiei unei relaţii, limbajele de prelucrare a datelor relaţionale
pot fi grupate în:
• limbaje algebrice - bazate pe teoria mulţimilor (SEQUEL, SQL);
• limbaje predicative - fondate pe calculul predicatelor.
Limbajele predicative pot fi:
• orientate pe tupluri (QUEL, ALPHA);
• orientate pe domenii (pot fi non-grafice (ILL, FQL) sau grafice).
Limbajele grafice pot fi:
• cu variabile domeniu explicite (QBE);
• fără variabile domeniu explicite (LAGRIF, CUPID, VGQF).
SQL este limbajul standard de descriere a datelor şi acces la
informaţiile din baza de date. SQL nu este un limbaj unic (cu excepţia
standardului care este puţin utilizat), existând peste o 100 de dialecte. Au
fost concepute şi dezvoltate diferite versiuni ale standardului SQL de către
68

ANSI, IBM, Microsoft, Borland, etc. Din păcate, lipsa unui standard unic
SQL are drept consecinţe creşterea costurilor programelor de gestiune a
bazelor de date şi îngreunarea întreţinerii arhitecturilor client/server.
Un grup de specialişti în baze de date s-au reunit sub numele SAG
(SQL Access Group) cu scopul de a construi un limbaj SQL comun şi de a
realiza pentru fiecare dialect un program de conversie din dialect în SQL, şi
invers.
Rezultatul a fost că în:
• 1992, Microsoft a lansat ODBC (Open Database Connectivity)
care este o mulţime de primitive bazate pe activitatea lui SAG;
• 1994 Borland a lansat IDAPI (Integrated Database Application
Programming Interface) care este o bibliotecă de funcţii SQL ce
se pot integra într-un program gazdă.

Limbaje algebrice
În abordarea algebrică, o relaţie este considerată ca o mulţime de
tupluri, iar o bază de date este considerată ca o mulţime de relaţii pe care
sunt definiţi operatorii algebrici.
Există două tipuri de operatori algebrici: mulţime (intersecţie,
reuniune, diferenţă, produs cartezian) şi relaţionali (proiecţie, selecţie,
diviziune, compunere). Operatorii selecţie, proiecţie, produs cartezian,
reuniune şi diferenţă sunt ireductibili şi sunt consideraţi drept operatori de
bază, iar operatorii intersecţie, diviziune şi compunere pot fi deduşi din
operatorii anteriori şi sunt consideraţi operatori derivaţi.
Operatorii limbajului algebric permit exprimarea unor cereri
nerecursive. Dacă cererea este recursivă este necesar un operator special şi
anume închiderea tranzitivă a unei relaţii.
SEQUEL (Structured English as a Query Language) este un
limbaj algebric definit pentru prototipul relaţional SYSTEM–R. Operaţia
fundamentală a limbajului este SELECT, care are forma generală clasică.
Operatorii clasici UNION, INTERSECTION, DIFFERENCE şi
INCLUSION sunt implementaţi în limbaj. SEQUEL este singurul limbaj
relaţional care are integrată închiderea tranzitivă. Limbajul permite
reactualizări asupra bazelor (UPDATE, INSERT, DELETE) şi calculul
unor funcţii elementare (COUNT, SUM, AVG, MAX, MIN). Conceptul de
partiţionare a fost de asemenea introdus în SEQUEL şi realizat cu ajutorul
clauzelor GROUP BY şi HAVING.
O extensie comercială a acestui limbaj, adoptată de aproape toate
SGBD şi considerată drept standard în prelucrarea datelor relaţionale, este
SQL.
69

Limbaje predicative
Limbajele predicative se bazează pe calculul predicatelor. Cererile
sunt exprimate sub forma unor mulţimi de tupluri sau valori pentru care se
specifică, sub forma unor predicate, proprietăţile pe care trebuie să le
îndeplinească.
QUEL este un limbaj predicativ orientat pe tupluri, utilizat de
sistemul INGRES. Limbajul QUEL poate fi utilizat independent sau inclus
în limbajul de programare C. Limbajul este caracterizat de:
• declararea unei variabile tuplu pentru fiecare relaţie (prin
RANGE),
• absenţa cuantificatorilor în expresii,
• utilizarea unor operatori speciali pe mulţimi,
• integrarea operaţiilor aritmetice.
Exemplu.
Să se listeze numele cititorilor care au împrumutat cărţi scrise de
Cioran.
RANGE OF a IS carte
RANGE OF b IS cititor
RANGE OF v IS imprumuta
RETRIEVE b.nume
WHERE (b.codec = v.codec)
AND (v.codel = a.codel)
AND (a.autor = ’Cioran’)
Limbajul acceptă comenzi de inserare (APPEND), reactualizare
(REPLACE), suprimare (DELETE), precum şi funcţii de calcul (MAX, MIN,
SUM, COUNT, AVG). Cuantificatorul existenţial este reprezentat implicit
prin declaraţia RANGE, iar cuantificatorul universal este simulat cu ajutorul
funcţiei COUNT.
Exemplu.
Să se listeze numele cititorilor care au împrumutat toate cărţile din
bibliotecă scrise de Cioran.
RANGE OF a IS carte
RANGE OF b IS cititor
RANGE OF v IS imprumuta
RETRIEVE b.nume
WHERE
COUNT (v.codel
WHERE (b.codec=v.codec)
70

AND (a.codel=v.codel)
AND (a.autor=’Cioran’))
=
COUNT (a.codel WHERE (a.autor=’Cioran’))

QBE (Query By Example) este un limbaj predicativ orientat pe


domenii. Limbajul dispune de primitive de programare grafică a cererilor
de date şi a fost conceput pentru utilizatorii neiniţiaţi. Utilizatorii, pentru a
manipula datele, completează o mulţime de câmpuri predefinite pe un ecran
special.
Exemplu.
Să se obţină titlurile cărţilor scrise de Cioran, din care există în
bibliotecă mai mult de 10 exemplare.

Carte Codel Titlu Autor Pret Nrex Coded


P.X 'Cioran' >10

Dacă utilizatorul doreşte şi tipărirea, atunci indică rezultatul care îl


interesează sub forma unei variabile domeniu (notată în acest exemplu prin
X) prefixată de P (print).
Dacă condiţia care apare în interogare este complexă sau se doreşte
simplificarea scrierii unei cereri, se poate utiliza o casetă specială (box
condition) în care se introduce condiţia.
În limbaj sunt admise funcţiile COUNT, MAX, MIN, AVG, SUM,
iar pentru eliminarea dublurilor a fost introdus operatorul UNIQUE.
Exemplu.
Să se obţină pentru fiecare autor, preţul celei mai scumpe cărţi şi
numărul exemplarelor scrise de acesta, care să găsesc în bibliotecă (tabelul
sortat!!!).

Carte Codel Titlu Autor Pret Nrex Coded


GROUP BY MAX SUM

În QBE există posibilitatea de a crea o nouă relaţie care poate fi o


schemă virtuală care reflectă modificările din relaţiile de bază sau o
imagine în care modificările nu sunt stocate.
Exemplu.
Codurile cărţilor scrise de Popa sau care au titlul „Geometrie“.
71

Algebric:
R1 = SELECT(carte, autor = 'Popa')
R2 = SELECT(carte, titlu = Geometrie')
R3 = R1 ∪ R2
Rezultat = PROJECT (R3, codel)
SEQUEL:
SELECT codel
FROM carte
WHERE autor = ’Popa’
OR titlu = ’Geometrie’
QBE:
Carte Codel Titlu Autor Pret Nrex Coded
P.X 'Popa'
P.Y 'Geometrie'
Exemplu.
Numele cititorilor care au împrumutat cel putin o carte scrisa de
Cioran.
Algebric:
R1 = PROJECT(cititor, codec, nume)
R2 = SELECT(carte, autor = 'Cioran')
R3 = PROJECT(R2, codel)
R4 = PROJECT(imprumuta, codel, codec)
R5 = JOIN(R4, R3, codel)
R6 = JOIN(R5, R1, codec)
Rezultat = PROJECT(R6, nume)
QBE:
Cititor Codec Nume Dep
Y P.X

Imprumuta Codel Codec Dataim Datares Dataef


Z Y

Carte Codel Titlu Autor Pret Nrex Coded


Z 'Cioran'
SEQUEL:
SELECT nume
FROM cititor
WHERE codec IS IN
72

SELECT codec
FROM imprumuta
WHERE codel IS IN
SELECT codel
FROM carte
WHERE autor = ’Cioran’

Utilizarea limbajelor de prelucrare a datelor relaţionale


în contextul limbajelor de programare
Două abordări:
• integrarea,
• extensia.
Integrarea LMD-ului într-un limbaj de programare.
Se consideră limbajul de prelucrare independent de limbajul de
programare şi există construcţii speciale care permit utilizarea acestuia în
limbajul gazdă. De exemplu, comenzile SQL pot fi integrate în limbajul
PL/1. Ele sunt prefixate de caracterul $ pentru a le distinge de comenzile
PL/1. Pentru a realiza integrarea, este necesară fie o precompilare a
cererilor, fie o interpretare la execuţie. Precompilatoarele actuale acoperă
majoritatea limbajelor semnificative existente. Alegerea unui precompilator
particular depinde de domeniul aplicaţiei.
Extensia limbajului de programare cu un LMD
Se consideră un limbaj de programare şi se realizează extensii ale
acestuia cu clauze specifice limbajelor de prelucrare a datelor.
Un exemplu tipic este extensia PASCAL/R care permite definirea unui
nou tip de date, şi anume tipul RELATION. De exemplu, relaţia carte este
definită:
TYPE car = RECORD
codel: TEXTE;
titlu: TEXTE;
autor: TEXTE;
nrex: INTEGER;
pret: INTEGER;
coded: TEXTE
END;
abc = RELATION OF car;
VAR carte: abc;
73

Exemplu.
Să se obţină o relaţie având numele rezultat, ce conţine toate cărţile
scrise de Cioran care au preţul mai mare de 150000.
VAR rezultat: abc;

BEGIN
rezultat:=[];
FOR EACH x IN carte DO
IF(x.autor = ’Cioran’) AND (x.pret >= 150000)
THEN rezultat:=rezultat + [x]
END;
Relaţia rezultat poate fi construită şi direct prin atribuirea:
rezultat := [EACH (x) IN carte:
(x.autor = ’Cioran’) AND (x.pret >= 150000)];
PROIECTAREA BAZELOR DE DATE
RELAŢIONALE
3.1. Preliminarii

Modelul relaţional a fost conceput şi dezvoltat de E.F. Codd. El este


un model formal de organizare conceptuală a datelor, destinat reprezentării
legăturilor dintre date, bazat pe teoria matematică a relaţiilor. Este modelul
cel mai accesibil pentru utilizatorul bazei de date deoarece structura sa fizică
este aceeaşi cu cea a datelor care trebuie prelucrate. În general, datele se
prezintă sub forma unor tabele (relaţii) în care liniile constituie
înregistrări, iar coloanele sunt atribute ce caracterizează aceste
înregistrări.
Obiectivele modelului relaţional, considerate de către E.F. Codd, sunt
următoarele:
• să permită un grad înalt de independenţă a datelor;
• să furnizeze baze solide pentru tratarea semanticii, coerenţei şi
problemelor de redundanţă a datelor;
• să permită dezvoltarea limbajelor de prelucrare a datelor.
Spre deosebire de modelul ierarhic şi reţea unde apar două elemente,
şi anume tipul entităţii şi relaţiile dintre două entităţi, modelul relaţional
este alcătuit numai din relaţii şi prin urmare, orice interogare asupra bazei
de date este tot o relaţie. Modelul relaţional a fost definit cu o deosebită
rigoare matematică, furnizând un mijloc performant de studiu al
proprietăţilor logice ale unui sistem de baze de date. Referitor la partea de
prelucrare a datelor, modelul relaţional este orientat spre mulţimi, în timp ce
modelele ierarhic şi reţea sunt orientate spre fişiere.
Pentru modelele ierarhic şi reţea, programatorul trebuie să proiecteze
programe care să acceseze baza de date, înregistrare cu înregistrare, utilizând
legături fizice între înregistrări. Modelul relaţional a permis introducerea
unor limbaje neprocedurale de prelucrare a datelor. Modelul relaţional nu
este orientat spre sistemul de calcul, deci modelul nu include regulile,
structurile şi operaţiile referitoare la implementarea fizică a unui sistem de
baze de date. De fapt, unul dintre obiectivele modelului este acela de a face
o distincţie între aspectele fizice şi logice ale unei baze de date
(independenţa datelor).

1
Modelul relaţional, deşi are unele imperfecţiuni, a fost adoptat în
ultimele decenii de majoritatea programatorilor din domeniu, tocmai datorită
acestor trei calităţi: este simplu, riguros din punct de vedere matematic şi nu
este orientat spre sistemul de calcul.
Definirea unui SGBD relaţional impune analizarea caracteristicilor pe
care trebuie să le prezinte un model de date pentru a fi considerat relaţional.
Există diferite modalităţi pentru a defini acest concept:
• prezentarea datelor în tabele supuse anumitor operaţii de tip
proiecţie, selecţie, reuniune, compunere, intersecţie etc. (definiţie
simplă);
• un sistem de baze de date ce suportă un limbaj de tip SQL –
Structured Query Language (definiţie practică);
• un sistem de baze de date care respectă principiile modelului
relaţional introdus de E.F. Codd (definiţia folosită cel mai
frecvent).
E.F. Codd a publicat un set de 13 reguli, numite reguli de fidelitate, în
raport cu care un SGBD poate fi apreciat ca relaţional. Ulterior, cele 13
reguli de fidelitate ale lui Codd au fost extinse la un număr de 100. Trebuie
remarcat că nu există un SGBD care respectă toate regulile definite de Codd.
Nu trebuie să apreciem un SGBD ca fiind relaţional sau nu, ci măsura în care
acesta este relaţional, deci numărul regulilor de fidelitate pe care le respectă.

3.2. Caracterisicile modelului relaţional

Dintre principalele caracteristici ale modelului relaţional se remarcă:


• nu există tupluri identice;
• ordinea liniilor şi a coloanelor este arbitrară;
• articolele unui domeniu sunt omogene;
• fiecare coloană defineşte un domeniu distinct şi nu se poate repeta
în cadrul aceleiaşi relaţii;
• toate valorile unui domeniu corespunzătoare tuturor cazurilor nu
mai pot fi descompuse în alte valori (sunt atomice).
Comparativ cu celelalte modele de date, modelul relaţional are
avantaje remarcabile dintre care se remarcă:
• fundamentarea matematică riguroasă,
• independenţa fizică a datelor,
• posibilitatea filtrărilor,

2
• existenţa unor structuri de date simple,
• minimizarea redundanţei,
• supleţea în comunicarea cu utilizatorul neinformatician etc.
Ca limite ale modelului relaţional pot fi menţionate:
• rămâne totuşi redundanţă,
• ocupă spaţiu,
• apar fenomene de inconsistenţă,
• nu există mecanisme pentru tratarea optimă a cererilor recursive,
• nu lucrează cu obiecte complexe,
• nu există mijloace perfecţionate pentru exprimarea constrângerilor
de integritate,
• nu realizează gestiunea cunoştinţelor etc.
Un model relaţional este caracterizat de trei elemente:

• structura relaţională a datelor (caracteristica structurală),


• operatorii modelului relaţional (caracteristica de asigurare a
prelucrării),
• regulile de integritate care guvernează folosirea cheilor în model
(caracteristica de asigurare a integrităţii).
Aceste trei elemente corespund celor trei componente ale ingineriei
software: informaţie, proces, integritate.

3.2.1. Structura datelor

Conceptelor descrise formal drept relaţie, tuplu sau atribut, le


corespund uzual denumirile tabel, linie sau coloană, iar fizic fişier,
înregistrare sau câmp.
Un domeniu este o mulţime de valori care se poate defini fie
enumerând elementele componente, fie specificând o proprietate distinctivă
a valorilor. Domeniului îi corespunde, atât uzual cât şi fizic, conceptul de
tip de date.
Un tip de date este o mulţime de valori, şi anume mulţimea tuturor
valorilor care satisfac o anumită constrângere a tipului. Un tip de date poate
fi definit de către sistem sau de către utilizator. De asemenea, fiecare tip are
asociat un set de operatori care pot fi aplicaţi valorilor tipului respectiv.
Tipurile constrâng operaţiile prin faptul că este necesar ca operanzii unei
operaţii să fie de tipurile definite pentru operaţia respectivă.

3
Tipurile pot fi oricât de simple sau de complexe. Se pot distinge tipuri
de date ale căror valori sunt numere, şiruri, date calendaristice, înregistrări
audio sau video, hărţi, puncte geometrice etc.
Orice tip de date este scalar (atomic, încapsulat) sau nescalar. Tipul
nescalar are componente vizibile utilizatorului şi direct accesibile.
Trebuie făcută distincţia între un tip şi reprezentarea sa fizică,
deoarece tipurile sunt legate de model, iar reprezentarea fizică este un aspect
legat de implementare.
Fie D1, D2, ..., Dn domenii finite, nu neapărat disjuncte. Produsul
cartezian D1 × D2 × ... × Dn al domeniilor D1, D2, ..., Dn este definit de
mulţimea tuplurilor (V1, V2, ..., Vn), unde V1 ∈ D1, V2 ∈ D2, ..., Vn ∈ Dn.
Numărul n defineşte aritatea tuplului.
O relaţie R pe mulţimile D1, D2, ..., Dn este o submulţime a produsului
cartezian D1 × D2 × ... × Dn, deci este o mulţime de tupluri. Există un alt mod
de a defini relaţia, şi anume ca o mulţime finită de funcţii. Asociem fiecărui
domeniu Di un atribut Ai şi definim relaţia R = {f1, f2, ..., fm}, unde
fi : {A1, A2, ..., An} → D1 ∪ D2 ∪ ... ∪ Dn şi fi(Aj) ∈ Dj pentru orice valori ale
lui i şi j. În această definiţie nu mai este restricţionată ordinea.
Definirea unei relaţii ca o mulţime de tupluri sau ca o mulţime de funcţii
se referă la mulţimi care variază în timp (se adaugă, se şterg sau se modifică
elemente). Pentru a caracteriza o relaţie este necesară existenţa unui element
invariant în timp, iar acest invariant este dat de structura relaţiei (schema
relaţională). Mulţimea numelor atributelor corespunzătoare unei relaţii R
defineşte schema relaţională a relaţiei respective. Vom nota schema
relaţională prin R(A1, A2, ..., An).
De exemplu, pentru modelul de date analizat în această lucrare,
VESTIMENTATIE(cod_vestimentatie, cod_designer, cod_model,
cod_prezentare, denumire, valoare, descriere) reprezintă o schemă relaţională.
Putem reprezenta o relaţie printr-un tabel bidimensional în care fiecare
linie corespunde unui tuplu şi fiecare coloană corespunde unui domeniu din
produsul cartezian. O coloană corespunde unui atribut. Numărul atributelor
defineşte gradul relaţiei, iar numărul de tupluri din relaţie defineşte
cardinalitatea relaţiei.
Bazele de date relaţionale sunt percepute de către utilizatori ca o
mulţime de tabele. Tabelul reprezintă structura logică dintr-un sistem
relaţional, nu structura fizică. La nivel fizic, sistemul poate stoca datele în
diferite moduri, folosind fişiere secvenţiale, indexări, înlănţuiri de pointeri etc.,
cu condiţia să poată realiza corespondenţa dintre reprezentarea stocată şi
tabelele de la nivelul logic.

4
Bazele de date relaţionale respectă principiul informaţiei (principiul
reprezentării uniforme), care afirmă că întregul conţinut informaţional al bazei
este reprezentat într-un mod unic, şi anume, ca valori explicite ale celulelor
unui tabel. Această modalitate de reprezentare este singura disponibilă, la nivel
logic, într-un sistem relaţional.
Când se inserează tupluri într-o relaţie, de multe ori valoarea unui
atribut este necunoscută sau nu este aplicabilă tuplului respectiv. Pentru a
reprezenta valoarea acestui atribut a fost introdusă o valoare convenţională
în relaţie, şi anume null. De fapt, null nu reprezintă o valoare, ci absenţa
uneia. Un null nu este acelaşi lucru cu o valoare numerică egală cu zero sau
cu un şir de caractere vid. Zerourile şi spaţiile libere (şirul vid) sunt valori,
pe când null semnifică absenţa unei valori. Prin urmare, null trebuie tratat în
mod diferit faţă de alte valori şi trebuie înţeles că termenul „valoare nulă“
este depreciativ.
Evident, este necesară o aritmetică şi o logică (polivalentă) nouă
(fig.3.1) care să cuprindă acest element. De exemplu, ce valoare are „10 >
null“ ? Răspunsul este null. În general, rezultatul operaţiilor aritmetice sau
logice este null când unul din operanzi este null. Prin urmare, „null = null“
are valoarea null, iar ¬ null este null.
Întroducerea null-urilor în modelul relaţional constituie o problemă
controversată, deşi Codd tratează null ca parte integrantă a modelului. Alţii
consideră această abordare greşită şi prematură. Trebuie remarcat că nu toate
sistemele relaţionale acceptă null-urile.

AND T F Null OR T F Null

T T F Null T T T T

F F F F F T F Null

Null Null F Null Null T Null Null

Fig. 3.1. Tabele de adevăr pentru operatorii AND şi OR


Tabelul vizualizare (view, filtru, relaţie virtuală, vedere) constituie un
filtru asupra tabelului iniţial, care conţine numai informaţia necesară unei
anumite abordări sau aplicaţii. De fapt, vizualizarea este o expresie
relaţională căreia i se atribuie un nume.

5
Dacă baza de date conţine tabele reale depuse pe disc, o vizualizare
este virtuală deoarece datele pe care le conţine nu sunt în realitate memorate
într-o bază de date. Este memorată numai definiţia vizualizării. Vizualizarea
nu este definită explicit, ca relaţiile de bază, prin mulţimea tuplurilor
componente, ci implicit, pe baza altor relaţii obţinute prin intermediul unor
expresii relaţionale. Stabilirea efectivă a tuplurilor care compun vizualizarea
se realizează prin evaluarea expresiei atunci când utilizatorul se referă la
acest tabel.
Utilizarea vizualizărilor este avantajoasă, deoarece:
• asigură securitatea tabelului iniţial (care este protejat de ştergeri,
modificări etc.) prin capacitatea de a ascunde datele;
• permit vizualizarea simultană a aceloraşi date de către diverşi
utilizatori;
• sunt concise, punând la dispoziţie capacităţi „macro“;
• asigură independenţa logică faţă de date (imunitatea programelor
de aplicaţie faţă de modificările din structura logică a bazei de
date).
Există totuşi limitări în utilizarea acestor tabele, în special legate de
problema reactualizării. De exemplu, coloanele calculate nu pot fi
reactualizate. De asemenea, inserarea, reactualizarea şi ştergerea nu sunt, în
general, recomandate şi sunt permise numai cu anumite restricţii care sunt
specifice fiecărui SGBD. De exemplu, Oracle9i rezolvă problema dificilă a
reactualizării vizualizărilor, în anumite situaţii, utilizând o clasă specială de
declanşatoare (TRIGGER de tip INSTEAD OF).

3.2.2. Reguli de integritate

Regulile de integritate sunt aserţiuni pe care datele conţinute în baza


de date trebuie să le satisfacă. Trebuie făcută distincţia între regulile
structurale care sunt inerente modelării datelor şi regulile de funcţionare
(comportament) care sunt specifice unei aplicaţii particulare.
Există trei tipuri de constrângeri structurale (de cheie, de referinţă, de
entitate) ce constituie mulţimea minimală de reguli de integritate pe care
trebuie să le respecte un SGBD relaţional. Restricţiile de integritate
minimale sunt definite în raport cu noţiunea de cheie a unei relaţii.
O mulţime minimală de atribute ale căror valori identifică unic un
tuplu într-o relaţie reprezintă o cheie pentru relaţia respectivă.

6
Prin urmare, o cheie a unei relaţii R este o mulţime K de atribute,
astfel încât:
(1) pentru orice două tupluri t1, t2 ale lui R ⇒ t1(K) ≠ t2(K);
(2) nu există nicio submulţime proprie a lui K având proprietatea (1).
Fiecare relaţie are cel puţin o cheie. Dacă există diferite chei posibile,
ele se numesc chei candidat. Una dintre cheile candidat va fi aleasă pentru a
identifica efectiv tupluri şi ea va primi numele de cheie primară. Cheia
primară nu poate fi reactualizată. Restul cheilor candidat vor purta numele de
chei alternative sau secundare. Atributele care reprezintă cheia primară pot fi
subliniate sau urmate de semnul „#“.
O cheie identifică linii şi este diferită de un index care localizează
liniile. O cheie secundară este folosită ca index pentru a accesa tupluri. Un
grup de atribute din cadrul unei relaţii care conţine o cheie a relaţiei poartă
numele de supercheie.
Fie schemele relaţionale R1(P1, S1) şi R2(S1, S2), unde P1 este cheie
primară pentru R1, S1 este cheie secundară pentru R1, iar S1 este cheie
primară pentru R2. În acest caz, vom spune că S1 este cheie externă (cheie
străină) pentru relaţia R1.
De exemplu, cod_casa_moda este cheie externă pentru relaţia
CREATOR şi este cheie primară pentru relaţia CASA_MODA. Cheia
primară poate conţine cheia externă. De exemplu, relaţia ACCESORIU are
cheia primară formată din atributele cod_accesoriu şi cod_vestimentatie, iar
atributul cod_vestimentatie fiind cheie primară în relaţia
VESTIMENTATIE, devine cheie externă în relaţia ACCESORIU.
Modelul relaţional respectă trei reguli de integritate structurală.

 Regula 1 – unicitatea cheii. Cheia primară trebuie să fie unică şi


minimală.
 Regula 2 – integritatea entităţii. Atributele cheii primare trebuie să
fie diferite de null.
 Regula 3 – integritatea referirii. O cheie externă trebuie să fie ori
null în întregime, ori să corespundă unei valori a cheii primare
asociate.
Uneori constrângerile de integritate sunt implementate procedural,
folosind o clasă de proceduri (declanşatori) precompilate, stocate împreună
cu baza de date şi invocate automat ori de câte ori are loc un anumit
eveniment. Aceste proceduri nu reprezintă o modalitate recomandată de
implementare a constrângerilor de integritate deoarece, fiind proceduri, sunt

7
mai dificil de optimizat de către sistem şi, de asemenea, sunt executate doar
atunci când apare evenimentul specificat (declanşator).
Declanşatorii trebuie utilizaţi cu precauţie, sau deloc, dacă există o
modalitate alternativă de rezolvare a problemei respective. Ei pot crea
probleme practice datorită fenomenului „declanşatori în cascadă“ (lanţ de
declanşatori). De asemenea, dacă acelaşi eveniment determină pornirea mai
multor declanşatori diferiţi, atunci ordinea în care pornesc poate fi
importantă sau poate fi chiar nedefinită. Există posibilitatea ca un
declanşator să se declanşeze singur, recursiv. Dacă sunt disponibile, soluţiile
declarative sunt de preferat celor procedurale.

3.2.3. Operatorii modelului relaţional

Operatorii modelului relaţional definesc operaţiile care se pot efectua


asupra relaţiilor în scopul realizării funcţiilor de prelucrare asupra bazei de
date. Modelul relaţional oferă două mulţimi de operatori pe relaţii, şi anume:
algebra relaţională şi calculul relaţional. La rândul său, calculul relaţional
este de două tipuri: orientat pe tupluri sau orientat pe domenii.
Operatorii algebrei relaţionale sunt fie operatori tradiţionali pe
mulţimi (UNION, INTERSECT, PRODUCT, DIFFERENCE), fie operatori
relaţionali speciali (PROJECT, SELECT, JOIN, DIVISION). Aceşti
operatori vor fi analizaţi în secţiunea 3.4.
Calculul relaţional reprezintă o adaptare a calculului predicatelor la
domeniul bazelor de date relaţionale. Ideea de bază este de a identifica o
relaţie cu un predicat. Pe baza unor predicate iniţiale, prin aplicarea unor
operatori ai calculului cu predicate (conjuncţia, disjuncţia, negaţia,
cuantificatorul existenţial şi cel universal) se pot defini noi relaţii.
Variabilele care apar în construcţiile calculului relaţional orientat pe domenii
sunt variabile definite asupra domeniilor, iar cele care apar în construcţiile
calculului relaţional orientat pe tupluri sunt variabile definite asupra
relaţiilor, adică valorile acestora reprezintă tupluri.
Echivalenţa dintre algebra relaţională şi calculul relaţional a fost
demonstrată de J.D.Ullman. Această echivalenţă arată că orice relaţie posibil
de definit în algebra relaţională poate fi definită şi în cadrul calcului
relaţional, şi reciproc.

8
3.3. Proiectarea modelului relaţional

Problema proiectării bazelor de date poate fi enunţată în următoarea


manieră: fiind dat un volum de informaţii care trebuie reprezentat într-o bază
de date, cum se poate alege o structură logică adecvată pentru acesta?
Proiectarea bazelor de date este mai mult o artă, decât o ştiinţă. Există
câteva principii ştiinţifice care pot fi invocate pentru a rezolva problema, dar
există multe aspecte legate de proiectare pe care aceste principii nu le
abordează şi evident, nu le rezolvă. Teoreticienii şi practicienii au propus
metodologii de proiectare mai mult sau mai puţin riguroase, dar găsirea
proiectării logice optime rămâne o problemă complexă şi dificilă. Pot exista
criterii obiective care să favorizeze o abordare în raport cu celelalte. În
capitolul 2 s-a prezentat o abordare (proiectarea modelului E/R) care are
meritul că este frecvent utilizată în practică.
În practică, se încearcă obţinerea unei scheme conceptuale corecte,
adică realizarea proiectării logice abstracte independent de hardware, de
sistemul de operare, de SGBD, de limbaj, de utilizator etc. Este importantă
atât obţinerea structurilor de date corecte, cât şi realizarea integrităţii datelor.
De asemenea, trebuie ca designul să fie robust, în sensul că nu va fi invalidat
prin ivirea unor noi cerinţe ale aplicaţiei, care nu au fost prevăzute în
momentul proiectării iniţiale.
Pentru rafinarea proiectării modelului de date, pentru obţinerea
schemei conceptuale a bazei de date relaţionale, se pleacă de la o formă de
modelare semantică specială a datelor, mai precis de la diagrama E/R.
Ideea generală este de a reprezenta entităţile şi legăturile dintre
acestea sub forma unor tabele speciale (relaţii). Vor fi prezentate 9 reguli
care arată maniera în care se transformă entităţile, relaţiile şi atributele
acestora, în vederea obţinerii schemei conceptuale.
Ca formalism, în diagrama conceptuală, simbolul „ד indică
plasamentul cheii externe. Dacă simbolul este subliniat („ד), se exprimă şi
faptul că respectiva cheie externă este conţinută în cheia primară.

9
3.3.1. Transformarea entităţilor

 Entităţile independente devin tabele independente. Cheia primară


nu conţine chei externe. De exemplu, entitatea independentă
PREZENTARE generează un tabel independent pentru care
atributul cod_prezentare reprezintă cheia primară.
 Entităţile dependente devin tabele dependente. Cheia primară a
entităţilor dependente conţine cheia primară a entităţii de care
depinde (cheie externă) plus unul sau mai multe atribute
adiţionale. De exemplu, cheia primară a entităţii dependente
ACCESORIU este formată din atributul cod_vestimentatie, care
reprezintă cheia primară a entităţii de care depinde
(VESTIMENTATIE), plus atributul adiţional cod_accesoriu.
 Subentităţile devin subtabele. Cheia externă se referă la
supertabel, iar cheia primară este această cheie externă. De
exemplu, cheia primară a subentităţii MODEL este cod_angajat
care este o cheie externă (cheie primară a entităţii
ANGAJAT_TEMP).

3.3.2. Transformarea relaţiilor

 Relaţiile 1:1 şi 1:n devin chei externe. De exemplu, relaţia creeaza


(CREATOR_creeaza_VESTIMENTATIE) devine coloană în
tabelul VESTIMENTATIE. Atributul cod_creator, care este cheie
primară în tabelul CREATOR, va fi cheie externă în tabelul
VESTIMENTATIE. Relaţia 1:1 plasează cheia externă în tabelul cu
mai puţine linii.
 Relaţia m:n devine un tabel special, numit tabel asociativ, care are
două chei externe pentru cele două tabele asociate. Cheia primară
este compunerea acestor două chei externe plus eventuale coloane
adiţionale. Un tabel asociativ se desenează punctat. De exemplu,
relaţia participa (CASA_MODA_participa_PREZENTARE), care
este de tip m:n, devine tabel asociativ având cheia primară formată
din atributele cod_casa_moda şi cod_prezentare.
 Relaţiile de tip trei devin tot tabele asociative. De exemplu, relaţia
primeste ce leagă entităţile ANGAJAT_TEMP, PREZENTARE şi
CASA_MODA, devine tabel asociativ. Cheia primară a tabelului
este compunerea a trei chei externe: cod_angajat, cod_casa_moda

10
şi cod_prezentare. Practic, în acest caz, este preferabil să fie
introdusă o cheie primară artificială.

3.3.3. Transformarea atributelor

 Un atribut singular devine o coloană.


 Atributele multiple devin tabele dependendente ce conţin cheia
primară a entităţii şi atributul multiplu. Cheia primară este formată
dintr-o cheie externă, plus una sau mai multe coloane adiţionale.
De exemplu, o persoană de contact poate cunoaşte mai multe limbi
străine. În acest caz, atributul limba_cunoscuta este multiplu şi va
genera tabelul dependent LIMBA.
 Entităţile devin tabele, iar atributele lor devin coloane în aceste
tabele. Ce devin atributele relaţiilor? Pentru relaţii 1:1 şi 1:n,
atributele relaţiilor vor aparţine tabelului care conţine cheia
externă, iar pentru relaţii m:n şi de tipul trei, atributele vor fi
plasate în tabelele asociative.

Tabel Reprezintă Cheie primară


Independent entitate independentă nu conţine chei externe
Subtabel subentitate o cheie externă
entitate dependentă o cheie externă şi una sau mai
Dependent
Atribut multiplu multe coloane adiţionale
relaţie m:n două sau mai multe chei externe
Asociativ şi (opţional) coloane adiţionale
relaţie de tip 3

Fig. 3.2. Clasificarea tabelelor

11
LIMBA INFO CONTACT

FIRMA_PUB cunoaste are

ORGANIZATOR
are ×
PERS CONTACT
face ×
are
PUBLICITATE×
organizeaza LOCALIZARE
FIRMA_SEC LOCATIE
se_face
are
are
×
ANGAJAT_SEC PAZA ×
PREZENTARE
× FINANTEAZA SPONSOR
×

asigura PARTICIPA
SOC ASIG

CASA MODA × PRIMESTE


prezinta
lucreaza
ANGAJAT_TEMP
×
CREATOR MODEL
×
creeaza prezinta
lucreaza_la
face × ×
VESTIMENTATIE
× are AGENTIE

are refera
×
× ACCESORIU ISTORIC ×

Fig. 3.3. Diagrama conceptuală.

12
Cele patru tipuri de tabele (independente, dependente, subtabele şi
asociative) se deosebesc prin structura cheii primare (figura 3.2.).
În figura 3.3 este prezentată diagrama conceptuală pentru proiectarea
modelului relaţional comentat. Ea a fost construită din diagrama E/R prin
adăugarea tabelelor asociative şi prin marcarea cheilor externe.
În continuare va fi prezentată modalitatea efectivă de trecere de la
diagrama entitate-relaţie la diagrama conceptuală pentru modelul de date
real analizat în capitolul 2.
Entităţile independente PERS_CONTACT, ORGANIZATOR,
PREZENTARE, PUBLICITATE, SPONSOR, FIRMA_PUB,
CASA_MODA, CREATOR, ANGAJAT_TEMP, ACCESORIU,
LOCALIZARE, FIRMA_SEC, ANGAJAT_SEC, SOCIETATE_ASIG,
INFO_CONTACT, AGENTIE, LOCATIE devin tabele independente.
Cheile primare ale fiecărei entităţi au fost specificate în capitolul 2.
Entităţile dependente ISTORIC şi ACCESORIU, care intervin în
model, devin tabele dependente, iar cheile primare au fost specificate în
capitolul 2.
Subentitatea MODEL devine subtabel, având aceeaşi cheie primară cu
superentitatea ANGAJAT_TEMP, adică atributul cod_angajat.
Relaţiile de tip one-to-one şi one-to-many devin chei externe.
Relaţia PERS_CONTACT_are_LOCALIZARE devine cheie externă în
tabelul PERS_CONTACT. Dacă restricţia că o persoană de contact are o
singură localizare este eliminată, atunci cardinalitatea relaţiei devine 1:n, iar
atributul cod_pers_contact devine cheie externă în tabelul LOCALIZARE.
Toate comentariile anterioare rămân valabile şi pentru entităţile
FIRMA_PUB, FIRMA_SEC, PREZENTARE, ORGANIZATOR,
CASA_MODA, SPONSOR, SOC_ASIG, CREATOR, LOCATIE,
ANGAJAT_TEMP şi AGENTIE, care sunt legate de entitatea
LOCALIZARE, permiţând astfel localizarea tuturor structurilor modelului.
Relaţia PERS_CONTACT_are_INFO_CONTACT devine cheie externă în
tabelul PERS_CONTACT. Dacă restricţia că pentru o persoană de contact
există o singură posibilitate de contactare este eliminată, atunci
cardinalitatea relaţiei devine 1:n, iar atributul cod_pers_contact devine cheie
externă în tabelul INFO_CONTACT. Toate comentariile anterioare rămân
valabile şi pentru entităţile FIRMA_PUB, FIRMA_SEC,
ANGAJAT_TEMP, PREZENTARE, ORGANIZATOR, CASA_MODA,
SPONSOR, SOC_ASIG, CREATOR, LOCATIE şi AGENTIE, care sunt
legate de entitatea INFO_CONTACT, permiţând astfel accesarea tuturor
structurilor modelului.

13
Relaţia FIRMA_PUB_face_PUBLICITATE devine cheie externă în tabelul
PUBLICITATE.
Relaţia PUBLICITATE_se_face_pentru_PREZENTARE devine cheie
externă în tabelul PUBLICITATE.
Relaţia ORGANIZATOR_are_PERS_CONTACT devine cheie externă în
tabelul PERS_CONTACT.
Relaţia FIRMA_SEC_are_ANGAJAT_SEC devine cheie externă în tabelul
ANGAJAT_SEC.
Relaţia SOC_ASIG_asigura_PREZENTARE devine cheie externă în tabelul
PREZENTARE.
Relaţia CASA_MODA_lucreaza_CREATOR devine cheie externă în tabelul
CREATOR.
Relaţia CREATOR_creeaza_VESTIMENTATIE devine cheie externă în
tabelul VESTIMENTATIE.
Relaţia VESTIMENTATIE_are_ACCESORIU devine cheie externă în tabelul
ACCESORIU.
Relaţia MODEL_prezintă_VESTIMENTATIE devine cheie externă în tabelul
VESTIMENTATIE.
Relaţia CREATOR_face_ACCESORIU devine cheie externă în tabelul
ACCESORIU.
Relaţia PREZENTARE_prezinta_VESTIMENTATIE devine cheie externă în
tabelul VESTIMENTATIE.
Relaţia PREZENTARE_are_LOCATIE devine cheie externă în
PREZENTARE.
Relaţia MODEL_lucreaza_AGENTIE devine cheie externă în tabelul
MODEL.
Relaţia MODEL_are_ISTORIC devine cheie externă în tabelul ISTORIC.
Relaţia ISTORIC_refera_AGENTIE devine cheie externă în tabelul
ISTORIC.
Relaţiile de tip many-to-many devin tabele asociative, având două
chei externe pentru cele două tabele asociate.
Relaţia ANGAJAT_SEC_paza_PREZENTARE devine tabel asociativ
(PAZA).
SPONSOR_finanteaza_PREZENTARE devine tabel asociativ
(FINANTEAZA).
CASA_MODA_participa_PREZENTARE devine tabel asociativ
(PARTICIPA).
Relaţiile de tipul trei (adică cele care leagă cel puţin trei entităţi)
devin tabele asociative, având chei externe pentru fiecare dintre tabelele
asociate.

14
Relaţia primeste, care leagă entităţile ANGAJAT_TEMP, PREZENTARE şi
CASA_MODA, devine tabel asociativ (PRIMESTE). În acest caz, s-a
considerat o cheie primară artificială (atributul cod_primeste). Tabelul
asociativ are drept chei externe atributele: cod_angajat, cod_casa_moda şi
cod_prezentare.
Atributele multiple devin tabele dependendente ce conţin cheia
primară a entităţii şi atributul multiplu.
Atributul limba_cunoscuta este multiplu (relativ la entitatea
PERS_CONTACT) şi va genera tabelul dependent LIMBA. Acesta va avea
drept cheie primară atributele cod_pers_contact şi limba_cunoscuta. Tabelul
mai conţine trei atribute ce reprezintă nivelul de cunoaştere (scris, citit,
vorbit) a limbii.
Atributele entităţilor devin coloane în tabelele corespunzătoare. Pentru
relaţii 1:1 şi 1:n, atributele relaţiilor vor aparţine tabelului care conţine cheia
externă, iar pentru relaţii m:n şi de tipul trei, atributele vor fi plasate în
tabelele asociative.
Tabelul asociativ PRIMESTE va avea ca atribute, pe lângă cele ce constituie
cheia primară, suma, data_achitare, cont, banca.
Schemele relaţionale corespunzătoare diagramei conceptuale din
figura 3.3. sunt următoarele:
MODEL(cod_angajat#, cod_agentie, inaltime, nr_pantof, info)
ANGAJAT_TEMP(cod_angajat#, nume, prenume, data_nastere,
nationalitate, sex, cod_localizare, cod_info_acces, tip)
PUBLICITATE(cod_publicitate#, cod_firma_pub, cod_prezentare, tip,
nume, suma, observatii)
FIRMA_PUB(cod_firma_pub#, nume, info, director, observatii,
cod_localizare, nume_pers_contact, cod_info_acces)
ORGANIZATOR(cod_organizator#, denumire, banca, cont, cod_info_acces,
informatii, cod_localizare)
PERS_CONTACT(cod_pers_contact#, cod_organizator, nume, prenume,
directie, cod_localizare, cod_info_acces)
PREZENTARE(cod_prezentare#, denumire, data_start, data_final,
cod_soc_asig, cod_organizator, cod_locatie)
LOCATIE(cod_locatie#, denumire, tip, cod_localizare, cod_info_acces,
capacitate)
SPONSOR(cod_sponsor#, tip, nume, info, cod_localizare, cod_info_acces)

15
CASA_MODA(cod_casa_moda#, nume, cifra_afaceri, proprietar, director,
istoric, data_creare, cod_localizare, cod_info_acces)
CREATOR(cod_creator#, nume, prenume, data_nastere, data_angajare, tip,
mod_angajare, info, cod_casa_moda, cod_localizare, cod_info_acces)
VESTIMENTATIE(cod_vestimentatie#, denumire, valoare, descriere,
cod_creator, cod_model, cod_prezentare)
ACCESORIU(cod_vestimentatie#, cod_accesoriu#, cod_creator, descriere,
tip, valoare)
AGENTIE(cod_agentie#, nume, data_creare, director, cifra_afaceri, info,
cod_localizare, cod_info_acces)
ISTORIC(cod_model#, data_angajare#, data_final, cod_agentie, conditii)
LOCALIZARE(cod_localizare#, adresa, cod_postal, oras, tara)
INFO_CONTACT(cod_info_acces#, telefon_fix, telefon_mobil, mail, fax)
FIRMA_SEC(cod_firma_sec#, nume_firma, tip_servicii, director,
cod_localizare, cod_info_acces, observatii)
ANGAJAT_SEC(cod_angajat#, nume, prenume, data_nastere, specializare,
nivel, observatii, cod_info_acces, cod_firma_sec)
PAZA(cod_angajat#, cod_prezentare#, tip_paza, dotare, observatii)
SOC_ASIG(cod_soc_asig#, conditii, suma, director, observatii,
cod_localizare, nume_pers_contact_firma, cod_info_acces)
PARTICIPA(cod_prezentare#, cod_casa_moda#, tip, data)
FINANTEAZA(cod_sponsor#, cod_prezentare#, suma, banca, cont_emitent,
data_emitere, cod_ordin_plata)
PRIMESTE(cod_primeste#, cod_angajat, cod_prezentare, cod_casa_moda,
data_achitare, suma, cont, banca)
LIMBA(cod_pers_contact#, limba_cunoscuta#, niv_scris, niv_citit,
niv_vorbit)

16
3.4. Regulile lui Codd

Un SGBD relaţional îndeplineşte funcţiile unui SGBD, dar cu anumite


particularităţi care decurg din concepţia de organizare a datelor, respectiv
din modelul relaţional. Fiecare SGBD relaţional implementează modelul
relaţional într-o manieră proprie, care îl diferenţiază de restul sistemelor
relaţionale. Caracterizarea unui SGBD relaţional se poate realiza la nivelul
clasei sistemelor relaţionale, în sensul caracterizării globale, unitare în raport
cu celelalte tipuri de SGBD-uri, sau la nivelul SGBD-ului relaţional
individual în sensul caracterizării particularităţilor sale, în raport cu alte
SGBD-uri relaţionale.
Realizarea funcţiilor SGBD-urilor relaţionale se face cu ajutorul unor
mecanisme de lucru specifice, care le separă de sistemele nerelaţionale.
Dintre mecanismele de lucru de care dispune un SGBD relaţional se pot
menţiona:
• un limbaj relaţional pentru descrierea datelor la nivel fizic, logic şi
conceptual;
• un limbaj relaţional pentru prelucrarea datelor;
• mecanisme pentru controlul integrităţii semantice a datelor;
• mecanisme pentru optimizarea cererilor de date;
• mecanisme pentru asigurarea coerenţei datelor;
• utilitare pentru generarea de rapoarte, pentru generarea de
aplicaţii, pentru generarea unor statistici referitoare la starea şi
activitatea bazei de date etc.
În anul 1985, E.F. Codd a publicat un set de 13 reguli în raport cu care
un sistem de gestiune a bazelor de date poate fi apreciat ca relaţional. Niciun
sistem de gestiune a bazelor de date pus în vânzare pe piaţa comercială nu
respectă absolut toate regulile definite de Codd, dar acest lucru nu împiedică
etichetarea acestor sisteme drept relaţionale. Nu trebuie apreciat un SGBD
ca fiind relaţional sau nu, ci măsura în care acesta este relaţional, deci
numărul regulilor lui Codd pe care le respectă.
Regulile lui Codd au fost şi sunt cauza multor controverse. Unii le
consideră doar un exerciţiu academic, alţii pretind că produsele lor satisfac
majoritatea regulilor. De fapt, discuţiile în jurul acestor reguli au generat o
cunoaştere mai bună a caracteristicilor esenţiale ale unui SGBD relaţional,
atât din punctul de vedere al utilizatorilor, cât şi din cel al producătorilor de
software.

17
Regulile pot fi organizate în următoarele cinci domenii de
funcţionalitate: reguli fundamentale, reguli structurale, reguli de integritate,
reguli de prelucrare a datelor şi reguli privind independenţa datelor.
Regula 1 – regula gestionării datelor. Un SGBD relaţional trebuie să
fie capabil să gestioneze o bază de date prin posibilităţile sale relaţionale.
Practic, nicio implementare curentă de SGBD nu respectă această regulă,
deoarece implementările conţin atât caracteristici relaţionale cât şi
nerelaţionale.
Regula 2 – regula reprezentării informaţiei. Într-o bază de date
relaţională, informaţia este reprezentată la nivel logic sub forma unor
tabele ce poartă numele de relaţii. Este regula cea mai importantă şi
conform lui Codd, un SGBD care nu respectă această regulă, nu poate fi
considerat relaţional. Chiar şi meta-datele, conţinute în catalogul de sistem,
trebuie să fie stocate ca relaţii.
Regula 3 – regula accesului garantat la date. Fiecare valoare dintr-o
bază de date relaţională trebuie să poată fi adresată în mod logic printr-o
combinaţie formată din numele relaţiei, valoarea cheii primare şi numele
atributului.
Regula 4 – regula reprezentării informaţiei necunoscute. Un sistem
relaţional trebuie să permită utilizatorului definirea unui tip de date numit
„null“ pentru reprezentarea unei informaţii necunoscute la momentul
respectiv. Într-un SGBD relaţional trebuie să putem face diferenţa între
valoarea zero, un şir vid de caractere şi o valoare necunoscută.
Regula 5 – regula dicţionarelor de date. Asupra descrierii bazelor de
date (informaţii relative la relaţii, vizualizări, indecşi etc.) trebuie să se
poată aplica aceleaşi operaţii ca şi asupra datelor din baza de date.
Descrierea bazei de date este reprezentată la nivel logic sub forma unor
tabele care pot fi accesate în acelaşi mod ca şi datele efective. Prin urmare
există un singur limbaj de prelucrare atât a meta-datelor, cât şi a datelor.
Regula 6 – regula limbajului de interogare. Trebuie să existe cel puţin
un limbaj pentru prelucrarea bazei de date. În general, toate implementările
SQL respectă această regulă. Limbajul permite utilizatorilor să definească
relaţii şi vizualizări, să prelucreze datele interactiv sau prin intermediul
programului, să regăsească informaţia şi să o poată actualiza, să verifice şi să
corecteze datele de intrare, să implementeze constrângeri, să stabilească
limite pentru tranzacţii etc.
Regula 7 – regula de actualizare a vizualizării. Un SGBD trebuie să
poată determina dacă o vizualizare poate fi actualizată şi să stocheze
rezultatul interogării, ce defineşte vizualizarea, într-un dicţionar de tipul

18
unui catalog de sistem. Trebuie să existe un mecanism prin care să se poată
determina dacă anumite vizualizări pot fi actualizate sau nu. Regula
stabileşte că toate vizualizările care sunt teoretic reactualizabile pot fi
reactualizate şi de către sistemul de gestiune. Nu au fost încă descoperite
condiţiile pentru identificarea tuturor vizualizărilor care pot fi teoretic
reactualizate.
Regula 8 – regula limbajului de nivel înalt. Capacitatea de tratare a
unei relaţii de bază sau a unei vizualizări ca pe un singur operand se aplică
atât pentru operaţiile de regăsire a datelor, cât şi asupra operaţiilor de
inserare, actualizare şi ştergere a datelor. Un SGBD relaţional nu trebuie să
oblige utilizatorul să caute într-o relaţie, tuplu cu tuplu, pentru a regăsi
informaţia dorită. Operaţiile de prelucrare a datelor pot să fie aplicate atât în
mod interactiv cât şi prin program, într-un limbaj gazdă.
Regula 9 – regula independenţei fizice a datelor. Programele de
aplicaţie şi activităţile utilizatorilor nu depind de modul de depunere a
datelor sau de modul de acces la date. Într-un SGBD relaţional trebuie să se
separe aspectul fizic al datelor (stocare sau acces la date) de aspectul logic al
datelor.
Regula 10 – regula independenţei logice a datelor. Programele de
aplicaţie trebuie să fie transparente la modificările de orice tip efectuate
asupra datelor. Orice modificare efectuată asupra unei relaţii nu trebuie să
afecteze operaţiile de prelucrare a datelor.
Regula 11 – regula independenţei datelor din punct de vedere al inte-
grităţii. Regulile de integritate trebuie să fie definite într-un sublimbaj
relaţional de date, nu în programul de aplicaţie. SQL permite definirea de
restricţii privind integritatea datelor şi stocarea lor în catalogul de sistem. Cu
cât sunt mai multe constrângeri de integritate care pot fi întreţinute mai
degrabă de către SGBD, decât în cadrul fiecărui program aplicaţie, cu atât
garantarea calităţii datelor este mai bună.
Regula 12 – regula independenţei datelor din punct de vedere al
distribuirii. Distribuirea datelor pe mai multe calculatoare dintr-o reţea de
comunicaţii de date nu trebuie să afecteze programele de aplicaţie. ANSI-
SQL nu menţionează regula în specificaţiile sale, deoarece este destul de
greu de respectat. De observat că regula nu cere ca SGBD-ul să accepte o
bază de date distribuite pentru a fi relaţional, dar stabileşte că limbajul de
interogare va rămâne acelaşi atunci când se va introduce această capacitate,
iar datele vor fi distribuite.

19
Regula 13 – regula versiunii procedurale a unui SGBD. Orice
componentă procedurală a unui SGBD trebuie să respecte aceleaşi restricţii
de integritate ca şi componenta relaţională. De exemplu, dacă în partea de
prelucrare a datelor a limbajului relaţional valoarea dintr-o coloană este de
tipul not null, orice altă metodă procedurală de accesare a acestei coloane nu
trebuie să permită introducerea unui null în această coloană. Prin urmare,
regulile de integritate exprimate într-un limbaj relaţional de un anumit nivel
nu pot fi distruse de un limbaj de nivel inferior.
Deoarece regulile lui Codd sunt prea severe pentru a fi respectate de
un SGBD operaţional, s-au formulat criterii minimale de definire a unui
SGBD relaţional.
Un SGBD este minimal relaţional dacă:
• toate datele din cadrul bazei sunt reprezentate prin valori în tabele;
• nu există pointeri observabili de către utilizator;
• sistemul suportă operatorii relaţionali de proiecţie, selecţie şi
compunere naturală, fără limitări impuse din considerente interne.
Un SGBD este complet relaţional dacă este minimal relaţional şi
satisface în plus condiţiile:
• sistemul suportă restricţiile de integritate de bază (unicitatea cheii
primare, constrângerile referenţiale, integritatea entităţii);
• sistemul suportă toate operaţiile de baza ale algebrei relaţionale.

20
4. NORMALIZAREA RELAŢIILOR
4.1. Preliminarii
În procesul modelării unei baze de date relaţionale, o etapă importantă o
reprezintă normalizarea relaţiilor conceptuale. Aceasta presupune obţinerea de
relaţii „moleculare“, fără a pierde nimic din informaţie, având scopul de a
elimina redundanţa şi anomaliile reactualizării informaţiilor. Tehnica
normalizării permite determinarea unei scheme conceptuale rafinate, printr-un
proces de ameliorare progresivă a unei scheme conceptuale iniţiale a bazei de
date relaţionale. După fiecare etapă de ameliorare, relaţiile bazei de date ating
un anumit grad de perfecţiune, deci se află într-o anumită formă normală.
Trecerea unei relaţii dintr-o formă normală în alta presupune eliminarea unui
anumit tip de dependenţe nedorite, care sunt transformate în dependenţe
admisibile, adică dependenţe care nu provoacă anomalii.
Procesul de ameliorare progresivă a schemei conceptuale trebuie să
satisfacă următoarele cerinţe:
• să garanteze conservarea datelor, adică în schema conceptuală
finală trebuie să figureze toate datele din cadrul schemei iniţiale;
• să garanteze conservarea dependenţelor dintre date, adică în
schema finală fiecare dependenţă trebuie să aibă determinantul şi
determinatul în schema aceleiaşi relaţii;
• să reprezinte o descompunere minimală a relaţiilor iniţiale, adică
nici una din relaţiile care compun schema finală nu trebuie să fie
conţinută într-o altă relaţie din această schemă.
Există două metode pentru a modela baze de date relaţionale fără
anomalii sau pierderi de informaţie.
• Schema descompunerii pleacă de la o schemă relaţională
universală care conţine toate atributele bazei de date. Schema se
descompune prin proiecţii succesive în subrelaţii. Descompunerea
se opreşte atunci când continuarea ei ar duce la pierderi de
informaţie. Algoritmii de descompunere se bazează, în general, pe
descrierea formală a dependenţei dintre atribute.
• Schema sintezei pleacă de la o mulţime de atribute independente.
Utilizând proprietăţi de semantică şi legături între atribute se pot
compune noi relaţii, astfel încât acestea să nu sufere de anumite
anomalii pe care dorim să le evităm. Algoritmii de sinteză se
bazează în general pe teoria grafurilor pentru a reprezenta
legăturile între atribute.

21
4.2. Dependenţe funcţionale

Unul dintre conceptele principale asociate normalizării este cel de


dependenţă funcţională, care descrie formalizat legăturile dintre atribute.
Dependenţa funcţională este o proprietate a semanticii atributelor dintr-o
relaţie. Semantica indică modul în care sunt legate atributele şi specifică
dependenţele dintre ele. Atunci când există o dependenţă funcţională, ea este
specificată ca o constrângere între atribute.
O relaţie universală este o relaţie ce grupează toate atributele care
modelează sistemul real cercetat. Fie E, mulţimea dependenţelor considerate
de proiectantul bazei pentru o schemă relaţională sau pentru o relaţie
universală.
Plecând de la o mulţime de proprietăţi formale ale dependenţelor,
proprietăţi considerate drept reguli de deducţie (axiome), poate fi obţinută
mulţimea maximală de dependenţe asociate lui E. Această mulţime defineşte
închiderea lui E.
Fie R(A1, A2, ..., An) o schemă relaţională şi fie X, Y submulţimi de
atribute ale lui R. X determină funcţional Y sau Y depinde funcţional (FD)
de X, dacă pentru orice relaţie r (valoare curentă a lui R) nu există două
tupluri care să aibă aceleaşi valori pentru atributele lui X şi să aibă valori
diferite pentru cel puţin un atribut din Y. Cu alte cuvinte, o valoare a lui X
determină unic o valoare a lui Y. Notaţia utilizată pentru desemnarea
dependenţei funcţionale este X → Y. Altfel spus:
Definitie: Fie R un tabel relational si X si Y două submultimi de coloane
ale lui R. Spunem că X determină functional pe Y sau că Y depinde
functional de X dacă nu există două rânduri în tabelul R care să aibă aceleasi
valori pentru coloanele din X si să aibă valori diferite pentru coloanele din Y.
Dependenţa funcţională X → Y reprezintă o constrângere aplicată
tuplurilor relaţiei R, în sensul că oricare două tupluri din R care au aceeaşi
valoare pentru X trebuie să ia aceeaşi valoare şi pentru Y.
Dacă pentru fiecare valoare a lui X există cel mult o valoare a lui Y,
spunem că X este determinant iar Y este determinat.
Comparând toate submulţimile de atribute ale unei relaţii şi
determinând legăturile dintre ele, se pot obţine toate dependenţele
funcţionale pe care o relaţie le satisface. Această abordare nu este eficientă,
consumând mult timp. Există posibilitatea ca, ştiind anumite dependenţe
funcţionale şi utilizând reguli de deducţie, să fie obţinute toate dependenţele
funcţionale.

22
Fie X, Y, Z, W mulţimi de atribute ale unei scheme relaţionale R şi fie
următoarele reguli de inferenţă (axiome) prin care noi dependenţe
funcţionale pot fi deduse din cele date:
Ax1 – reflexivitate. X → X. Mai general, dacă Y ⊆ X, atunci X → Y.
Ax2 – creşterea determinantului. Pot fi considerate trei formulări echi-
valente pentru această axiomă.
1. Dacă X → Y şi X ⊆ Z, atunci Z → Y.
2. Dacă X → Y şi W ⊆ Z, atunci X ∪ Z → Y ∪ W.
3. Dacă X → Y atunci X ∪ Z → Y ∪ Z.
Ax3 – tranzitivitate. Dacă X → Y şi Y → Z, atunci X → Z.

4.3. Necesitatea normalizării

Anomaliile care apar în lucrul cu baze de date se produc datorită


dependenţelor care există între datele din cadrul relaţiilor bazei. Aceste
anomalii fac extrem de dificil lucrul cu baza de date. Aceste anomalii vor fi
comentate cu ajutorul unui exemplu.
Se consideră o vizualizare (VP) asupra schemei relaţionale
PREZENTARE ce conţine doar atributele cod_prezentare#, denumire,
luna_start, cod_organizator. Aceste atribute reprezintă pentru fiecare
prezentare de modă: codul acesteia, denumirea, luna în care începe prezentarea
şi codul organizatorului.
Se consideră constrângerea: „toate prezentările de modă cu acelaşi
nume încep în aceeaşi lună“.

cod_prezentar denumire luna_start cod_organizato


e r
1 primavara mai 11
2 primavara mai 37
3 primavara mai 11
4 iarna martie 32
5 toamna august 11

Fig. 4.1. Vizualizarea VP

Datorită dependenţei introduse pot exista: anomalii la inserare,


modificare sau ştergere, redundanţă în date, probleme de reconexiune.
1. Redundanţă logică. Cuplul (primavara, mai) apare de trei ori.

23
2. Anomalie la inserţie. Dacă se doreşte includerea unei prezentări
de modă, care va incepe în luna aprilie şi va avea denumirea
„veselie“, atunci perechea (veselie, aprilie) poate fi inserată în
relaţia VP doar dacă se defineşte o nouă valoare pentru cheia
primară.
3. Anomalie la ştergere. Dacă este ştearsă înregistrarea pentru care
codul prezentării are valoarea 4, atunci se pierde informaţia că
prezentarea având denumirea „iarna“ a început în luna martie.
4. Anomalie la modificare. Dacă se modifică luna de început a
prezentării „primavara“ de la mai la februarie, atunci costul
modificării este mare pentru a modifica toate înregistrările, iar
dacă se modifică doar o înregistrare atunci constrângerea nu va
mai fi verificată.
Anomaliile au apărut datorită dependenţei funcţionale (constrângerii)
introduse anterior.
Normalizarea are drept scop: suprimarea redundanţei logice, evitarea
anomaliilor la reactualizare, rezolvarea problemei reconexiunii. Există o
teorie matematică a normalizării al cărei autor este E.F. Codd. Soluţia lui
E.F. Codd este construirea unor tabele standard (forme normale).
Normalizarea este procesul reversibil de transformare a unei relaţii, în
relaţii de structură mai simplă. Procesul este reversibil în sensul că nicio
informaţie nu este pierdută în timpul transformării. O relaţie este într-o formă
normală particulară dacă ea satisface o mulţime specificată de constrângeri.
Procesul normalizării se realizează plecând de la o relaţie universală ce
conţine toate atributele sistemului de modelat, plus o mulţime de anomalii.
Orice formă normală se obţine aplicând o schemă de descompunere.

4.4. Forme normale

Formele normale ale relaţiilor din baze de date relaţionale sunt


definite în raport cu anomaliile care pot apărea în lucrul cu aceste relaţii,
deci în funcţie de dependenţele nedorite care se manifestă în cadrul relaţiilor.
Pe măsură ce relaţia este transformată în forme superioare, devine din
ce în ce mai restrictivă ca format şi mai puţin expusă anomaliilor la
reactualizare. Altfel spus:
Definitie: Normalizarea reprezintă procesul de descompunere a unui
tabel relational în mai multe tabele care satisfac anumite reguli si care
stochează aceleasi date ca si tabelul initial astfel încât să fie eliminate
redundanta în date si anomaliile la actualizare.

24
Prima formă normală (FN1)

O relaţie este în prima formă normală dacă fiecărui atribut care o


compune îi corespunde o valoare indivizibilă (atomică). În plus, un tuplu nu
trebuie să conţină atribute sau grupuri de atribute repetitive.
Această formă figurează ca cerinţă minimală în majoritatea sistemelor
relaţionale.
Algoritm AFN1 (aducerea unei relaţii în FN1 prin eliminarea
atributelor compuse şi a celor repetitive)
1. Se introduc în relaţie, în locul atributelor compuse, componentele
acestora.
2. Se plasează grupurile de atribute repetitive, fiecare în câte o nouă
relaţie.
3. Se introduce în schema fiecărei noi relaţii de la pasul 2 cheia
primară a relaţiei din care a fost extras atributul repetitiv.
4. Se stabileşte cheia primară a fiecărei noi relaţii create la pasul 2.
Aceasta este compusă din cheia introdusă la pasul 3, precum şi din
atribute proprii ale acestor noi relaţii.
Forma normală 2 (FN2)
O relaţie R este în a doua formă normală dacă şi numai dacă:
• relaţia R este în FN1;
• fiecare atribut care nu este cheie (nu participă la cheia primară)
este dependent de întreaga cheie primară.
A doua condiţie exprimă necesitatea dependenţei totale de cheia
primară. Această formă normală interzice manifestarea unor dependenţe
funcţionale parţiale în cadrul relaţiei R.
Pentru a obţine o relaţie FN2 se poate aplica regula Casey-Delobel.
Fie relaţia R(K1, K2, X, Y), unde K1 şi K2 definesc cheia primară, iar X şi Y
sunt mulţimi de atribute, astfel încât K1 → X. Din cauza dependenţei
funcţionale K1 → X care arată că R nu este în FN2, se înlocuieşte R (fără
pierdere de informaţie) prin două proiecţii R1(K1, K2, Y) şi R2(K1, X).
Caracterul reversibil al normalizării

Prin caracter reversibil al normalizării se întelege faptul că descompunerea


se face fără pierdere de informatie, adică tabelul initial poate fi reconstituit
prin compunerea naturală, pe atribute comune, a tabelelor rezultate.

25
Pentru un tabel R care se descompune prin proiectie în mai multe tabele: R1,
R2, … Rn, conditia de descompunere fără pierdere de informatie presupune
ca în urma operatiei de compunere naturală a tabelelor R1, R2, … Rn să se
obtină tabelul R.

Regula Casey-Delobel (caz particular de descompunere fără pierdere de


informatie):

Fie un tabel R(X, Y, Z) care se descompune prin proiectie în tabelele R1(X,


Y) si R2(X, Z) unde prin X notăm setul de coloane comune ale tabelelor R1
si R2, iar prin Y si Z, coloanele specifice lui R1, respectiv R2. Conditia de
descompunere fără pierdere de informatie presupune ca tabelul R să fie
obtinut prin compunerea naturală a tabelelor R1 si R2.

În SQL:

SELECT R1.X, R1.Y, R2.Z


FROM R1, R2
WHERE R1.X = R2.X
Algoritm AFN2 (aducerea unei relaţii în FN2 prin eliminarea depen-
denţelor funcţionale parţiale din cadrul unor relaţii aflate în FN1)
1. Pentru fiecare dependenţă funcţională parţială se creează o nouă
relaţie având schema formată din determinantul şi determinatul
acestei dependenţe.
2. Se elimină din cadrul relaţiei iniţiale atributele care formează
determinatul dependenţei parţiale.
3. Dacă în relaţia iniţială există mai multe dependenţe parţiale cu
acelaşi determinant, pentru acestea se creează o singură relaţie cu
schema formată din determinant (luat o singură dată) şi din
determinaţii dependenţelor considerate.
4. Se determină cheia primară a fiecărei noi relaţii create. Aceasta va
conţine atributele din determinantul dependenţei funcţionale
parţiale care au stat la baza constituirii relaţiei.
5. Dacă noile relaţii create conţin dependenţe parţiale, atunci se face
transfer la pasul 1, altfel procesul de aducere la FN2 s-a terminat.

26
Exemplu
Fie schema relaţională PARTICIPA (cod_prezentare#,
cod_casa_moda#, tip, data, data_start, data_final, denumire)

Pentru relaţia PARTICIPA sunt adevărate dependenţele:


{cod_prezentare} → {data_start, data_final, denumire}
{cod_prezentare, cod_casa_moda} → {data, tip}
Relaţia PARTICIPA este în FN1, dar nu este în FN2 deoarece
atributele data_start, data_final şi denumire nu depind de codul casei de
modă, deci nu depind de întreaga cheie primară.
Pentru a obţine o relaţie în FN2 se aplică regula Casey Delobel şi
relaţia PARTICIPA se proiectează în două relaţii:
PARTI1(cod_prezentare#, data_start, data_final, denumire)
PARTI2(cod_prezentare#, cod_casa_moda#, data, tip).

Notă (reamintim C2):


Entitatea PREZENTARE are atributele: cod_prezentare, denumire,
data_start, data_final, cod_organizator, cod_soc_asig, cod_locatie.
Entitatea CASA_MODA are atributele: cod_casa_moda, nume, cifra_afaceri,
proprietar, director, istoric, data_creare, cod_localizare, cod_info_acces.
Atribute ale relatiei PARTICIPA
tip = variabilă de tip caracter, de lungime maximă 15, care reprezintă
modalitatea în care o casă de modă participă la o prezentare, în sensul că
poate fi organizator sau neorganizator.
data = variabilă de tip dată calendaristică reprezentând ziua în care defilează
modelele casei de modă. Atributul nu este multiplu, deoarece s-a presupus că
defilarea unei case de modă are loc într-o singură zi.

Alt Exemplu:

Fie tabelul VANZARI care se foloseste la înregistrarea tranzactiilor unui


magazin ce vinde articole la comandă.

VANZARI (cod_client#, cod_comanda#, cod_articol#, nume_client,


nr_telefon, data, nume_articol, cost_articol, cantitate)

A1 C1 P1 Popescu 415355 08.10.04 camasa 400000 2


A1 C1 P3 Popescu 415355 08.10.04 tricou 200000 1

27
A2 C2 P1 Ionescu 596322 09.10.04 camasa 400000 3
A2 C2 P3 Ionescu 596322 C2 09.10.04 tricou 200000 2
A2 C2 P2 Ionescu 596322 09.10.04 pantaloni 800000 1
A1 C3 P3 Popescu 415355 10.10.04 tricou 200000 3
A3 C4 P1 Marinescu 546229 C4 10.10.04 P1 camasa 400000 1

Tabelul de mai sus prezintă următoarele deficiente:

a) redundante în date:
- informatia (P1, camasa, 400000) este specificata de 3 ori
- informatia (A1, Popescu, 415355) este specificata de 3 ori
- informatia (A2, Ionescu, 196322) este specificata de 3 ori
- s. a. m. d.
b) anomalii la actualizare:

- anomalie la insertie
Dacă magazinul achizitionează un nou articol (P4, pantofi, 980000)
informatia nu poate fi introdusă în tabel (un nou tuplu) pentru că s-ar
introduce o valoare Null în cheia primară (cod_comanda).
- anomalie la stergere
Dacă este anulat articolul P2 în cadrul comenzii C2 se pierde informatia
referitoare la numele si costul articolului respectiv.
- anomalie la modificare
Dacă se modifică numărul de telefon al unui client, modificarea trebuie
facută în toate tuplurile (liniile) unde apare numele acelui client.
În tabelul VANZARI există următoarele dependente functionale în
care determinantul nu este cheie a tabelului:

(cod_articol) → (nume_articol, cost_articol)


(cod_comanda) → (data, cod_client, nume_client, nr_telefon)
(cod_client) → (nume_client, nr_telefon)
Pentru a obţine o relaţie în FN2 se aplică regula Casey Delobel şi
relaţia VANZARI se proiectează în trei relaţii:

VANZARI1(cod_articol# nume_articol, cost_articol)


VANZARI2(cod_comanda#, data, cod_client, nume_client, nr_telefon)
VANZARI3(cod_client #, nume_client, nr_telefon)

28
Forma normală 3 (FN3)
Intuitiv, o relaţie R este în a treia formă normală dacă şi numai dacă:
• relaţia R este în FN2;
• fiecare atribut care nu este cheie (nu participă la o cheie) depinde
direct de cheia primară.
Fie R o relaţie, X o submulţime de atribute ale lui R şi A un atribut al
relaţiei R. A este dependent tranzitiv de X dacă există Y astfel încât X → Y şi
Y → A (unde A nu aparţine lui Y şi Y nu determină pe X). De exemplu, dacă
au loc dependenţele K1, K2, K3 → A1 şi K1, K2, A1 → A2, atunci K1, K2, K3 →
K1, K2, A1 şi K1, K2, A1 → A2. Prin urmare, A2 este dependent tranzitiv de K1,
K2, K3.
Formal, o relaţie R este în a treia formă normală dacă şi numai dacă:
• relaţia R este în FN2;
• fiecare atribut care nu este cheie (nu participă la o cheie) nu este
dependent tranzitiv de nicio cheie a lui R.
A doua condiţie interzice utilizarea dependenţelor funcţionale tranzitive
în cadrul relaţiei R.
Prin urmare, o relaţie este în FN3 dacă şi numai dacă fiecare
atribut care nu este cheie depinde de cheie, de întreaga cheie şi numai de
cheie.
Pentru a obţine o relaţie FN3 se poate aplica regula de descompunere
Casey-Delobel. Fie relaţia R(K, X1, X2, X3), unde atributul X2 depinde
tranzitiv de K, iar K este cheia primară a lui R. Presupunem că K → X1 →
X2. Din cauza dependenţei funcţionale X1 → X2 care arată că R nu este în
FN3, se înlocuieşte R (fără pierdere de informaţie) prin două proiecţii R1(K,
X1, X3) şi R2(X1, X2).
Dependenţa tranzitivă poate fi mai complexă. Fie K1 o parte a cheii K.
Tranzitivitatea poate fi de forma K → Y → X2 unde Y = {K1, X1}. În acest
caz, R poate fi descompusă în R1(K, X1, X3) şi R2(K1, X1, X2).
Algoritm AFN3 (aducerea unei relaţii FN2 în FN3 prin eliminarea
dependenţelor funcţionale tranzitive)
1. Pentru fiecare dependenţă funcţională tranzitivă se transferă
atributele implicate în dependenţa tranzitivă într-o nouă relaţie.
2. Se determină cheia primară a fiecărei noi relaţii create la pasul 1.
3. Se introduc în relaţia iniţială, în locul atributelor transferate, cheile
primare determinate la pasul 2.

29
4. Se reanalizează relaţia iniţială. Dacă în cadrul ei există noi
dependenţe tranzitive, atunci se face transfer la pasul 1, altfel
procesul de aducere la FN3 s-a terminat.
Exemplu
Fie schema relaţională PREZENT(cod_prezentare#, data_start,
data_final, denumire, cod_locatie, capacitate, cod_info_acces).
Pentru relaţia PREZENT sunt adevărate dependenţele:
{cod_prezentare} → {data_start, data_final, denumire, cod_locatie}
{cod_locatie} → {capacitate, cod_info_acces}
Relaţia PREZENT este în FN2, dar nu este în FN3 deoarece atributele
capacitate, cod_info_acces depind indirect de cheia primară, prin
intermediul atributului cod_locatie.
Pentru a obţine o relaţie în FN3 se aplică regula Casey-Delobel şi
relaţia PREZENT se proiectează în două relaţii, prin eliminarea
dependenţelor funcţionale tranzitive.
PREZENT1(cod_prezentare#, data_start, data_final, denumire, cod_locatie)
PREZENT2(cod_locatie#, capacitate, cod_info_acces)

Forma normală Boyce-Codd (BCNF)


Determinantul este un atribut sau o mulţime de atribute neredundante,
care constituie un identificator unic pentru alt atribut sau altă mulţime de
atribute ale unei relaţii date.
Intuitiv, o relaţie R este în forma normală Boyce-Codd dacă şi numai
dacă fiecare determinant este o cheie candidat.
Formal, o relaţie R este în forma normală Boyce-Codd dacă şi numai
dacă pentru orice dependenţă funcţională totală X → A, X este o cheie a lui
R.
Algoritm ABCNF (aducerea unei relaţii FN3 în BCNF prin
eliminarea dependenţelor funcţionale ai căror determinanţi nu sunt chei
candidat)
1. Dacă relaţia conţine unul sau cel mult două atribute, atunci nu pot
exista dependenţe noncheie şi deci relaţia este în BCNF.
2. Dacă relaţia conţine mai mult de două atribute, se caută dacă ea
conţine dependenţe noncheie. Dacă nu există astfel de dependenţe,
relaţia este în BCNF.
3. Pentru fiecare dependenţă noncheie X → Y se creează două relaţii.
Una dintre ele va avea schema formată din atributele {X, Y}, iar

30
cealaltă va avea schema formată din toate atributele relaţiei
iniţiale, mai puţin Y.
4. Se reiau paşii 1, 2, 3 pentru relaţiile obţinute la pasul 3.
Exemplu
Se consideră relaţia FINANTEAZA1, ce leagă entităţile
PREZENTARE şi SPONSOR. Ea are cardinalitatea many to many şi va
genera un tabel asociativ. Se presupune că acest tabel are schema
relaţională:
FINANTEAZA1(cod_prezentare#, cod_sponsor#, nume_prezentare,
cod_ordin_plata).
Pentru exemplul analizat se presupune că numele prezentărilor sunt
unice. Prin urmare, în orice moment fiecare prezentare are un cod unic şi
un nume unic. Cheile candidat sunt {cod_prezentare, cod_sponsor},
respectiv {nume_prezentare, cod_sponsor}.
Între atributele relaţiei există dependenţele:
{cod_prezentare, cod_sponsor} → {cod_ordin_plata}
{cod_prezentare} → {nume_prezentare}
Tabelul nu este în BCNF deoarece conţine doi determinanţi,
cod_prezentare şi nume_prezentare, care nu sunt chei candidat pentru
tabelul respectiv. Ambele atribute sunt determinanţi deoarece fiecare îl
determină pe celălalt.
Soluţia problemei constă în divizarea relaţiei în două proiecţii
conform tehnicii Casey-Delobel.
PREZENTARE(cod_prezentare#, nume_prezentare)
FINANTEAZA(cod_prezentare#, cod_sponsor#, cod_ordin_plata)

Forma normală 4 (FN4)


Dacă BCNF elimină redundanţele datorate relaţiilor singulare, FN4
elimină redundanţele datorate relaţiilor m:n, adică datorate dependenţei
multiple.
Intuitiv, o relaţie R este în a patra formă normală dacă şi numai dacă
relaţia este în BCNF şi nu conţine relaţii m:n independente.
Exemplu
Fie schema relaţională
PERS_CONTACT(cod_pers#, limba_cunoscuta, nr_telefon).
Se presupune că o persoană de contact poate cunoaşte mai multe limbi
străine şi poate avea mai multe numere de telefon. Între atributele relaţiei
există multidependenţele:

31
cod_pers# →→ limba_cunoscuta
cod_pers# →→ nr_telefon.
Pentru a aduce relaţia PERS_CONTACT (care este în BCNF) în FN4,
aceasta se va diviza în două proiecţii :
PERS_CONTACT1(cod_pers#, limba_cunoscuta)
PERS_CONTACT1(cod_pers#, nr_telefon).

Forma normală 5 (FN5)


Semnificaţia lui FN5 este mai mult „academică“, ea apărând rar în
practică. A cincea formă normală îşi propune eliminarea redundanţelor care
apar în relaţii m:n dependente. În general, aceste relaţii nu pot fi
descompuse. S-a arătat că o relaţie de tip 3 este diferită de trei relaţii de tip
2. Există totuşi o excepţie, şi anume, dacă relaţia este ciclică.
Intuitiv, o relaţie R este în forma normală 5 dacă şi numai dacă:
1. relaţia este în FN4;
2. nu conţine dependenţe ciclice.

Exemplu
Se consideră o relaţie ce conţine informaţii despre creatori,
vestimentaţiile create de aceştia şi accesoriile corespunzătoare. Se consideră
schema relaţională CREARE(cod_vestimentatie#, cod_creator#,
cod_accesoriu#).
Se presupune că fiecare creator poate crea una sau mai multe
vestimentaţii. Fiecare vestimentaţie poate fi creată de unul sau mai mulţi
creatori. Similar, fiecare creator este responsabil de crearea unuia sau a mai
multor accesorii, iar fiecare accesoriu este creat de unul sau mai mulţi
creatori. Fiecare accesoriu apare în una sau mai multe vestimentaţii, iar
fiecărei vestimentaţii i se ataşează unul sau mai multe accesorii.
Mai mult chiar, dacă creatorul C creează vestimentaţia V, iar
accesoriul A este ataşat lui V, iar C este este responsabil de A, atunci C
creează accesoriul A pentru vestimentaţia V.
Ţinând seama de constrângerile impuse modelului se obţin
dependenţele:
{cod_vestimentatie#, cod_creator#} → {cod_accesoriu}
{cod_vestimentatie#, cod_accesoriu#} → {cod_creator}
{cod_accesoriu#, cod_creator#} → {cod_vestimentatie}.
Datorită dependenţelor formulate anterior, relaţia nu este în FN5. Ea
se poate rupe prin proiecţie în trei relaţii:
CREARE1(cod_vestimentatie#, cod_creator#)

32
CREARE2(cod_vestimentatie#, cod_accesoriu#)
CREARE3(cod_creator#, cod_accesoriu#).
În acest caz, sunt evidente relaţiile:
CREARE ≠ JOIN(CREARE1, CREARE2)
CREARE ≠ JOIN(CREARE1, CREARE3)
CREARE ≠ JOIN(CREARE2, CREARE3)
CREARE = JOIN(JOIN(CREARE1, CREARE2), CREARE3).
Concluzii:
1. FN1 → FN2 elimină redundanţele datorate dependenţei netotale a
atributelor care nu participă la o cheie, faţă de cheile lui R. Se
suprimă dependenţele funcţionale care nu sunt totale.
2. FN2 → FN3 elimină redundanţele datorate dependenţei tranzitive.
Se suprimă dependenţele funcţionale tranzitive.
3. FN3 → BCNF elimină redundanţele datorate dependenţei
funcţionale. Se suprimă dependenţele în care partea stângă nu este
o supercheie.
4. BCNF → FN4 elimină redundanţele datorate multidependenţei. Se
suprimă toate multidependenţele care nu sunt şi dependenţe
funcţionale.
5. FN4 → FN5 elimină redundanţele datorate dependenţei ciclice. Se
suprimă toate join-dependenţele care nu sunt implicate de o cheie.
6. BCNF, FN4 şi FN5 corespund la regula că orice determinant este
o cheie, dar de fiecare dată dependenţa cu care se defineşte deter-
minantul este alta şi anume dependenţa funcţională,
multidependenţa sau join-dependenţa.
7. Descompunerea unei relaţii FN2 în FN3 conservă datele şi
dependenţele, pe când descompunerea unei relaţii FN3 în BCNF
şi, respectiv, a unei relaţii BCNF în FN4 conservă doar datele.

33
Partea a II-a. LIMBAJUL SQL

În această tema: se prezintă conceptele limbajului SQL în 5 lecŃii,


după cum urmează:
INTRODUCERE. Concepte SQL
LECłIA 1. Limbajul de definire a datelor - DDL
LECłIA 2. Limbajul de interogare a datelor - DQL
LECłIA 3. Combinarea datelor din mai multe tabele –Uniuni
LECłIA 4. Limbajul de manipulare a datelor – DML
LECłIA 5. Limbajul de control al datelor – DCL

Introducere. Concepte SQL

SQL a devenit limbajul universal pentru bazele de date relaŃionale


şi este acceptat de aproape toate sistemele SGBD moderne. Fără îndoială,
acceptarea pe scară largă este rezultatul timpului şi eforturilor depuse
pentru dezvoltarea caracteristicilor limbajului şi a standardelor, crescând
nivelul de portabilitate a codului SQL între diferitele produseSGBD.

Ce este SQL?
SQL (Structured Query Language -limbaj structurat de
interogare) este un limbaj standard folosit pentru crearea, actualizarea şi
regăsirea informaŃiilor stocate în baze de date prin intermediul sistemelor
de gestionare a bazelor de date ( SGBD-uri).
Numele limbajului poate fi pronunŃat pe litere (es-q-el) sau la fel ca
şi cuvântul englezesc „sequel". O interogare (query) este o simplă cerere
transmisă către baza de date, la care aceasta răspunde într-o anumită
formă. SQL este limbajul folosit cel mai frecvent pentru interogarea
bazelor de date. SQL este considerat un limbaj neprocedural sau
declarativ, ceea ce înseamnă că-i spuneŃi calculatorului ce rezultate vreŃi,
fară să-i spuneŃi cum să le obŃină. De exemplu, dacă vreŃi să obŃineŃi
media numerelor de pe o coloană, folosiŃi funcŃia AVG. Nu este nevoie să
număraŃi valorile din coloană şi să împărŃiŃi suma acestora la numărul
obŃinut - procesorul limbajului SQL din SGBD se ocupă de toate aceste
lucruri în locul dumneavoastră.
Este important să înŃelegi că SQL nu este un limbaj procedural, ca
C, Pascal, Basic, FORTRAN, COBOL sau Ada. Un limbaj procedural
foloseşte o serie de instrucŃiuni executate secvenŃial. De asemenea,
limbajele procedurale includ instrucŃiuni care pot modifica secvenŃa de

1
execuŃie, prin ramificarea la alte porŃiuni ale procedurii sau prin
parcurgerea ciclică a unui set de instrucŃiuni din procedură. MulŃi
producători de sisteme SGBD oferă extensii procedurale ale limbajului
SQL de bază, cum ar fi Oracle PL/SQL (Procedural Language/SQL) sau
Microsoft Transact-SQL, dar reŃineŃi că acestea sunt extensii SQL care
formează noi limbaje - codul SQL pe care-1 conŃin rămâne neprocedural.
De asemenea, SQL nu trebuie confundat cu limbajele orientate spre
obiecte, precum Java şi C++.
Simplu spus, SQL este un limbaj neprocedural pentru gestionarea
şi întreŃinerea bazelor de date relaŃionale, nu un limbaj potrivit pentru
programarea generală a aplicaŃiilor, cum ar fi sistemele de prelucrare a
comenzilor sau a plăŃilor.
SQL este deseori folosit în combinaŃie cu limbajele procedurale sau
orientate spre obiecte menŃionate anterior pentru a manipula stocarea şi
extragerea datelor, folosind instrucŃiuni din limbajul de programare cu
destinaŃie generală pentru alte sarcini de programare, precum prezentarea
datelor pe o pagină web sau furnizarea răspunsurilor la informaŃiile
introduse de utilizatori de la tastatură sau mouse. Atunci când este
necesară interacŃionarea cu baza de date, instrucŃiunile din limbajul
procedural formează instrucŃiunea SQL, o transmit către SGBD în
vederea prelucrării, primesc rezultatele returnate de SGBD şi le
prelucrează într-un mod corespunzător.
Folosind SQL puteŃi transforma întrebări obişnuite :”Din ce oras
sunt studentii notri?” în instrucŃiuni pe care le înŃelege soft-ul pentru baze
de date: “SELECT oras FROM studenti”.
SQL se poate folosi nu numai pentru interogare, dar şi pentru a
adăuga, a modifica sau a şterge înregistrări din bazele de date.
Majoritatea SGBD -urilor populare, ca de exemplu Microsoft
Accsess, Oracle şi MySQL , asigură suport pentru SQL, chiar dacă acest
nivel de suport diferă de la produs la produs.

Conectarea la baza de date

Atunci când folosiŃi limbajul SQL pe un calculator personal, cu o


copie personală a unui sistem SGBD, precum Microsoft Access sau
Oracle Personal Edition, toate componentele bazei de date rulează pe
acelaşi sistem de calcul. Totuşi, acest aranjament nu este potrivit pentru
bazele de date care trebuie să fie folosite în comun de mai mulŃi
utilizatori. Ca urmare, sunt mult mai frecvent întâlnite situaŃiile în care
baza de date este instalată într-un aranjament client/server.
Într-un aranjament client/server:

2
• Sistemul rulează pe un server, care este un sistem de calcul
partajat. Pentru scopurile acestei definiŃii, un sistem mainframe poate fi
considerat un server de dimensiuni mari.
• Fişierele care compun baza de date din punct de vedere fizic sunt
stocate pe discuri conectate la serverul de baze de date.
• Utilizatorii care au acces la baza de date folosesc staŃii de lucru,
numite clienŃi. Clientul trebuie să aibă o conexiune de reŃea la baza de
date, care poate fi o reŃea privată, instalată acasă sau la birou, ori o reŃea
publică, precum Internet.
• Componentele software furnizate de producătorul SGBD rulează
pe staŃiile de lucru alte clienŃilor pentru a oferi utilizatorilor posibilitatea
să introducă instrucŃiuni SQL, să le transmită sistemului SGBD în
vederea prelucrării şi să vadă rezultatele returnate de DBMS. În general,
acest software se numeşte client SQL.
ReŃineŃi că nimic nu vă opreşte să instalaŃi clientul SQL pe acelaşi
calculator cu sistemul SGBD. De fapt, mulŃi dezvoltatori care utilizează
sisteme SGBD precum MySQL, Microsoft SQL Server şi Oracle fac în
mod obişnuit acest lucru, deoarece este foarte convenabil să aibă întregul
mediu de dezvoltare pe un singur calculator, cum ar fi un laptop. Totuşi,
în momentul în care este necesar accesul partajat al mai multor utilizatori,
este mult mai convenabil şi mai eficient să aveŃi o singură copie a
sistemului SGBD pe un server partajat şi să aveŃi numai clientul SQL
instalat pe staŃia de lucru a fiecărui client.
În funcŃie de interfaŃa cu utilizatorul de pe staŃia de lucru client,
clienŃii SQL sunt clasificaŃi în trei categorii: în linia de comandă, grafici
şi bazaŃi pe web. O interfaŃă în linia de comandă se bazează exclusiv pe
intrări şi ieşiri de tip text, cu comenzile introduse de la tastatură şi
răspunsurile afişate ca mesaje de tip text. Principalul avantaj al
interfeŃelor în linia de comandă este că pot fi rulate pe aproape orice
sistem de operare. De exemplu, clientul SQL*Plus rulat într-o fereastră de
comandă Microsoft Windows.

3
O interfaŃă grafică cu utilizatorul (GUI - Graphical User Interface)
rulează sub un tip oarecare de sistem bazat pe ferestre, cum ar fi :
X Window System, Mac OS sau Microsoft Windows, şi afişează datele
sau opŃiunile comenzilor folosind elemente grafice, precum pictograme,
butoane şi casete de dialog. În figura de mai jos se prezintă clientul
SQL*Plus(unul din clienții SQL furnizați de ORACLErulat ca aplicație
GUI sub Microsoft Windows.

O interfaŃă bazată pe web rulează pe serverul de baze de date,


folosind un browser web de pe staŃia de lucru client pentru a interacŃiona
cu utilizatorul bazei de date. Din punct de vedere tehnic, un client SQL
bazat pe web nici nu este o aplicaŃie client, deoarece nu există nici o
componentă software specifică producătorului SGBD rulată pe staŃia de
lucru a clientului. Totuşi, aproape întotdeauna există componente
furnizate de producătorul SGBD care sunt descărcate în fundal de
browser-ul web pentru a asista în procesul de reprezentare grafică a
formularelor web folosite pentru introducerea instrucŃiunilor SQL şi
afişarea rezultatelor.
Tabelul următor prezintă clienŃi SQL oferiŃi de diferiŃi producători
SGBD. În aceast curs nu prezentăm toate detaliile referitoare la fiecare
client SQL pe care aŃi putea să-1 folosiŃi, aşa că vă rog să consultaŃi
documentaŃia producătorului SGBD pentru informaŃii despre instalarea şi
utilizarea clienŃilor SQL disponibile pentru sistemul SGBD pe care-1
folosiŃi

4
Producător SGBD Client SQL Descriere
Microsoft Access este o bază de date de uz
personal, cu clientul SQL integrat în
Microsoft Access Nu există
DBMS, toate fiind rulate local pe staŃia de
lucru a utilizatorului.
Client SQL care rulează ca aplicaŃie în
Microsoft SQL Server iSQL linia de comandă într-un nucleu de
comenzi Microsoft Windows.
Client SQL care rulează ca
Microsoft SQL Server Query Analyzer
aplicaŃie Microsoft Windows.
Client SQL care rulează ca
aplicaŃie în linia de comandă sub
MySQL MySQL MySQL diferite sisteme de operare, inclusiv
Microsoft Windows, Linux, Mac OS
X şi diferite implementări Unix.
Client SQL bazat pe web -
Oracle Oracle iSQL*Plus acceptat în versiunile Oracle 9i
si mai noi.
Client SQL care rulează ca
aplicaŃie Microsoft Windows sau
ca aplicaŃie în linia de comandă
Oracle Oracle SQL*Plus sub diferite sisteme de operare,
inclusiv Microsoft Windows,
Linux, Mac OS X, diferite
implementări Unix şi altele.
Client SQL scris în Java -
disponibil în Oracle 8i şi 9i, dar
Oracle Oracle SQL Worksheet
înlocuit de iSQL*Plus în Oracle
10g.
Clientul SQL care rulează ca aplicaŃie

în linia de comandă într-un nucleu de

comenzi Microsoft Windows.

Sybase Sybase iSQL Asemănările cu Microsoft SQL Server

nu sunt întâmplătoare - primele

versiuni Microsoft SQL Server erau

bazate pe sistemul SGBDSybase.

5
Un scurt istoric al limbajului SQL

Către sfârşitul anilor '70, un grup de cercetători de la IBM au


dezvoltat o bază de date relaŃională, numită System/R, bazată pe lucrările
Dr. E. F. Codd. În System/R a fost inclus un limbaj, numit SEQUEL
(Structured English Query Language), pentru manipularea şi extragerea
datelor. Acronimul „SEQUEL" a fost ulterior condensat în abrevierea
„SQL", atunci când s-a descoperit că „SEQUEL" era marcă înregistrată a
companiei Hawker-Siddeley Aircraft din Marea Britanie.
Deşi IBM a creat prima implementare SQL, două alte produse, cu
nume diferite pentru limbajele de interogare, au fost lansate pe piaŃă ca
primele produse pentru baze de date relaŃionale, Oracle, furnizat de
Relational Software, şi INGRES, furnizat de Relational Technology. IBM
a lansat în 1982 produsul SQL/DS, cu limbajul de interogare numit acum
SQL (Structured Query Language). Dacă programarea structurată era
expresia la modă în anii '80, cuvântul „structured" din SQL nu avea nici o
legătură cu programarea structurată, deoarece SQL nu este un limbaj de
programare procedural.
Comitetele de standardizare a limbajului SQL au fost formate de
ANSI (American National Standards Institute) în 1986 şi ISO
(International Organization for Standardization) în 1987. Din fericire,
comitetele create de cele două organizaŃii au colaborat pentru dezvoltarea
unui standard SQL comun, la nivel mondial. Doi ani mai târziu, au fost
publicate primele specificaŃii ale standardului, numite SQL-89. După trei
ani, specificaŃiile originale au fost extinse, sub forma standardului SQL-
92, care avea aproximativ 600 de pagini. A treia generaŃie a fost numită
SQL-99 sau SQL3. Cele mai multe produse SGBD sunt construite pe
baza standardului SQL-92 (numit acum SQL2). SQL3 include multe
caracteristici obiectuale, necesare pentru folosirea limbajului SQL cu o
bază de date relaŃională orientată spre obiecte, precum şi extensii de
limbaj care fac din SQL un limbaj de programare complet (adăugând
cicluri, ramificări şi construcŃii de comutare, de tip case). Cea mai recentă
generaŃie, numită SQL:2003, introduce caracteristici legate de XML şi
alte îmbunătăŃiri. Aceste standarde nu sunt gratuite. Standardul SQL:2003
poate fi cumpărat de la ISO (www.iso.org) sau ANSI (webstore.ansi.org).
Pentru cei care au un buget mai restrâns, este disponibilă o versiune
apropiată de cea finală la Whitemarsh Information Systems Corporation
(www.wiscorp.com/SQLStandards.html). Aproape toŃi furnizorii au
adăugat extensii la „dialectul" SQL propriu, în parte deoarece doreau să
diferenŃieze produsele proprii şi în parte deoarece cerinŃele pieŃei îi forŃau
să implementeze caracteristici înainte a apărea standarde pentru acestea.
Un astfel de exemplu este acceptarea tipurilor de date
TIMESTAMP şi DATE. Datele calendaristici sunt foarte importante

6
pentru prelucrarea datelor comerciale, dar dezvoltatorii produselor SGBD
originale erau academicieni şi oameni de ştiinŃă, nu specialişti în
prelucrări comerciale, aşa că această cerinŃă nu a fost anticipată. Ca
rezultat, primele dialecte SQL nu asigurau un suport special pentru datele
calendaristice. Pe măsură ce au apărut produsele comerciale, furnizorii au
răspuns cererilor lansate de clienŃii importanŃi şi au adăugat în grabă
suportul pentru date calendaristice. Din nefericire, din cauza grabei
fiecare a făcut-o în felul propriu. Codul SQL este foarte compatibil şi
portabil între produsele diferiŃilor furnizori, dar sistemele complete de
baze de date pot fi rareori transferate fară anumite ajustări.
SQL a sistemului Oracle este o extensie a normei SQL89 şi o
implementare a normei SQL92.

ConvenŃii de sintaxă SQL

Această secŃiune prezintă convenŃiile generale de sintaxă folosite


pentru construia instrucŃiunilor SQL. Totuşi, reŃineŃi că există o mulŃime
de extensii şi variaŃii între diferiŃii producători. Pentru simplitate,
termenul implementare este folosit pentru referirea fiecărei versiuni SQL
a fiecărui producător (cu alte cuvinte, Oracle 9i, Oracle 10g, Microsoft
SQL Server 7, Microsoft SQL Server 2000 şi Microsoft SQL Server 2005
conŃin implementări diferite ale limbajului SQL).
ConvenŃiile de sintaxă SQL sunt mai uşor de înŃeles folosind un
exemplu simplu. InstrucŃiunea de mai jos returnează valorile Movie ID şi
Movie Title pentru toate filmele din magazinul de produse video pentru
care categoria MPAA este „PG":
SELECT FILM_ID, TITLU_FILM
FROM FILM
WHERE MPAA_RATING_COD = 'PG';
ConvenŃiile de bază sunt următoarele:
• Fiecare instrucŃiune începe cu o comandă, de obicei sub forma
unui singur cuvânt, care aproape întotdeauna este un verb (în limba
engleză) care descrie o acŃiune. În acest exemplu, instrucŃiunea începe cu
comanda SELECT, care este descrisă în detaliu în lecŃia 3.
• Fiecare instrucŃiune se termină cu un delimitator, care este, de
obicei, un caracter punct şi virgulă (;). Unele implementări permit
schimbarea delimitatorului cu un alt caracter. Mai mult, unele
implementări, cum ar fi cea din Oracle, nu execută o instrucŃiune SQL
căreia-i lipseşte delimitatorul de sfârşit, în timp ce alte implementări
consideră acest delimitator opŃional.
• InstrucŃiunile sunt construite într-o manieră similară cu
propoziŃiile din limba engleză, cu unul sau mai multe spaŃii pentru

7
separarea elementelor de limbaj. Un element de limbaj, asemănător cu un
cuvânt dintr-o propoziŃie, poate fi un cuvânt cheie (SELECT, FROM,
WHERE), numele unui obiect al bazei de date (FILM, FILM_ID,
TITLU_FILM), un operator (=) sau o constantă ('PG') care apare într-o
instrucŃiune.
• InstrucŃiunile sunt scrise într-o formă liberă, ceea ce înseamnă că
nu există reguli stricte privind poziŃia elementelor de limbaj pe o linie sau
locul în care se poate face trecerea la o linie nouă. Totuşi, în general nu
este o idee bună să împărŃiŃi un element de limbaj pe mai multe linii. Din
punct de vedere logic, instrucŃiunea de mai jos este identică cu cea
prezentată la începutul acestei secŃiuni, dar nu este la fel de uşor de citit şi
de înŃeles:
SELECT FILM_ID, TITLU_FILM FROM FILM WHERE
MPAA_RATING_COD ='PG';

• InstrucŃiunile sunt organizate într-o serie de clauze şi, de obicei,


clauzele trebuie să apară într-o anumită ordine atunci când sunt folosite
(multe clauze sunt opŃionale). în exemplul nostru, există trei clauze,
fiecare începând cu un cuvânt cheie (SELECT, FROM, WHERE).
• Elementele de limbaj SQL pot fi scrise cu litere mari, cu litere
mici sau în combinaŃii. Totuşi, în majoritatea implementărilor şi în
conformitate cu standardele ANSI/ISO, toate minusculele sunt
transformate în majuscule în vederea prelucrării. Aceasta nu înseamnă că
datele nu pot conŃine litere mici, ci că numele obiectelor din baza de date
(tabele, coloane etc.) şi comenzile trebuie să fie scrise cu litere mari.
ExcepŃii notabile sunt Microsoft SQL Server şi Sybase, care permit
modul de lucru cu diferenŃierea literelor mari de cele mici, caz în care
numele de obiecte scrise diferit sunt tratate ca nume diferite. în MySQL,
diferenŃierea literelor mari de cele mici în numele obiectelor este legată
de capacitatea sistemului de operare de a face această diferenŃiere.
• Virgulele sunt folosite pentru separarea articolelor dintr-o listă. În
exemplul nostru, numele a două coloane sunt specificate într-o listă
separată prin virgule (FILM_ID, TITLU_FILM). SpaŃiile care urmează
după virgule sunt opŃionale - puteŃi adăuga orice număr de spaŃii, inclusiv
zero.
• Şirurile de caractere care apar în instrucŃiunile SQL trebuie să
fie încadrate cu apostrofuri (unele implementări SQL permit şi folosirea
ghilimelelor). Constantele numerice nu sunt niciodată încadrate cu
apostrofuri. Dacă în şirul de caractere trebuie să apară un caracter
apostrof, sunt inserate două apostrofuri unul lângă celălalt. De exemplu,
dacă vreŃi să găsiŃi în baza de date un film numit Sophie's Choice, veŃi
scrie clauza WHERE astfel:
WHERE TITLU_FILM = 'Sophie''s Choice'

8
• Numele obiectelor bazei de date sunt formate folosind numai
litere, cifre şi liniuŃe de subliniere. Caracterul underscore (liniuŃa de
subliniere) este folosit, de obicei, ca separator între cuvinte, pentru
îmbunătăŃirea lizibilităŃii. Aşa cum am menŃionat anterior, unele
implementări permit folosirea numelor care fac diferenŃa între literele
mari şi cele mici, cum ar fi PersonMiddleName, un stil numit deseori
„scriere de tip cămilă", dar acest stil nu este recomandabil dacă doriŃi ca
instrucŃiunile SQL să fie portabile pe alte implementări. în definitiv, un
nume precum „PERSONMIDDLENAME" nu este foarte uşor de citit.
• In fiecare implementare SQL este definit un set de cuvinte
rezervate, care sunt cuvinte cu o semnificaŃie specifică pentru procesorul
SQL al sistemului SGBD şi, care urmare, nu trebuie folosite într-un alt
context - de exemplu ca nume pentru obiectele bazei de date. Scopul
acestei restricŃii este de a evita interpretarea greşită a instrucŃiunilor SQL
de către SGBD. Aşa cum probabil bănuiŃi, lista cuvintelor rezervate diferă
semnificativ de la o implementare SQL la alta, aşa că este bine să
consultaŃi documentaŃia implementării pe care o folosiŃi pentru a vă
familiariza cu aceste cuvinte.
• Un comentariu pe o singură linie începe cu două liniuŃe de
despărŃire (--). Cele două liniuŃe se pot afla la începutul unei linii, ceea ce
înseamnă că întreaga linie este considerată comentariu, sau oriunde în
cadrul liniei, caz în care restul liniei, până la sfârşit, este considerat
comentariu. De exemplu:
-- Acesta este un comentariu pe o singură linie în SQL.
• Un comentariu pe mai multe linii începe cu combinaŃia dintre o
diagonală la dreapta (slash) şi un asterisc (/*) şi continuă până la
întâlnirea combinaŃiei invers (*/). AveŃi grijă să terminaŃi corect
comentariile, altfel multe linii SQL pe care le-aŃi scris vor fi tratate de
către SGBD ca şi cum ar fi comentarii. Iată un exemplu de comentariu pe
mai multe linii:
/* Acesta este un comentariu pe mai multe linii.
Continuă până la întâlnirea combinaŃiei de caractere care
marchează sfârşitul comentariului. */

Sistemul impune anumite restricŃii asupra identificatorilor.


• Numele unui obiect nu poate depăşi 30 de caractere, cu
excepŃia numelui bazei de date care este limitat la 8 caractere şi
a numelui legăturii unei baze care poate ajunge la 128 caractere.
• Nu se face distincŃie între litere mici şi litere mari.
• Numele trebuie să înceapă printr-un caracter alfabetic şi nu
poate fi un cuvânt cheie rezervat; poate să conŃină literele mari
şi mici ale alfabetului englez, cifrele 0 - 9 şi caracterele $, _, #.

9
• Un utilizator nu trebuie să definească două obiecte cu acelaşi
nume.
• În general este bine ca numele unui obiect să fie descriptiv şi
fără prescurtări excesive.

Categorii de instrucŃiuni SQL

InstrucŃiunile SQL sunt împărŃite în categorii, după funcŃiile pe


care le îndeplinesc. Unii experŃi consideră aceste categorii ca fiind
limbaje separate sau sublimbaje. Totuşi, în SQL acestea au aceeaşi
sintaxă de bază şi respectă aceleaşi reguli, aşa că eu le consider categorii
de instrucŃiuni din acelaşi limbaj.
Categoriile de instrucŃiuni, descrise în secŃiunile următoare, sunt:
• Limbajul de definire a datelor (DDL sau LDD – Data
Definition Language)
• Limbajul de interogare a datelor (DQL-Data Query Language)
• Limbajul de manipulare a datelor (DML sau LMD - Data
Manipulation Language)
• Limbajul pentru controlul datelor (DCL sau LCD–Data
Control Language)
• Comenzile pentru controlul tranzacŃiilor (Transaction Control
Commands)

Limbajul de definire a datelor (DDL)

Limbajul de definire a datelor (DDL - Data Definition Language)


include instrucŃiuni SQL care permit utilizatorului bazei de date să creeze
şi să modifice structura obiectelor bazei de date, cum ar fi tabele,
vizualizări şi indexuri. InstrucŃiunile SQL care folosesc comenzile
CREATE, ALTER şi DROP sunt considerate parte a DDL. Este
important să înŃelegeŃi că instrucŃiunile DDL afectează containerele care
stochează datele în baza de date, nu datele propriu-zise. Ca urmare, există
instrucŃiuni DDL pentru crearea, ştergerea şi modificarea tabelelor, dar
nici una dintre aceste instrucŃiuni nu oferă posibilitatea de a crea sau
modifica rânduri de date din tabelele respective.
InstrucŃiunile LDD au efect imediat asupra bazei de date şi
înregistrează informaŃia în dicŃionarul datelor. De asemenea, LDD contine
instructiunile RENAME, TRUNCATE si COMMENT.

10
Limbajul de interogare a datelor (DQL)

Limbajul de interogare a datelor (DQL - Data Query Language)


include instrucŃiuni SQL care permit obŃinerea datelor din baza de date.
Deşi reprezintă o parte foarte importantă a limbajului SQL, DQL este
format din instrucŃiuni care folosesc o singură comandă: SELECT. Unii
furnizori şi autori clasifică instrucŃiunile DQL şi DML în aceeaşi
categorie.

Limbajul de manipulare a datelor (DML)

Limbajul de manipulare a datelor (DML - Data Manipulation


Language) include instrucŃiuni SQL care permit utilizatorului bazei de
date să adauge date în baza de date (sub forma rândurilor din tabele), să
şteargă date şi să modifice datele existente în baza de date. InstrucŃiunile
SQL care folosesc comenzile INSERT, UPDATE şi DELETE sunt
considerate parte a DML.

Limbajul pentru controlul datelor (DCL)

Limbajul pentru controlul datelor (DCL – Data Control Language)


include instrucŃiuni SQL care permit administratorilor să controleze
accesul la datele din baza de date şi folosirea diferitelor privilegii ale
sistemului DBMS, cum ar fi privilegiul de oprire şi pornire a bazei de
date. InstrucŃiunile SQL care folosesc comenzile GRANT si ALTER sunt
considerate parte a DCL.

Comenzile pentru controlul tranzacŃiilor


O tranzacŃie în baza de date este un set de comenzi pe care
utilizatorul bazei de date vrea sa le trateze ca pe o unitate funcŃionala de
tip „totul sau nimic”, întelegând prin aceasta că intreaga tranzactie trebuie
sa reuseasca sau sa esueze. Comenzile pentru cotrolul tranzacŃiilor
(Transaction Control Commands ) nu respectă cu exactitate sintaxa
instrucŃiunilor SQL , dar afecteaza puternic comportamentul
instructiuunilor SQL incluse în tranzacŃii.

Lecția 1:Limbajul de definire a datelor


La nivel logic, o bază de date Oracle este alcătuită din scheme. O
schemă este o mulŃime de structuri logice de date, numite obiecte. Ea
aparŃine unui utilizator al bazei de date şi poartă numele său.

11
Specificarea bazelor de date şi a obiectelor care le compun se
realizează prin intermediul limbajului de definire a datelor (DDL).
Definirea unui obiect presupune crearea, modificarea şi suprimarea sa.
Limbajul de definire a datelor cuprinde instrucŃiunile SQL care permit
realizarea acestor operaŃii (CREATE, ALTER, DROP).
InstrucŃiunile DDL au efect imediat asupra bazei de date şi
înregistrează informaŃia în dicŃionarul datelor. De asemenea, DDL contine
instructiunile RENAME, TRUNCATE si COMMENT.
În cadrul unei scheme se pot defini obiecte de tip: tabel (table),
vizualizare (view), vizualizare materializată (materialized view), secvenŃă
(sequence), index (index), sinonim (synonym), grupare (cluster),
procedură (procedure) şi funcŃie (function) stocată, declanşator (trigger),
pachet stocat (package), legătură a bazei de date (database link),
dimensiune (dimension) etc.
Se vor prezenta în continuare instrucŃiunile SQL folosite pentru
definirea şi gestionarea obiectelor dintr-o bază de date relaŃională.
InstrucŃiunile CREATE, ALTER şi DROP formează o categorie a
limbajului SQL numită limbaj de definire a datelor (DDL– Data
Definition Language).
Se prezintă DDL înaintea DQL, DML deoarece trebuiesc create
obiectele bazei de date înainte de a insera date în baza de date.

ConvenŃii de sintaxă
InstrucŃiunile SQL DDL au mai multe opŃiuni decât alte
instrucŃiuni SQL. Următoarele convenŃii sunt pentru a prezenta sintaxa
instrucŃiunilor DDL:
• Cuvintele cheie şi cuvintele rezervate din SQL sunt scrise cu
majuscule, cum ar fi CREATE TABLE.
• InformaŃiile pe care ar trebui să fie furnizate la scrierea
instrucŃiunilor sunt scrise cu italic, cum ar fi nume_coloană.
• Elementele opŃionale sunt încadrate în paranteze pătrate, cum ar
fi [WITH TIME ZONE].
• OpŃiunile dintr-o listă de elemente posibile sunt separate de o
bară verticală (simbolul logic pentru „sau"), cum ar fi TABLE |
VIEW | INDEX. Se pot întâlni uneori ca listă de elemente
opŃionale, cum ar fi [NULL | NOT NULL].
• Elementele de grup care sunt explicate sau analizate ulterior pe
componente (de obicei după descrierea unui tip principal de
instrucŃiune) sunt încadrate de caracterele „mai mic decât" şi

12
„mai mare decât", cum ar fi <specificaŃii_pentru_coloană>.
• Un element care se poate repeta este urmat de trei puncte, cum ar
fi. [,<restricŃie_pentru_tabel>...].
Toate celelalte simboluri, în special virgulele şi parantezele, fac
parte din sintaxa SQL obligatorie şi, ca urmare, trebuie să fie incluse aşa
cum sunt scrise aici.

Tipuri de date
O coloană este cea mai mică unitate denumită care poate fi referită
într-o bază de date relaŃională. Fiecare, coloană trebuie să aibă asociate
un nume unic şi un tip de date. Un tip de date este o categorie pentru
formatul folosit de o anumită coloană. Tipurile de date asigură câteva
avantaje importante:
• RestricŃionarea, datelor din coloana respectivă la caracterele care
au sens pentru tipul de date specificat.
• Asigurarea unor comportamente utile pentru utilizatorul datelor.
De exemplu, dacă se scade un număr dintr-un alt număr, se
obŃine ca rezultat un număr; dar dacă se scade o dată dintr-o altă
dată, se obŃine ca rezultat diferenŃa în zile dintre cele două date
calendaristice.
• Creşterea eficienŃei sistemului SGBD la stocarea datelor din
coloane.
SQL acceptă trei categorii de tipuri de date: tipuri predefinite,
tipuri construite şi tipuri definite de utilizator.
Tipurile de date predefinite sunt cele furnizate de către producător
ca parte nativă a sistemului SGBD(vor fi tratate în continuare).
Tipurile de date construite, cunoscute şi ca tipuri de colecŃii, conŃin
matrice sau seturi de tipuri de date predefinite, în scopul reprezentării în
SGBD a construcŃiilor de date orientate spre obiect.
Tipurile de date definite de utilizator permit utilizatorului bazei de
date să definească propriile tipuri de date, adaptate unor scopuri specifice.
Ultimele două tipuri de date nu vor fi tratate , fiind prea
complicate pentru intenŃiile cursului.
Tipuri de date predefinite din standardul SQL:2003

Majoritatea implementărilorSQL acceptă cea mai mare parte parte

13
a tipurilor de date definite de standardul SQL:2003.
Avem următoarele clase de tipuri:
Tipuri de date pentru caractere, tipuri de date numerice,
tipuri de date temporale şi tipuri de date pentru obiecte mari.

Tipuri de date pentru caractere


Tipurile de date pentru caractere conŃin şiruri de caractere, adică
litere, cifre şi alte simboluri permise de sistemul de calcul pe care se află
baza de date.
Tipurile de date stardard pentru caractere sunt:
• Caracter cu lungime fixă - Un şir de caractere cu lungime finită.
Sintaxa SQL este:
CHARACTER(lungime) | CHAR(lungime)
Exemplu: CNP CHAR(13)
• Caracter naŃional - Acest tip de date poate fi folosit pentru
traducerea şirurilor de caractere în diferite limbi. Sintaxa SQL
este:
NATIONAL CHARACTER(lungime) | NCHAR(lungime)
Exemplu: TITLU_FILM NCHAR(50)
• Caracter variabil - Un şir de caractere cu lungime variabilă,
specificând lungimea maximă a şirurilor de caractere stocate.
Sintaxa SQL este:
CHARACTER VARYING(lungime_maximă) |
VARCHAR(lungime_maximă)
Exemplu: NUME_CLIENT VARCHAR(125)
• Caracter naŃional variabil – O variantă a tipului de date pentru
şiruri de caractere cu lungime variabilă, stocata într-un set de
caractere al unei anumite limbi. Sintaxa SQL este:
NATIONAL CHARACTER VARYING(lungime_maximă) |
NVARCHAR (lungime_maximă)
Exemplu: TITLU_FILM NVARCHAR(100)

Tipuri de date numerice

14
Acestea sunt utile mai ales pentru atributele folosite în calcule.
Toate tipurile numerice au o precizie (un număr de cifre). De asemenea
unele tipuri numerice au şi o scală (numărul de cifre aflate în dreapta
punctului zecimal). Tipurile întregi şi tipurile numerice care include o
scală sunt numite tipuri numerice exacte, în timp ce numerele reale care
nu include o scală (numerele cu virgulă mobilă) sunt numite numerice
aproximative.
Tipurile numerice standard sunt:
• Numeric - Un tip numeric exact care include o precizie şi o
scală. Sintaxa SQL este:
NUMERIC (precizie, scală)
Exemplu: PLATA_PE_ORA_ANGAJAT NUMERIC(5,2)
• Zecimal - Un tip numeric exact care include o precizie şi o scală.
Diferența față de Numeric, constă în faptul că precizia este mai
mare , având scopul de a permite maparea tipului peste un tip al
al platformei pe care rulează SGBD. Sintaxa SQL este:
DECIMAL(precizie, scală)
Exemplu: PLATA_PE_ORA_ANGAJAT DECIMAL(5,2)
• Întreg - Un tip numeric exact care include numai precizia, scris
INTEGER sau INT. Numerele întregi nu au cifre zecimale, aşa
că scala nu este necesară, deoarece este întotdeauna zero.
Sintaxa SQL este:
INTEGER (precizie) | INT (precizie)
Exemplu: ID_CONT_CLIENT INTEGER
• Întreg mic - O variantă a tipului INTEGER, scrisă SMALLINT,
care stochează numere mai mici şi, ca urmare, ocupă mai puŃin
spaŃiu. Sintaxa SQL este:
SMALLINT (precizie)
Exemplu: ID_CONT_CLIENT SMALLINT
• Întreg mare - O variantă a tipului INTEGER, scrisă BIGINT,
care stocheză numere mai mari şi ocupă mai mult spaŃiu.
Sintaxa SQL este:
BIGINT (precizie)
Exemplu: ID_CONT_CLIENT BIGINT
• Număr în virgulă mobilă - Un tip numeric aproximativ, cu
precizia mai mare sau egală cu precizia specificată. Specificarea

15
preciziei este opŃională. Este scrisă FLOAT. Sintaxa SQL este:
FLOAT (precizie)
Exemple: RATA_DOBANDA FLOAT(16)
RATA_DOBANDA FLOAT
• Număr real - Un tip numeric aproximativ, cu precizie definită de
implementare. Sintaxa SQL este:
REAL
Exemplu: RATA_DOBANDA REAL
• Număr real cu precizie dublă - Un tip numeric aproximativ, cu
precizie definită de implementare, dar mai mare sau egală cu
precizia definită pentru tipul REAL. Sintaxa SQL este:
DOUBLE PRECISION | DOUBLE
Exemplu: RATA_DOBANDA DOUBLE PRECISION

Tipuri de date temporale (tipuri pentru date şi ore)


Aceste tipuri stochează date care măsoară timpul, într-un mod
oarecare.
Tipurile de date temporale conŃin următoarele componente, numite
de standard, câmpuri (fields) :

Numele câmpului (cuvânt cheie


DefiniŃie
SQL)
Anul calendaristic, pe două sau
YEAR
patru cifre
MONTH Luna din an
DAY Ziua din lună
HOUR Ora din zi
MINUTE Minutul din oră
SECOND Secunda din minut
Valoarea orei cu diferenŃa de fus
TIMEZONE_HOUR
orar
Valoarea minutului cu diferenŃa
TIMEZONE_MINUTE
de fus orar

Câmpurile TIMEZONE_HOUR şi TIMEZONE_MINUTE sunt


incluse în toate tipurile de date temporale pentru care este specificat
cuvântul cheie WITH TIMEZONE.

16
Tipurile de date temporale sunt:

• Data - O dată calendaristică, incluzând câmpurile YEAR,


MONTH şi DAY. Sintaxa SQL este:
DATE [WITH TIMEZONE]
Exemplu: DATA_NASTERE DATE
• Ora - Un tip de date pentru oră, incluzând câmpurile HOUR,
MINUTE şi SECOND. Sintaxa SQL este:
TIME [WITH TIMEZONE]
Exemplu: TIMPUL_DEMARARE TIME
• Marcă temporală - Un tip de date combinat pentru dată şi oră,
incluzând câmpurile YEAR, MONTH, DAY, HOUR, MINUTE
şi SECOND. Sintaxa SQL este:
TIMESTAMP [WITH TIMEZONE]
Exemplu: DATA_TIMP_ NASTERE TIMESTAMP
• Interval - Un interval de timp, incluzând câmpurile
specificate printr-un calificator de interval (internal qualifier),
care reprezintă precizia intervalului. Sintaxa SQL este:
INTERVAL câmp_de_start TO
câmp_de_sfârşit|INTERVAL câmp
Exemple:
DURATA_PROIECT INTERVAL YEAR TO DAY
TIMP_LUCRU INTERVAL HOUR TO MINUTE
ZILE_VACANTA INTERVAL DAY

Tipuri de date pentru obiecte mari- LONG

Obiectele mari permit stocarea unor date care depăşesc cu mult


posibilităŃile de stocare ale tipurilor de date prezentate până acum,
ajungând deseori la dimensiuni de câŃiva megaocteŃi. Deoarece
manipularea obiectelor mari este un subiect avansat, care nu vace obiectul
cursului, se vor prezenta aceste tipuri fără sintaxa lor.
• Obiect mare pentru caractere - Un obiect mare pentru
caractere, scris în SQL sub foma CLOB.
• Obiect mare pentru caractere, în format naŃional - Un obiect
mare pentru caractere, stocat într-o anumită limbă, scris în SQL
sub forma NLOB.
• Obiect mare binar - Un obiect mare care conŃine date binare,
cum ar fi o imagine sau o secvenŃă sonoră, scris în SQL sub
forma BLOB.

17
Există restricŃii referitoare la folosirea tipului de date LONG.
• Într-un tabel poate să fie o singură coloană de tip LONG.
• Nu pot fi comparate două şiruri de caractere de tip LONG.
• O coloană de tip LONG nu poate fi parametru într-o procedură.
• O funcŃie nu poate întoarce ca rezultat o valoare de tip LONG.
• O coloană de tip LONG nu poate fi folosită în clauzele WHERE,
ORDER BY, GROUP BY, CONNECT.
• Operatorii sau funcŃiile Oracle nu pot fi folosiŃi în SQL pentru a
modifica coloane de tip LONG.
• O coloană de tip LONG nu poate fi indexată.

Un alt tip de date


Există un tip standard de date care nu este încadrat în nici una
dintre categoriile prezentate anterior:
Boolean - Stochează o valoare logică adevărat sau fals.
Sintaxa SQL este:
BOOLEAN
Exemplu: CLIENT_PREFERAT BOOLEAN

Extensii pentru tipuri de date şi diferenŃe faŃă de standard

Microsoft Access

Microsoft Access este baza de date care respectă în cea mai mică
măsură standardul, din toate sistemelm SGBD frecvent folosite.
Tipurile de date acceptate de Microsoft Access sunt:

• Text - Echivalent cu tipul de date standard VARCHAR. Poate


stoca până la 255 de caractere.
• Memo - ConŃine şiruri cu cel mult 65535 de caractere, dar este
definit fără specificarea unei dimensiuni.
• Number - Echivalent cu tipul de date standard NUMERIC, dar
precizia şi scala sunt stabilite folosind meniul derulant Field Size
(Mărimea câmpului). Numerele întregi pot fi definite alegând
valoarea zero (0) pentru parametrul Decimal Places (PoziŃii
zecimale).
• Date/Time - Aproximativ echivalent cu tipul de date standard
TIMESTAMP, dar poate stoca orice date şi oră valide între anii
100 şi 9999.

18
• Currency - Un tip de date numeric echivalent cu tipul NUMERIC
(19,4), adică un număr cu 15 cifre în stânga punctului zecimal şi
cel mult 4 cifre în dreapta punctului zecimal.
• AutoNumber - Un câmp pe 4 sau 16 octeŃi (în funcŃie de valoarea
Field Size) incrementat automat cu o unitate de fiecare dată când
în tabel este inserat un nou rând.
• Yes/No - Aproximativ echivalent cu tipul de date standard
BOOLEAN. Totuşi, Microsoft Access permite ca acest tip de
date să fie formatat ca Yes/No, On/Off sau True/False.
• OLE Object - Similar cu tipul de date standard BLOB, acest tip de
date permite stocarea unui obiect Microsoft OLE cu dimensiunea
maximă de 1GB (gigaoctet).
• Hyperlink Un tip de date specializat care poate conŃine o adresă
web din Internet.
• Lookup wizard - Un tip de date specializat care creează o legătură
între o coloană din tabelul curent şi conŃinutul unei coloane dintr-
un alt tabel. Acest tip de date poate fi folosit pentru legarea
dinamică a tabelelor la crearea formularelor în Microsoft Access.

Oracle

Oracle SQL acceptă următoarele tipuri de date standard:


• BLOB -Obiecte binare mari, cu dimensiunea maximă de (4GB-1)
x (dimensiunea unui bloc din baza de date).
• CHAR - Şiruri de caractere cu lungime fixă, conŃinând cel mult
2000 de octeŃi.
• CLOB - Obiecte de tip caracter mari, cu dimensiunea maximă de
(4GB- 1) x (dimensiunea unui bloc din baza de date).
• DATE - FuncŃionează ca tipul standard de date DATE, dar din
punct de vedere tehnic seamănă mai mult cu tipul DATETIME,
deoarece poate stoca atât data, cât şi ora. Acceptă date de la 1
ianuarie 4712 î.e.n. la 31 decembrie 9999 e.n. OpŃional, poate fi
inclusă şi ora, în ore, minute şi secunde. Dacă partea opŃională
este omisă, este stocată cu valoarea zero, echivalentă cu miezul
nopŃii.
• DECIMAL - Implementat ca NUMBER(precizie,scală).
• DOUBLE PRECISION - Implementat ca NUMBER.
• FLOAT - Implementat ca NUMBER.
• INTEGER - Implementat ca NUMBER(38).

19
• INTERVAL - Un interval de timp, dar sunt acceptate din
standard numai variantele INTERVAL YEAR TO MONTH şi
INTERVAL DAY TO SECOND.
• NCHAR - Şiruri de caractere cu lungime fixă într-o limbă
naŃională, cu dimensiunea maximă de 2000 de octeŃi.
• NCLOB - Şiruri de caractere cu lungime fixă într-o limbă
naŃională, cu dimensiunea maximă de (4GB-1) x (dimensiunea
unui bloc din baza de date).
• NUMERIC - Implementat NUMBER(precizie,scală).
• NVARCHAR - Date de tip caracter cu lungime variabilă într-o
limbă naŃională, cu dimensiunea maximă de 4000 de octeŃi .
• REAL - Implementat ca NUMBER.
• SMALLINT - Implementat ca NUMBER(38).
• TIMESTAMP - Data şi ora în ani, luni, zile, ore, minute şi
secunde.
• VARCHAR - Date de tip caracter cu lungime variabilă,
conŃinând cel mult 4000 de caractere.

Oracle oferă următoarele extensii la tipurile de date standard:


• BFILE - O valoare de localizare a unui fişier binar de dimensiuni
mari, stocat în afara bazei de date.
• LONG - Date de tip caracter cu lungime variabilă, cu
dimensiunea maximă de 2GB.
• LONG RAW - Date binare, cu dimensiunea maximă de 2GB.
• NUMBER - Date numerice, cu cel mult 38 de cifre. Poate stoca
valori întregi sau în virgulă mobilă.
• NVARCHAR2 - Identic cu NVARCHAR.
• RAW - Date binare, cu dimensiunea maximă de 2000 de octeli.
• ROWID - Şir de caractere codat Base 64*, reprezentând adresa
unică a unui rând în tabelul din care face parte.
• UROWID - Şir de caractere codat Base 64, reprezentând adresa
logică a unui rând într-un tabel indexat.
• VARCHAR2 - Identic cu VARCHAR, dar Oracle recomandă
folosirea folosirea acestui tip în loc de VARCHAR, deoarece
Oracle e posibil să schimbe la un moment dat implementarea
tipului VARCHAR.

Precizari si exemple

Pentru memorarea datelor numerice, tipurile cele mai frecvent


folosite sunt: NUMBER, INTEGER, FLOAT, DECIMAL.

20
Pentru memorarea şirurilor de caractere, cele mai frecvent tipuri
de date utilizate sunt: CHAR, NCHAR, VARCHAR2 , NVARCHAR2 şi
LONG.
InformaŃii relative la timp sau dată calendaristică se obŃin
utilizând tipul DATE. Pentru fiecare dată de tip DATE sunt depuse:
secolul, anul, luna, ziua, ora, minutul, secunda. Pentru o coloană de tip
DATE sistemul rezervă 7 bytes, indiferent dacă se memorează doar
timpul, sau doar data calendaristică.
Formatul implicit al datei se defineşte cu ajutorul parametrului de
iniŃializare NLS_DATE_FORMAT. În general, acest parametru este setat
la forma DD-MON-YY. Dacă nu este specificat timpul, timpul implicit
este 12:00:00.
Oracle9i introduce noi tipuri de date pentru timp:
• TIMESTAMP(precizie_fracŃiuni_secundă) cuprinde
valori pentru anul, luna şi ziua unei date calendaristice, dar şi valori
pentru oră, minut, secundă
• INTERVAL YEAR (precizie_an) TO MONTH stochează o
perioadă de timp specificată în ani şi luni, unde precizie_an reprezintă
numărul de cifre din câmpul YEAR.
• INTERVAL DAY (zi) TO SECOND (prec_frac_sec)
stochează o perioadă de timp reprezentată în zile, ore, minute şi secunde.

Exemple

Să se creeze un tabel cu trei coloane, inceput, durata_1, durata_2.


Coloana inceput va cuprinde valori ce reprezintă momente de timp,
inclusiv fracŃiunile de secundă corespunzătoare. Valorile coloanei
durata_1 vor fi intervale de timp specificate în număr de zile, ore, minute
şi secunde. Coloana durata_3 va conŃine intervale de timp precizate în
număr de ani şi luni. Să se insereze o înregistrare în acest tabel.

CREATE TABLE TIMP (


inceput TIMESTAMP,
durata_1 INTERVAL DAY(2) TO SECOND(3),
durata_2 INTERVAL YEAR TO MONTH );

Exemple date inserate 1.


INSERT INTO timp

21
VALUES (TIMESTAMP '2009-10-31 09:26:50.30',
INTERVAL '23 7:44:22' DAY TO SECOND,
INTERVAL '19-02' YEAR TO MONTH);

Ex. 2
INSERT INTO timp
VALUES (TIMESTAMP '2010-02-20 09:20:40.20',
INTERVAL '23 7:44:22' DAY TO SECOND,
INTERVAL '200-02' YEAR TO MONTH);

INTERVAL '200-02' da eroare, deoarece implicit precizia pentru


an este 2, iar 200 are 3 digiti

Ex.3
INSERT INTO timp
VALUES (TIMESTAMP '2010-01-25 09:26:50.30',
INTERVAL '23 7:44:22' DAY TO SECOND,
INTERVAL '20-100' YEAR TO MONTH);

22
INTERVAL '20-100' eroare, deoarece 100 de luni adauga ani
Ex.4
INSERT INTO timp
VALUES (TIMESTAMP '2010-01-25 09:26:50.30',
INTERVAL '23 2:2:2' DAY TO SECOND,
INTERVAL '20-10' YEAR TO MONTH);

Ex.5
INSERT INTO timp
VALUES (TIMESTAMP '2010-01-25 09:26:50.30',
INTERVAL '23 2:2:2' DAY TO SECOND,
INTERVAL '20-12' YEAR TO MONTH);

INTERVAL '20-12' eroare deoarece 12 luni fac un an si depasesc


intervalul de 20 ani

Ex.6

23
INSERT INTO timp
VALUES (TIMESTAMP '2010-01-25 09:26:50.30',
INTERVAL '23 2:2:2' DAY TO SECOND,
INTERVAL ‘120’ MONTH);

Se observă ca executând instructiunea:


SELECT * from timp ;
Ca durata_2 are valoarea 10;

Ex.7
INSERT INTO timp
VALUES (TIMESTAMP '2010-01-25 09:26:50.30',
INTERVAL '360' SECOND,
INTERVAL ‘144’ YEAR);

24
Se observa că inregistrarea introdusa are :
• Durata_1 este de 6 min(360 sec) si
• Durata_2 de 12 ani(144 de zile)
Ex.8
INSERT INTO timp
VALUES (TIMESTAMP '2010-01-25 09:00:00.30',
INTERVAL '20' DAY(2),
INTERVAL ‘10’ YEAR);

Se observa că inregistrarea introdusa are :


• Durata_1 de 20 zile si 0 secunde( fiind un INTERVAL DAY TO
SECOND) si
• Durata_2 este 10 ani si 0 luni (fiind un INTERVAL YEAR TO
MONTH)

25
Exemplu
CREATE TABLE exemplu
(durata INTERVAL YEAR(3) TO MONTH);

INSERT INTO exemplu


VALUES (INTERVAL '120' MONTH);

SELECT TO_CHAR(SYSDATE+durata, 'DD-mon- YYYY')


FROM exemplu;

Exemplu
CREATE TABLE noi_carti
(codel NUMBER,
start_data TIMESTAMP);

INSERT INTO noi_carti


VALUES (1,TIMESTAMP '2009-10-31 09:26:50.30');

SELECT codel ,start_data


FROM noi_carti;

INSERT INTO noi_carti


VALUES (5, timestamp '12-02-08 0:0:0');

26
Pentru informatii de tip TIMESTAMP, numarul maxim de digiti
pentru fractiuni de secunda este 9, implicit este 6.
Rezultatele cererii:
1
31-OCT-09 09.26.50.300000 AM
5
08-FEB-12 12.00.00.000000 AM

Pentru informatii de tip DATE, formatul implicit ar fi fost DD-


MON-RR

Valori valide pentru date Valori valide pentru


Câmp
calendaristice intervale
De la -4712 la 9999 (cu excepŃia
YEAR Orice valoare întreagă.
anului 0).
MONTH De la 01 la 12. De la 0 la 11.
De la 01 la 31 (limitat de valorile
câmpurilor MONTH şi YEAR,
DAY Orice valoare întreagă.
corespunzător regulilor
calendarului curent).
HOUR De la 00 la 23. De la 0 la 23.
MINUTE De la 00 la 59. De la 0 la 59.
De la 00 la 59.9(n), unde „9(n)“ De la 0 la 59.9(n), unde
SECOND este precizia fracŃiunilor de „9(n)“ este precizia
secundă. fracŃiunilor de secundă.
De la –12 la 13 (prevede
TIMEZONE_HOUR schimbările datorate trecerilor la Nu se aplică.
ora de vară sau iarnă).
TIMEZONE_MINU
De la 00 la 59. Nu se aplică.
TE

Sistemul Oracle permite construcŃia de expresii folosind valori de


tip dată calendaristică şi interval. OperaŃiile care pot fi utilizate în aceste
expresii şi tipul rezultatelor obŃinute sunt următoarele:
• Data + Interval, Data – Interval, Interval + Data, iar rezultatul
este de tip dată calendaristică;
• Data – Data, Interval + Interval, Interval – Interval, Interval *
Number, Number * Interval, Interval / Number, iar rezultatul este de tip
interval.

27
Modele de format
Un model de format este un literal caracter care descrie formatul
valorilor de tip DATE sau NUMBER stocate într-un şir de caractere.
Atunci când se converteşte un şir de caractere într-o dată calendaristică
sau într-un număr, modelul de format indică sistemului cum să
interpreteze şirul respectiv.
În instrucŃiunile SQL se poate folosi un model de format ca
argument al funcŃiilor TO_CHAR şi TO_DATE. În felul acesta se poate
specifica formatul folosit de sistemul Oracle pentru a returna sau a stoca
o valoare în/din baza de date. Un model de format nu schimbă
reprezentarea internă a valorii în baza de date.
O parte dintre elementele cel mai frecvent întâlnite ale unui format
de tip numeric sunt sintetizate în tabelul următor.

Element Exemplu Descriere


Plasează o virgulă în poziŃia specificată. Într-un model de
format numeric pot fi precizate mai multe virgule, dar o
, (virgulă) 9,999
virgulă nu poate apărea în partea dreaptă a punctului
zecimal.
Plasează un punct zecimal în poziŃia specificată. Într-un
. (punct) 99.99 format numeric, se poate specifica cel mult un punct
zecimal.
$ $9999 Include semnul „$“ în faŃa unei valori.
0999;
0 Plasează zerouri în faŃa sau la sfârşitul valorii.
9990
Întoarce valoarea cu numărul specificat de cifre. Valoarea
9 9999 va avea un spaŃiu, respectiv un minus în faŃă dacă este
pozitivă, respectiv negativă.
Plasează în poziŃia specificată simbolul ISO pentru
C C999 monede(valoarea curentă a parametrului
NLS_ISO_CURRENCY).
Plasează în poziŃia specificată caracterul zecimal, care este
valoarea curentă a parametrului
D 99D99 NLS_NUMERIC_CHARACTER. Valoarea implicită este
punctul. Se poate specifica cel mult un caracter zecimal
într-un model de format numeric.
EEEE 9.9EEEE Returnează o valoare folosind notaŃia ştiinŃifică.
Întoarce în poziŃia specificată simbolul monedei locale
L L999
(valoarea curentă a parametrului NLS_CURRENCY).
Plasează semnul minus la sfârşitul valorilor negative şi un
spaŃiu la sfârşitul celor pozitive. Acest element poate fi
MI 9999MI
specificat numai pe ultima poziŃie a modelului de format
numeric.
S9999; Plasează semnele plus sau minus la începutul sau la
S
9999S sfârşitul valorii. Acest element poate apărea doar pe prima

28
sau ultima poziŃie a modelului de format numeric.

Modelele de format pentru date calendaristice pot fi utilizate în


cadrul următoarelor funcŃii de conversie:
• TO_DATE, pentru a converti o valoare de tip caracter, care este
într-un alt format decât cel implicit, într-o valoare de tip DATE;
• TO_CHAR, pentru a converti o valoare de tip DATE, care este
într-un alt format decât cel implicit, într-un şir de caractere.
• SYSDATE, pentru aflarea datei curente. De exemplu
SELECT SYSDATE FROM dual;
Un model de format pentru date calendaristice este alcătuit dintr-
unul sau mai multe elemente specifice. Scrierea cu litere mari sau mici a
cuvintelor, abrevierilor sau a numeralelor romane este respectată în
elementul de format corespunzător.
De exemplu, modelul de format „DAY“ produce cuvinte cu
majuscule, cum ar fi „FRIDAY“, iar „Day“ şi „day“ au ca rezultat
„Friday“, respectiv „friday“.
Într-un model de format pentru date calendaristice se pot preciza
semne de punctuaŃie şi literale caracter, incluse între ghilimele. Toate
aceste caractere apar în valoarea returnată pe locul specificat în modelul
de format.

Element ExplicaŃie
AD sau A.D. Indicatorul AD (Anno Domini) cu sau fără puncte.
BC sau B.C. Indicatorul BC (Before Christ) cu sau fără puncte.
Numărul zilei din săptămână (1-7). Duminica este considerată prima
D
zi a săptămânii.
DAY Numele zilei completat cu spaŃii, până la lungimea de 9 caractere.
DD Numărul zilei din lună (1-31).
DDD Numărul zilei din an (1-366).
DY Numele zilei din săptămână, printr-o abreviere de 3 litere.
FF FracŃiunile de secundă.
HH sau HH12 Ora din zi (1-12).
HH24 Ora din zi (0-23).
MI Minutele din oră (0-59).
MM Luna din an (01-12).
MON Numele lunii, printr-o abreviere de 3 litere.

29
MONTH Numele lunii completat cu spaŃii, până la lungimea de 9 litere.
RM Luna în cifre romane (I-XII).
RR Anul cel mai apropiat de data curentă.
Acceptă intrarea atât cu 2, cât şi cu 4 cifre. Dacă anul de intrare se dă
RRRR
cu 2 cifre, furnizează acelaşi lucru ca şi formatul RR.
SS Secundele din minut (0-59).
SSSSS Secundele trecute de la miezul noptii (0-86399).
TZH Ora regiunii.
TZM Minutul regiunii.
Y,YYY Anul scris cu virgulă după prima cifră.
YEAR sau SYEAR Anul în litere („S“ prefixează anii i.Hr. cu semnul minus).
YYYY sau SYYYY Anul cu 4 cifre.
YYY, YY sau Y Ultimele cifre ale anului.

Modificatorii FM şi FX pot fi utilizaŃi în modelele de format din


cadrul funcŃiei TO_CHAR, controlând completarea cu spaŃii şi verificarea
exactă a formatelor. Un modificator poate să apară într-un model de
format de mai multe ori. În acest caz, efectele sale sunt active pentru
porŃiunea din model care începe la prima apariŃie şi apoi dezactivate
pentru porŃiunea din model care urmează celei de-a doua apariŃii ş.a.m.d.
Modificatorul FM (Fill Mode) suprimă completarea cu spaŃii în
valoarea returnată de funcŃia TO_CHAR, iar FX (Format eXact) impune
corespondenŃa exactă dintre argumentul de tip caracter şi modelul de
format precizat pentru data calendaristică respectivă.

Exemplu:

SELECT nume, TO_CHAR(data_ang,’Month FMDD,YYYY’) angajare


FROM angajati
WHERE TO_CHAR(data_ang, ’YYYY’)=’2009’;

Nume Angajare
Pop January 21,2009
Ene October 10,2009

Exemplu
SELECT nume, TO_CHAR(data_ang,’ DDTH ”of” Month YYYY’)
angajare
FROM angajati
WHERE TO_CHAR(data_ang, ’YYYY’)=’2009’;

30
Nume Angajare
Pop 21st of January 2009
Ene 10TH of October 2009

Exemplu
SELECT TO_CHAR(data_ang,’ fmDDspth Month.Year’) angajare
FROM angajati
WHERE id_ang=100;

Angajare
Twenty_NineTH July, Two Thousand Nine

Exemplu
SELECT ’sesiune incepe pe ’|| TO_DATE(’20-09-2010’,’DD-MM-
YYYY’) from dual;
Sesiunea incepe pe 20-09-2010

(Afişează formatul standard pentru dată)


Valoarea null, reprezentând lipsa datelor, nu este egală sau diferită
de nici o altă valoare, inclusiv null.
Totuşi, există două situaŃii în care sistemul Oracle consideră două
valori null ca fiind egale: la evaluarea funcŃiei DECODE şi dacă valorile
null apar în chei compuse. Două chei compuse care conŃin valori null sunt
considerate identice dacă toate componentele diferite de null sunt egale.

Pseudocoloane

O pseudocoloană se comportă ca şi o coloană a unui tabel, dar nu


este stocată efectiv într-un tabel. Se pot face interogări asupra
pseudocoloanelor, dar nu se pot insera, actualiza sau şterge valorile
acestora.
• LEVEL returnează nivelul liniilor rezultat ale unei cereri
ierarhice.
• CURRVAL şi NEXTVAL sunt pseudocoloane utile în lucrul cu
secvenŃe şi sunt tratate în secŃiunea corespunzătoare acestora.
• ROWID returnează adresa unei linii din baza de date, furnizând
modul cel mai rapid de a accesa linia respectivă. În sistemul Oracle,
valorile acestei pseudocoloane conŃin următoarele informaŃii necesare
pentru a localiza o linie: numărul obiectului, blocul de date, fişierul de
date, linia în cadrul blocului de date. Valorile pseudocoloanei ROWID
sunt de tipul ROWID sau UROWID.
• ROWNUM returnează numărul de ordine al liniilor rezultate în

31
urma execuŃiei unei cereri. Pseudocoloana poate fi utilizată pentru a
limita numărul de linii returnate. Dacă este folosită clauza ORDER BY
într-o subcerere, iar condiŃia în care apare ROWNUM este plasată în
cererea de nivel superior, atunci condiŃia va fi aplicată după ordonarea
liniilor.

Exemplu:
Să se afişeze informaŃii despre operele de artă având cele mai mici
10 coduri.

SELECT *
FROM (SELECT * FROM opera ORDER BY cod_opera)
WHERE ROWNUM < 11;

InstrucŃiuni DDL (Data Definition Language)

InstrucŃiunile DDL (Data Definition Language) definesc obiectele


bazei de date, dar nu inserează şi nu actualizează date în obiectele
respective. În SQL, există trei comenzi de bază pentru instrucŃiunile
DDL:
CREATE - Creează în baza de date un nou obiect, de tipul
specificat în instrucŃiune : CREATE DATABASE, CREATE TABLE,
CREATE INDEX şi CREATE VIEW.
ALTER - Modifică definiŃia unui obiect existent în baza de
date, de tipul specificat în instrucŃiune : ALTER TABLE, ALTER
DATABASE, ALTER SYSTEM, ALTER USER, ALTER SESSION.
D R O P - Şterge (distruge) un obiect existent în baza de date, de
tipul specificat în instrucŃiune.

InstrucŃiunea CREATE DATABASE

Definirea unei baze de date diferă destul de mult de la o


implementare la alta. Sintaxa generală pentru instrucŃiunea CREATE
DATABASE este:
CREATE DATABASE nume bazadedate [opŃiuni_specifice
_producătorul]
În Oracle, instrucŃiunea CREATE USER crează în baza de date o
schemă, cere este aproximativ echivalentă cu o bază de date.

32
Standardul SQL prevede şi o instrucŃiune CREATE SCHEMA,
care permite crearea unor grupuri de obiecte din baza de date, pentru
simplificarea administrării.

FILM
FILM_ID PK
MPAA_RATING FILM_COD_GEN FK1 FILM_GEN
MPAA_COD_RATING PK MPAA_COD_RATING FK2 FILM_COD_GEN PK
MPAA_DESCRIERE_VARSTE FILM_NUME FILM_DESCRIERE_GEN
RETAIL_PRET_VHS
RETAIL_PRET_DVD
AN_PRODUS

FILM_COPII FILM_INCHIRIERE
FILM_LIMBA FILM_ID PK,FK1 FILM_ID PK,FK1
FILM_ID PK,FK1 NUMAR_COPIE PK NUMAR_COPIE PK,FK1
COD_LIMBA PK,FK2 DATA_CUMPARARE TRANZACTIE_ID PK,FK2
DATA_VANZARE DATA_INTOARCERE
FORMAT_MEDIA COST_INCHIRIERE
COST_INTARZIERE_SAU_PIERDERE
DATA_RETURNARE

LIMBA
COD_LIMBA PK CLIENT_CONT CLIENT_TRANZACTIE
NUME_LIMBA CLIENT_CONT_ID PK TRANZACTIE_ID PK
CLIENT_HOLD_IND CLIENT_CONT_ID FK1
DATA_INSCRIS ANGAJAT_PERSOANA_ID
DATA_TERMINAT TRANZACTIE_DATA
CLIENT_COD_PERSOANA CLIENT_DEPOZIT_SUMA VANZARI_TAXA
CLIENT_CONT_ID PK,FK1 CARD_CREDIT_LA_DOSAR_INDIC
PERSOANA_ID PK,FK2 COPIL_INCHIRIERE_PERMIS_INDIC

PERSOANA ANGAJAT
PERSOANA_ID PK PERSOANA_ID PK,FK1
PERSOANA_PRENUME SUPERVISOR_PERSOANA_ID
PERSOANA_NUME_MIJLOCIU ANGAJAT_TAXA_ID
PERSOANA_NUME ANGAJAT_JOB_CATEGORIE
PERSOANA_ADRESA_1 ANGAJAT_RATA_PE_ORA
PERSOANA_ADRESA_2 ANGAJARE_DATA
PERSOANA_ADRESA_ORAS INCHIDERE_DATA
PERSOANA_ADRESA_JUDET_PROV
PERSOANA_ADRESA_COD_POSTAL
PERSOANA_ADRESA_TARA
PERSOANA_TELEFON
NASTERE_DATA
MOARTE_DATA

33
Exemplu de Diagrama conceptuală
Exemplele din lucrare se referă la un model de gestiune a operelor
de artă dintr-un muzeu. Diagrama entitate-relaŃie (E/R) corespunzătoare
modelului analizat este prezentată în figura 2.1.
Schemele relaŃionale corespunzătoare diagramei conceptuale sunt:
• OPERA(cod_opera#, tip, titlu, cod_artist, data_crearii,
data_achizitiei, valoare, cod_galerie, cod_sala,
material, stil,
dim1, dim2, stare);
• GALERIE(cod_galerie#, nume_galerie, nume_cladire, adresa);
• SALA(cod_sala#, cod_galerie#, nume_sala, suprafata);
• SECURITATE(cod_opera#, sistem#, descriere, valoare,
data_inst, firma, executant);
• POLITA_ASIG(cod_opera, cod_polita#, descriere, firma,
valoare, semnat_contract);
• SPECIALIST(cod_specialist#, nume, prenume, experienta,
autorizatie, tip, loc);
• ARTIST(cod_artist#, nume, prenume, an_nastere, an_moarte,
nationalitate, observatii);
• SURSA_BIBLIO(cod_sursa#, tip, titlu);
• ARTICOL(cod_sursa#, nume_revista, nr_revista, data,
pag_revista);
• CARTE(cod_sursa#, an, editura, ISBN);
• AUTOR(cod_autor#, nume, prenume, descriere, job, adresa);
• EXPOZITIE(cod_expo#, nume_expo, tip);
• STUDIAZA(cod_opera#, cod_specialist#, data#, operatia,
metode, rezultat, plata);
• MENTIONATA_IN(cod_opera#, cod_sursa#, pagina#);
• FIGUREAZA_IN(cod_opera#, cod_expo#, cond_speciale,
localitate, data_inceput);
• EDITATA_DE(cod_sursa#, cod_autor#);
• ORGANIZATA_DE(cod_organizator#, cod_expozitie#);
• ORGANIZATOR(cod_organizator#, nume, tip_organizator,
adresa).
Numele atributelor corespunzătoare relaŃiilor menŃionate sunt
sugestive, astfel încât semnificaŃia lor este evidentă. Se pot face
următoarele precizări:
• câmpul tip din tabelul opera este un şir de caractere ce
reprezintă categoria în care se încadrează opera de artă
respectivă (pictură, sculptură, grafică, tapiserie etc.);

34
• material este un câmp de tip şir de caractere, ale cărui valori
specifică materialul din care a fost concepută opera de artă
(hârtie, pânză, bronz, aramă, piatră etc.);
• stil este un atribut de tip şir de caractere ce precizează stilul în
care se încadrează opera de artă respectivă (clasic, renascentist,
contemporan, impresionist etc.);
• dim1, dim2 sunt coloane numerice care specifică dimensiunile
operei;
• stare este un atribut de tip şir de caractere care precizează starea
fizică a operei de artă respective (medie, bună, foarte bună etc.);
• câmpul tip din tabelul specialist precizează calificarea unui
specialist (expert, restaurator, evaluator etc.);
• loc reprezintă Ńara care a emis autorizaŃia corespunzătoare unui
specialist;
• operatia specifică acŃiunea la care este supusă opera de artă
(lipire, retuşare, curăŃare etc.);
• atributul metode specifică procedeele utilizate în realizarea
operaŃiei (infraroşii, ultrasunete, raze X etc.);
• câmpul rezultat reŃine informaŃii asupra expertizei efectuate
(dacă opera de artă este un fals, nivelul restaurării etc.);
• câmpul tip din tabelul sursa_biblio precizează categoria
publicaŃiei în care apar referinŃe la opera de artă respectivă
(articol, studiu, monografie etc.);
• câmpul job specifică profesia autorului unei surse bibliografice
(profesor, expert, artist, jurnalist etc.);
• atributul observatii conŃine informaŃii referitoare la artişti
(pseudonim, curentul artistic de care aparŃin etc.);
• câmpul tip din tabelul expozitie precizează categoria din care
face parte o expoziŃie (fixă, itinerantă, temporară etc.).

35
GALERIE 1 inclusa_in M(1)
cod_galerie SALA
# cod_sala#
cod_galerie#

1
cuprinsa_in SECURITATE

M(1) cod_opera#
1 protejata_prin M(0)
sistem#
1 creata_de M(1)
ARTIST OPERA
1 asigurata_de M(0)
cod_artist# cod_opera# POLITA_ASIG
M(1) cod_polita#
M(1) M(1)
mentionata_in
studiaza

M(0)
M(0)
SURSA_BIBLIO
cod_sursa# SPECIALIST
tip
cod_specialist#

ARTICOL
figureaza_in

CARTE M(0)

EXPOZITIE M(1) organizata_de M(1) ORGANIZATOR


M(1)
cod_expo# cod_organizator#
editata_de

M(1)

AUTOR

cod_autor
#

Figura 2.1. Diagrama E/R a modelului de gestiune a operelor de


artă dintr-un muzeu

36
Asupra modelului considerat sunt definite anumite restricŃii.
Conform acestora, o operă de artă poate:
• avea fie un singur autor, fie autor necunoscut;
• avea mai multe sisteme de securitate instalate;
• fi asigurată la mai multe firme;
• fi menŃionată în aceeaşi sursă bibliografică, la pagini diferite.

InstrucŃiunea CREATE TABLE

CREATE TABLE este una din instrucŃiunile fundamentale din


SQL. Modelul relaŃional cere ca toate datele stocate să fie ancorate într-
un tabel, aşa că posibilitatea de a stoca orice într-o bază de date începe
întotdeauna cu crearea unui tabel.
Crearea unui tabel constă din generarea structurii sale, adică
atribuirea unui nume tabelului şi definirea caracteristicelor sale (se
definesc coloanele, se definesc constrângerile de integritate, se specifică
parametrii de stocare etc.).
În Oracle9i tabelele pot fi create în orice moment, chiar şi în
timpul utilizării bazei. Structura unui tabel poate fi modificată online. Nu
este necesar să se specifice dimensiunea acestuia. Totuşi, din
considerente administrative, este important să se cunoască estimativ cât
spaŃiu va utiliza tabelul.

Sintaxa de bază pentru instrucŃiunea CREATE TABLE este:

CREATE TABLE nume_tabel


(<definiŃie_coloană>
[,<definiŃie_coloană> ...])
[,<restricŃie—tabel>... ];

Definirea coloanelor în SQL DDL

Sintaxa de bază folosită pentru definirea coloanelor unui tabel este:


<definiŃie_coloană>
nume coloană tip_de_date
[DEFAULT expresie]
[NULL | NOT NULL]

37
[<restricŃie_coloană>]

Componentele din definiŃia unei coloane sunt:


Numele coloanei - Numele coloanei trebuie să fie unic în cadrul
tabelului.
Tipul de date - Tipul de date trebuie să fie un tip de date valid
pentru implementarea SGBD
Restrictiile coloanei care sunt prezentate în continuare

Structura unui tabel poate fi creată în următoarele patru moduri:


• fără a indica cheile;
• indicând cheile la nivel de coloană;
• indicând cheile la nivel de tabel;
• prin copiere din alt tabel.

Exemplu : Gestiunea activităŃilor de împrumut dintr-o bibliotecă

M(1) M(0)
CITITOR
CARTE
imprumuta codec#
codel# nume
titlu dep
autor
pret
nrex
coded M(0) 1
DOMENIU
apartine coded#
intdom

1. Crearea structurii unui tabel fără a indica cheile:


CREATE TABLE carte
(codel CHAR(5),
titlu VARCHAR2(30),
autor VARCHAR2(30),
pret NUMBER(8,2),
nrex NUMBER(3),
coded CHAR(5));
2. Crearea structurii unui tabel indicând cheile la nivel coloană:

38
CREATE TABLE carte
(codel CHAR(5) PRIMARY KEY,
titlu VARCHAR2(30),
autor VARCHAR2(30),
pret NUMBER(8,2),
nrex NUMBER(3),
coded CHAR(5) NOT NULL
REFERENCES domeniu(coded));
Constrângerea de cheie primară sau externă ce presupune?
CREATE TABLE carte
(codel CHAR(5) PRIMARY KEY,
titlu VARCHAR2(30),
autor VARCHAR2(30),
pret NUMBER(8,2),
nrex NUMBER(3),
coded CHAR(5) NOT NULL
REFERENCES domeniu(coded)
ON DELETE CASCADE);
CREATE TABLE domeniu
(coded CHAR(5) PRIMARY KEY,
den_dom VARCHAR2(30));

CREATE TABLE cititor


(codec CHAR(5) PRIMARY KEY,
den_cititor VARCHAR2(30));

OpŃiunea ON DELETE CASCADE specifică că suprimarea oricărui


domeniu de carte din tabelul domeniu este autorizată şi implică
suprimarea automată a tuturor cărŃilor din domeniul respectiv care se
găsesc în tabelul carte.
3. Crearea structurii unui tabel indicând cheile la nivel de tabel:
CREATE TABLE carte
(codel CHAR(5),
titlu VARCHAR2(30),
autor VARCHAR2(30),
pret NUMBER(8,2),
nrex NUMBER(3),
coded CHAR(5) NOT NULL,
PRIMARY KEY (codel),
FOREIGN KEY (coded)

39
REFERENCES domeniu (coded));

Dacă cheia primară are mai mult de o coloană atunci cheile trebuie
indicate la nivel de tabel.
CREATE TABLE imprumuta
(codel CHAR(5),
codec CHAR(5),
dataim DATE DEFAULT SYSDATE,
datares DATE,
dataef DATE,
PRIMARY KEY (codel, codec, dataim),
FOREIGN KEY (codel)
REFERENCES carte(codel),
FOREIGN KEY (codec)
REFERENCES cititor(codec));

INSERT INTO domeniu


VALUES(’I’, ’Informatica’);

INSERT INTO carte


VALUES(’bnat1’, ’Baza_de_Date’, ’Popescu_Ioana’, 300.50, 100,’I’);

4. Crearea structurii unui tabel prin copiere din alt tabel:


CREATE TABLE carte_info
AS SELECT codel, titlu, autor
FROM carte
WHERE coded = ’I’;

40
Constrângeri

Constrângerea este un mecanism care asigură că valorile unei


coloane sau a unei mulŃimi de coloane satisfac o condiŃie declarată. Unei
constrâgeri i se poate da un nume unic. Dacă nu se specifică un nume
explicit atunci sistemul automat îi atribuie un nume de forma SYS_Cn,
unde n reprezintă numărul constrângerii. Constrângerile pot fi şterse, pot
fi adăugate, pot fi activate sau dezactivate, dar nu pot fi modificate.

RestricŃiile coloanelor

RestricŃiile unei coloane limitează într-un mod oarecare valorile ce


pot fi stocate într-o coloană a unui tabel. RestricŃiile coloanelor pot avea
oricare dintre următoarele forme:

Exemplu, crearea tabelului CONT_CLIENT, din baza de date a


magazinului de produse video.

CREATE TABLE CONT_CLIENT


(
ID_CONT_CLIENT INTEGER NOT NULL,
STARE_CONT_CLIENT CHAR(1) DEFAULT ‘N’ NOT NULL
CHECK (STARE_CONT_CLIENT IN (‘Y’, ‘N’)),
DATA_INSCRIERE DATE NOT NULL,
DATA_INCHEIERE DATE NULL,
SUMA_DEPOZIT_CLIENT NUMERIC(5,2) NULL,
IND_CREDIT_CARD CHAR(1) NOT NULL
CHECK (IND_CREDIT_CARD IN (‘Y’, ‘N’)),
INDIC_PERMIS_INCHIRIERE_COPIL CHAR(1) NOT NULL
CHECK(INDIC_PERMIS_INCHIRIERE_COPIL IN(‘Y’,‘N’)),
PRIMARY KEY (ID_CONT_CLIENT)
);

Descriere tabel:
ID_CONT_CLIENT - cheie primara
STARE_CONT_CLIENT de tip DA/NU, care indica daca un cont este sau nu
blocat.(inchirierile nu sunt permise pt conturile blocate)
DATA_INSCRIERE - data la care s-a deschis contul in magazin
DATA_INCHEIERE - daca contul a fost inchis contine data; daca contul e activ
contine NULL

41
SUMA_DEPOZIT_CLIENT – pt clientii care nu au carte de credit, suma lasata ca
depozit in magazin
IND_CREDIT_CARD - de tip DA/NU, care indica daca un client a lasat inf despre
carte de credit, pt a garanta platile asociate contului.
INDIC_PERMIS_INCHIRIERE_COPIL - de tip DA/NU, care indica daca
uncopil<18 ani are voie sa inchirieze filme folosind acest cont

• Clauza DEFAULT - O expresie care este aplicată coloanei atunci


când în tabel este inserat un nou rând, care nu conŃine o valoare
explicită pentru coloana respectivă. Expresia poate fi orice expresie
validă. Sintaxa SQL cu o clauză DEFAULT este:
[DEFAULT expresie]
Exemplu:
STARE_CONT_CLIENT CHAR(1) DEFAULT 'N' NOT NULL
(la creare are val N , adica contul nu e blocat)

• RestricŃia NULL | NOT NULL - Specificarea cuvântului cheie


NULL permite stocarca valorilor nule într-o coloană, în timp ce NOT
NULL nu permite stocarca valorilor nule în coloana respectivă. O
restricŃie NOT NULL poate fi scrisă şi sub forma unei restricŃii
CHECK cu condiŃia IS NOT NULL.
Sintaxa SQL şi câteva exemple:
NULL | NOT NULL
Exemple:
DATA_INSCRIERE DATE NOT NULL
DATA_INCHEIERE DATE NULL

• RestricŃia CHECK - O restricŃie de verificare (check) poate fl


folosită pentru impunerea unei reguli care poate fi aplicată unei
singure coloane a unui tabel. CondiŃia inclusă în restricŃie trebuie să
fie îndeplinită ori de câte ori datele din coloana respectivă a
tabelului sunt modificate – în caz contrar, sistemul SGBD va
respinge modificarea şi va afişa un mesaj de eroare.
Sintaxa restricŃiei CHECK şi un exemplu:
[CONSTRAINT nume restricŃie] CHECK (condiŃie)

Exemplu:
IND_CREDIT_CARD CHAR(1) NOT NULL,
CHECK (CREDIT_CARD_INDIC IN (‘Y’, ‘N’))

Clauză NOT NULL poate fi rescrisă şi sub forma unei restricŃii


CHECK:
ID_CONT_CLIENT INTEGER

42
CONSTRAINT CK_CUST _ACCT _ID
CHECK (ID_CONT IS NOT NULL)

• RestricŃia UNIQUE - O restricŃie UNIQUE impusă asupra unei


coloane garantează unicitatea valorilor din coloana respectivă a
tabelului. Sintaxa:
[CONSTRAINT nume_restricŃie] UNIQUE
Exemplu:
ID_CONT_CLIENT INTEGER UNIQUE

• RestricŃia PRIMARY KEY - O restricŃie de cheie primară


(PRIMARY KEY) impusă asupra unei coloane declară coloana
respectivă ca fiind cheia primară a tabelului, ceea ce înseamnă că în
coloana respectivă nu pot exista valori nule, iar valorile trebuie să fie
unice în cadrul tabelului.
Sintaxa :
(CONSTRAINT nume_restricŃie] PRIMARY KEY
Exemplu:
ID_CONT_CLIENT INTEGER PRIMARY KEY

• RestricŃia referentială (FOREIGN KEY) - O restricŃie


referenŃială impusă asupra unei coloane (numită şi restricŃie de cheie
externă) defineşte relaŃia dintre o cheie externă şi o cheie primară.
Sintaxa:
[CONSTRAINT nume_restricŃie]
REFERENCES nume_tabel(nume_coloană)
[ON DELETE CASCADE | ON DELETE SET NULL]
Exemplu:
MPAA_CODE_RATING din tabelul FILME este cheie externă
pentru tabelul MPPA_RATING, care are câmpurile:
MPAA_CODE_RATING şi MPAA__RATING _DESCRIERE

MPAA_COD_RATING CHAR (5) NOT NULL


REFERENCES MPPA_RATING(MPAA_CODE_RATING)

Clauza opŃională ON DELETE spune sistemului SGBD ce să facă


atunci când este şters rândul referit din tabelul părinte cu opŃiunea de
a şterge toate rândurile care conŃin cheia externă (CASCADE) sau de a
insera valori nule pentru toate cheile externe (SET NULL).

43
RestricŃiile tabelelor

RestricŃia unei coloane poate fi rescrisă şi ca restricŃie a întregului


tabel, astfel încât clauza care defineşte restricŃia să apară în instrucŃiunea
CREATE TABLE după definiŃiile tuturor coloanelor, nu după definiŃia
unei coloane. Principalul avantaj al restricŃiilor la nivelul tabelului este că
pot referi mai multe coloane.
• RestricŃia CHECK
[CONSTRAINT nume_restricŃie] CHECK (condiŃie)
RestricŃia de mai jos împiedică stocarea unei valori negative în
coloana SUMA_DEPOZITE_CLIENT . Operatorul OR permite stocarea
valorilor nule , deoarece o valoare nulA nu este mai mare sau egală cu
zero.

Exemplu:

CONSTRAINT CK_SUMA_DEPOZITE_CLIENT
CHECK (SUMA_DEPOZITE_CLIENT >= 0 OR
SUMA_DEPOZITE_CLIENT IS NULL)

• RestricŃia UNIQUE

[CONSTRAINT nume_restricŃie) UNIQUE (nume_coloană


[,nume coloană...])
Conform acestei restricŃii , combinaŃia de coloane
ID_CONT_CLIENT şi DATA_INSCRIERE trebuie să fie unică
în rândurile din tabel.
Exemplu:
CONSTRAINT UK_DATA_INSCR_CONT_CL
UNIQUE (ID_CONT_CLIENT, DATA_INSCRIERE )

• RestricŃia PRIMARY KEY

[CONSTRAINT nume_restricŃie]
PRIMARY KEY (nume_coloană [,nume_coloană...])
RestricŃia de mai jos este chiar definiŃia cheii primare din tabelul
CONT_CLIENT [
Exemplu:
CONSTRAINT PK_CONT_CLIENT
PRIMARY KEY (ID_CONT_CLIENT)

• RestricŃia referenŃială (FOREIGN KEY)

44
Spre deosebire de forma pentru restricŃia referenŃială a coloanei,
aceasta poate referi mai multe coloane.
[CONSTRAINT nume_restricŃie]
FOREIGN KEY (nume_coloană [,nume coloană...])
REFERENCES nume_tabel (nume_coloană [,nume_coloană...
[ON DELETE CASCADE |ON DELETE SET NULL]

Exemple de constrîngeri la nivel de coloană şi tabel pentru


gestiunea cărților dintr-o bibliotecă.

Exemple:
1. Să se definească o constrângere la nivel de coloană prin care să
se specifice cheia primară şi cheia externă.
CREATE TABLE carte
(codel CHAR(5)
CONSTRAINT cp_carte PRIMARY KEY,
Titlu VARCHAR2(30),
autor VARCHAR2(30),
pret NUMBER(8,2),
nrex NUMBER(3),
coded CHAR(5)
CONSTRAINT nn_coded NOT NULL
CONSTRAINT ce_coded
REFERENCES domeniu(coded));

2. Să se definească o constrângere la nivel de tabel prin care să se


specifice cheia primară şi cheia externă.

CREATE TABLE carte


(codel CHAR(5),
titlu VARCHAR2(30),
autor VARCHAR2(30),
pret NUMBER(8,2),
nrex NUMBER(3),
coded CHAR(5) NOT NULL,
CONSTRAINT cp_carte PRIMARY KEY (codel),
CONSTRAINT ce_coded FOREIGN KEY (coded)
REFERENCES domeniu(coded));

45
ObservaŃii:
• Liniile ce nu respectă constângerea sunt depuse automat într-un
tabel special.
• Constrângerile previn ştergerea unui tabel dacă există
dependenŃe.
• Constrângerile pot fi create o dată cu tabelul sau după ce acesta
a fost creat.
• Constrângerile pot fi activate sau dezactivate în funcŃie de
necesităŃi.

Constrângeri declarative pot fi: constrângeri de domeniu,


constrângerea de integritate a entităŃii, constrângerea de integritate
referenŃială.

Constrângerile de domeniu definesc valori luate de un atribut


(DEFAULT, CHECK, UNIQUE, NOT NULL).
• constrângerea (coloană) DEFAULT ;
• constrângerea (coloană sau tabel) CHECK ; constrângerea CHECK la
nivel de tabel poate compara coloane între ele, poate face referinŃă la
una sau mai multe coloane, dar nu poate conŃine subcereri.
Constrângerea la nivel de coloană nu poate referi alte coloane ale
aceluiaşi tabel.
CREATE TABLE carte
(codel CHAR(5),…
nrex NUMBER(3),
pret NUMBER(8,2)
CONSTRAINT alfa
CHECK (pret < nrex),…);
La execuŃia acestei comenzi apare mesajul: ORA – 02438: Column
check constraint cannot reference other columns.
Dacă după NUMBER(8,2) se adaugă o virgulă, atunci
constrângerea va fi la nivel de tabel, iar în aceste caz este permisă
referirea altei coloane.
• constrângerea (coloană sau tabel) UNIQUE ;
• constrângerea declarativă NOT NULL poate fi doar la nivel coloană.
Constrângerea de integritate a entităŃii precizează cheia primară
a unui tabel. Când se creează cheia primară se generează automat un
index unic. Valorile cheii primare sunt distincte şi diferite de valoarea
null.

46
Constrângerea de integritate referenŃială asigură coerenŃa între
cheile primare şi cheile externe corespunzătoare. Când este definită o
cheie externă sistemul Oracle verifică:
• dacă a fost definită o cheie primară pentru tabelul referit de
cheia externă;
• dacă numărul coloanelor ce compun cheia externă corespunde
numărului de coloane a cheii primare;
• dacă tipul şi lungimea fiecărei coloane a cheii externe
corespunde cu tipul şi lungimea fiecărei coloane a cheii
primare.

Această constrângere poate fi definită la nivel de coloană sau tabel


şi asigură coerenŃa între cheile primare şi cheile externe corespunzătoare.
Constrângerea FOREIGN KEY desemnează o coloană sau o combinaŃie
de coloane drept cheie externă şi stabileşte relaŃia cu o cheie primară sau
o cheie unică din acelaşi tabel sau din altul.
O cheie externă compusă poate fi definită doar la nivel de tabel.
Cheia externă se defineşte în tabelul „copil“, iar tabelul care
conŃine coloana referită reprezintă tabelul „părinte“. Valoarea unei chei
externe trebuie să fie egală cu o valoare existentă în tabelul „părinte“ sau
să fie null. Cheile externe se bazează pe valorile datelor şi sunt pointer-i
logici.
Cheile externe se definesc folosind următoarele cuvinte cheie:
• FOREIGN KEY este utilizat într-o constrângere la nivel de
tabel pentru a defini coloana din tabelul „copil“;
• REFERENCES identifică tabelul „părinte“ şi coloana
corespunzătoare din acest tabel;
• ON DELETE CASCADE determină ca, odată cu ştergerea unei
linii din tabelul „părinte“, să fie şterse şi liniile dependente din
tabelul „copil“;
• ON DELETE SET NULL determină modificarea automată a
valorilor cheii externe la valoarea null, atunci când se şterge
valoarea „părinte“.
DefiniŃiile şi numele constrângerilor definite se pot fi consulta prin
interogarea vizualizărilor USER_CONSTRAINTS şi ALL_CONSTRAINTS
din dicŃionarul datelor (Desc USER_CONSTRAINTS;)

Modificarea structurii unui tabel

47
Comanda care realizează modificarea structurii tabelului (la nivel de
coloană sau la nivel de tabel), dar nu modificarea conŃinutului acestuia,
este ALTER TABLE.

InstrucŃiunea ALTER TABLE

InstrucŃiunea ALTER TABLE ajută să se facă modificări asupra


tabelelor create. Utilizarea instrucŃiunii ALTER TABLE este un alt
domeniu în care au un rol important stilul şi preferinŃele personale.
MulŃi administratori de baze de date preferă să folosească instrucŃuni
CREATE TABLE cât mai simple, evitând să definească
restricŃii în instrucŃiunile CREATE TABLE.
Aceştia adaugă după instrucŃiunea CREATE TABLE
instrucŃiuni ALTER TABLE prin care specifică toate restricŃiile necesare
(cheie primară, cheie externă, unicitate, verificare). Dezavantajul
acestei metode este acela că necesită scrierea unei cantităŃi mai mari
de cod. Pe de altă parte, instrucŃiunea CREATE TABLE este mult
mai uşor de înŃeles fără restricŃii, iar scrierea separată a restricŃiilor
simplifică refolosirea instrucŃiunilor.
Comanda ALTER TABLE permite:
• adăugarea (ADD) de coloane, chei (primare sau externe),
constrângeri într-un tabel existent;
• modificarea (MODIFY) coloanelor unui tabel;
• specificarea unei valori implicite pentru o coloană existentă;
• activarea şi dezactivarea (ENABLE, DISABLE) unor
constrângeri;
• suprimarea unei coloane;
• suprimarea (DROP) cheii primare, a cheii externe sau a unor
constrângeri.
Comanda ALTER TABLE are următoarea sintaxă simplificată:

ALTER TABLE [<nume_schema>.] <nume_tabel>


[ADD (<nume_coloana> <tip_date>, <constrângere>) |
MODIFY (<nume_coloana_1>,…, <nume_coloana_n>) |
DROP <clauza_drop>,]
[ENABLE | DISABLE <clause>];

48
• Adăugarea unei coloane la un tabel. Definirea coloanei se face cu
aceeaşi sintaxă ca şi în cazul instrucŃiunii CREATE TABLE. Nu se
poate specifica unde să apară coloana, ea devenind ultima coloană a
tabelului.

ALTER TABLE nume_tabel


ADD ( <definiŃie_co1oană>
[,<definiŃie_co1oană>
Exemplu:
ALTER TABLE CONT_CLIENT
ADD (DATA_CLIENT DATE,
INTRODUSE_DE VARCHAR(50));

ALTER TABLE CITITOR


ADD (ADRESA VARCHAR(50));
ALTER TABLE carte
ADD(rezumat LONG);

• Modificarca definiŃiei unei coloane. Majoritatea SGBD-urilor


nu permit să scădeŃi precizia unei coloane dacă tabelul conŃine
date şi foarte puŃine permit să se schimbe tipul de date al unei
coloane existente. Sunt acceptate creşterea preciziei unei coloane,
adăugarea sau modificarea valorii prestabilite pentru o coloană, şi
trcerea de la NULL la NOT NULL sau invers.

ALTER TABLE nume_tabel


MODIFY [COLUMN] (<definiŃie — coloană>
[,<definiŃie_co1oană> ...]);
Exemplu:
ALTER TABLE CONT_CLIENT
MODIFY (SUMA_DEPOZIT_CLIENT NUMERIC(7,2)
DEFAULT 0 NOT NULL);

49
• Adăugarea unei restricŃii. DefiniŃia restricŃiei este identică cu
definiŃia unei restricŃii care ar putea apărea într-o instrucŃiune
CREATE TABLE.
ALTER TABLE nume_tabel
ADD CONSTRAINT <definiŃie_restricŃie>;
Exemplu:
ALTER TABLE CONT_CLIENT
ADD CONSTRAINT CK_SUMA_DEPOZIT_CLIENT
CHECK (SUMA_DEPOZIT_CLIENT >= 0
OR SUMA_DEPOZIT_CLIENT IS NULL);

Dacă pun o valoare negativă la suma, atunci apare eroare .

CREATE TABLE carte


(CODEL char(5),
…);
ALTER TABLE carte
ADD CONSTRAINT cheie_prim PRIMARY KEY (codel);

• Ştergerea cheii primare a unui tabel.


Dacă cheia primară este referită de restricŃii referenŃiale, trebuie
mai întâi şterse restricŃiile respective.
ALTER TABLE nume_tabel DROP PRIMARY KEY;
Dacă există o CE care referă o CP şi dacă se încearcă ştergerea cheii
primare, această ştergere nu se poate realiza (tabelele sunt legate
prin declaraŃia de cheie externă). Ştergerea este totuşi permisă dacă

50
în comanda ALTER apare opŃiunea CASCADE, care determină şi
ştergerea cheilor externe ce referă cheia primară.
ALTER TABLE domeniu
DROP PRIMARY KEY CASCADE;
• Ştergerea cheii externe se face ca si pentru ştergerea cheii
primare
ALTER TABLE carte
ADD CONSTRAINT beta
FOREIGN KEY (coded) REFERENCES domeniu;

• Schimbarea cheii primare. Este destul de complicat procesul


schimbării cheii primare fără a afecta modul de proiectare a bazei
de date. Schimbarea se face în două etape: se şterge cheia
primară şi apoi se recreează.
ALTER TABLE carte
ADD (PRIMARY KEY(codel));

ALTER TABLE carte


DROP PRIMARY KEY;

ALTER TABLE carte


ADD PRIMARY KEY(titlu, autor));

• Redenumirea unei coloane.

Dintre bazele de date care acceptă această sintaxă este numai


Oracle, începând cu versiunea 8.0
ALTER TABLE nume_tabel
RENAME COLUMN nume_vechi_coloană TO nume
_nou_coloană;
ALTER TABLE timp
RENAME COLUMN durata_1 TO dur_1;

ALTER TABLE timp


RENAME COLUMN durata_2 TO dur_2;

51
• Pentru a activa (ENABLE) sau dezactiva (DISABLE)
constrângeri:
ALTER TABLE nume_tabel
ENABLE nume_constrangere;

ALTER TABLE carte


DROP CONSTRAINT beta;

ALTER TABLE cititor


ADD CONSTRAINT cp_cititor
PRIMARY KEY (codec)
DISABLE;
ALTER TABLE cititor
ENABLE CONSTRAINT cp_cititor;

Stergerea unei coloane se face ca şi a unei constringeri;

ALTER TABLE nume_tabel


DROP nume_coloana;

ALTER TABLE CONT_CLIENT


DROP (DATA_CLIENT ,INTRODUSE_DE );

ObservaŃii
• Nu se poate specifica poziŃia unei coloane noi în structura tabelului. O
coloană nouă devine automat ultima în cadrul structurii tabelului.

52
• Modificarea unei coloane presupune schimbarea tipului de date, a
dimensiunii sau a valorii implicite a acesteia. O schimbare a valorii
implicite afectează numai inserările care succed modificării.
• Dimensiunea unei coloane numerice sau de tip caracter poate fi
mărită, dar nu poate fi micşorată decât dacă acea coloană conŃine
numai valori null sau dacă tabelul nu conŃine nici o linie.
• Tipul de date al unei coloane poate fi modificat doar dacă valorile
coloanei respective sunt null.
• Alte opŃiuni ale comenzii ALTER TABLE, care au apărut începând cu
versiunea Oracle8i, sunt SET UNUSED şi DROP UNUSED
COLUMNS:
ALTER TABLE nume_tabel
ET UNUSED [ ( ] nume_coloană [ ) ];
ALTER TABLE nume_tabel
DROP UNUSED COLUMNS;
OpŃiunea SET UNUSED permite marcarea uneia sau mai multor
coloane ca fiind nefolosite, cu scopul de a fi şterse atunci când
necesităŃile sistemului impun acest lucru. Coloanele nefolosite sunt tratate
ca şi cum ar fi fost suprimate, deşi datele acestora rămân în liniile
tabelului. După ce o coloană a fost marcată UNUSED, utilizatorul nu mai
are acces la aceasta prin intermediul cererilor. În plus, numele şi tipurile
de date ale coloanelor nefolosite nu vor fi afişate cu comanda DESCRIBE
din SQL*Plus. Utilizatorul poate să adauge tabelului o nouă coloană
având acelaşi nume cu cel al unei coloane nefolosite.
DROP UNUSED COLUMNS şterge din tabel toate coloanele
marcate ca fiind nefolosite. Acest lucru se poate utiliza pentru eliberarea
spaŃiului de pe disc corespunzător coloanelor nefolosite din tabel. Dacă
tabelul nu conŃine nici o coloană nefolosită, instrucŃiunea nu întoarce o
eroare şi nu are nici un efect.
Atunci când se elimină o coloană dintr-un tabel folosind opŃiunea
DROP a comenzii ALTER TABLE, vor fi suprimate şi coloanele din tabel
care sunt marcate cu opŃiunea SET UNUSED.

Suprimarea unui tabel


Pentru ştergerea unui tabel este utilizată comanda DROP TABLE:
DROP TABLE [nume_schema.]nume_tabel
[CASCADE CONSTRAINTS];
Clauza CASCADE CONSTRAINTS permite suprimarea tuturor
constrângerilor de integritate referenŃială corespunzătoare cheilor primare
şi unice din tabelul supus ştergerii. Dacă se omite această clauză şi există

53
constrângeri de integritate referenŃială, sistemul returnează o eroare şi nu
suprimă tabelul.
Suprimarea unui tabel presupune:
0suprimarea definiŃiei sale în dicŃionarul datelor;
0suprimarea indecşilor asociaŃi;
0suprimarea privilegiilor conferite în legătură cu tabelul;
0recuperarea spaŃiului ocupat de tabel;
0permanentizarea tranzactiilor in asteptare;
0invalidarea (dar nu suprimarea) funcŃiilor, procedurilor,
vizualizărilor, secventelor, sinonimelor referitoare la tabel.
Odată executată, instrucŃiunea DROP TABLE este ireversibilă. Ca
şi în cazul celorlalte instrucŃiuni ale limbajului de definire a datelor,
această comandă nu poate fi anulată (ROLLBACK).

InstrucŃiunea DROP

InstrucŃiunea DROP este cea mai simplă dintre instrucŃiunile DDL.


Sintaxa de bază este:
Pentru ştergerea unui tabel este utilizată comanda DROP TABLE:
DROP TABLE [nume_schema.]nume_tabel
[CASCADE CONSTRAINTS];
Clauza CASCADE CONSTRAINTS permite suprimarea tuturor
constrângerilor de integritate referenŃială corespunzătoare cheilor primare
şi unice din tabelul supus ştergerii. Dacă se omite această clauză şi există
constrângeri de integritate referenŃială, sistemul returnează o eroare şi nu
suprimă tabelul.
Suprimarea unui tabel presupune:
0suprimarea definiŃiei sale în dicŃionarul datelor;
0suprimarea indecşilor asociaŃi;
0suprimarea privilegiilor conferite în legătură cu tabelul;
0recuperarea spaŃiului ocupat de tabel;
0permanentizarea tranzactiilor in asteptare;
0invalidarea (dar nu suprimarea) funcŃiilor, procedurilor,
vizualizărilor, secventelor, sinonimelor referitoare la tabel.
Odată executată, instrucŃiunea DROP TABLE este ireversibilă. Ca
şi în cazul celorlalte instrucŃiuni ale limbajului de definire a datelor,
această comandă nu poate fi anulată (ROLLBACK).

54
Tipul de obiect specifică tipul obiectului care urmează să fie şters, cum ar
fi INDEX, TABLE sau VIEW.
OpŃiunile de ştergere sunt specifice fiecărui SGBD. Sintaxa este diferită
de la un producător la altul — PostgreSQL şi MySQL folosesc în acest
scop cuvântul cheie CASCADE, în timp ce în Oracle trebuie să se
folosească CASCADE CONSTRAINTS.
Exemplu:
DROP TABLE COD_CLIENT;
DROP TABLE COD_CLIENT CASCADE CONSTRAINTS; (Oracle)
DROP INDEX IX_TITLU_FILM;

Pentru ştergerea întregului conŃinut al unui tabel şi eliberarea


spaŃiului de memorie ocupat de acesta, sistemul Oracle oferă
instrucŃiunea:

TRUNCATE TABLE nume_tabel;

Fiind o instrucŃiune DDL, aceasta nu poate fi anulată ulterior


(printr-o operaŃie ROLLBACK). Ea reprezintă o alternativă a comenzii
DELETE din limbajul de prelucrare a datelor(DML). De remarcat că
instrucŃiunea DELETE nu eliberează spaŃiul de memorie. Comanda
TRUNCATE este mai rapidă deoarece nu generează informaŃie
ROLLBACK şi nu activează declanşatorii asociaŃi operaŃiei de ştergere.
Dacă tabelul este „părintele“ unei constrângeri de integritate referenŃială,
el nu poate fi trunchiat. Pentru a putea fi aplicată instrucŃiunea
TRUNCATE, constrângerea trebuie să fie mai întâi dezactivată.
In DDL, informaŃiile despre tabele se găsesc în vizualizarea
USER_TABLES.
Dintre cele mai importante coloane ale acesteia, se remarca le
obtinem cu instructiunea:

55
DESCRIBE USER_TABLES;

TABLE_NAME Numele tabelului


TABLESPACE_NAME SpaŃiul tabel în care se află tabelul
CLUSTER_NAME Numele cluster-ului din care face parte tabelul
PCT_FREE Procentul de spaŃiu păstrat liber în interiorul fiecărui
bloc
PCT_USED Procentul de spaŃiu ce poate fi utilizat în fiecare bloc
INI_TRANS Numărul iniŃial de tranzacŃii concurente în interiorul
unui bloc
NITIAL_EXTENT Dimensiunea spaŃiului alocat pentru prima extensie
NEXT_EXTENT Dimensiunea spaŃiului alocat pentru următoarea
extensie
MIN_EXTENTS Numărul minim de extensii ce se alocă la crearea
unui tabel
MAX_EXTENTS Numărul maxim de extensii ce se alocă la crearea
unui tabel
PCT_INCREASE Procentul cu care creşte dimensiunea unei extensii
BACKED_UP Y sau N, după cum tabelului i-a fost făcută o copie de
siguranŃă de la ultima modificare
NUM_ROWS Numărul de înregistrări din tabel
BLOCKS Numărul de blocuri utilizate de tabel
EMPTY_BLOCKS Numărul de blocuri ce nu conŃin date
AVG_SPACE SpaŃiul mediu liber din tabel
AVG_ROW_LEN Lungimea medie, în octeŃi, a unei linii
TABLE_LOCK ENABLED (activat) sau DISABLED (dezactivat):
este activată sau nu blocarea tabelului
PARTITIONED YES sau NO, indică dacă tabelul este partiŃionat (sau
nu)
TEMPORARY Y sau N, indică dacă tabelul este temporar (sau nu)
NESTED YES sau NO, indică dacă tabelul este imbricat (sau
nu)
Exemplu:
SELECT TABLE_NAME, NUM_ROWS, NESTED
FROM USER_TABLES;

Exemplu:
SELECT 'DROP TABLE ' || OBJECT_NAME || ';'
FROM USER_OBJECTS
WHERE OBJECT_TYPE = 'TABLE';

56
InstrucŃiunea CREATE INDEX

Indexurile sunt instrumente puternice, deoarece permit sistemului


să găsescă datele mult mai repede, tot aşa cum indexul unei cărŃi ne
permite să găsim mai rapid ceea ce ne interesează. De asemenea,
indexurile pe coloanele cheilor externe cresc mult peformanŃele la unirea
tabelelor. Sistemul SGBD întreŃine automat indexul, dar activitatea de
întreŃinere consumă din resursele calculatorului.
Pentru îmbunătăŃirea performanŃelor unor interogări, trebuie luată
în considerare crearea unui index. De asemenea, un index poate fi utilizat
pentru a impune unicitatea valorilor unei coloane sau ale unei colecŃii de
coloane.
Un index este un obiect al schemei, care conŃine câte o intrare
pentru fiecare valoare ce apare în coloanele indexate ale unui tabel sau
grupare şi determină accesul rapid şi direct la înregistrări, prin utilizarea
unui pointer.
Indecşii sunt utilizaŃi şi întreŃinuŃi automat de către server-ul
Oracle. Odată creat, un index nu necesită o acŃiune directă din partea
utilizatorului.
Un index poate fi creat asupra:
• uneia sau mai multor coloane ale unui tabel nepartiŃionat,
partiŃionat, organizat pe bază de index sau ale unui cluster;
• unuia sau mai multor atribute de tip scalar ale unui obiect dintr-

57
un tabel sau cluster;
• unui tabel imbricat.

Indecşii sunt independenŃi din punct de vedere logic şi fizic de


tabelul pe care îl indexează. Aceasta înseamnă că indecşii pot fi creaŃi sau
suprimaŃi la orice moment fără a avea vreun efect asupra tabelelor de
bază sau asupra altor indecşi.

Un index este un obiect al schemei unei baze de date care:


• creşte viteza de execuŃie a cererilor;
• garantează că o coloană conŃine valori unice.

Un index trebuie să aibă cel puŃin o coloană, dar, nu există o limită


superioară a numărului de coloane.

Server-ul Oracle utilizează identificatorul ROWID pentru regăsirea


liniilor în structura fizică a bazei de date. Indexul, din punct de vedere
logic, este compus dintr-o valoare cheie şi din identificatorul adresă
ROWID.

select rowid, cod_artist,nume,prenume from artist;

ROWID COD_ARTIST NUME PRENUME


------------------ ---------- ------------------------------ ------------
AAAHkEAAJAAAAbPAAA 1 Grigorescu Dan
AAAHkEAAJAAAAbPAAB 2 ene ana

select * from artist where rowid='AAAHkEAAJAAAAbPAAA';

COD_ARTIST NUME PRENUME


-------------------- ----------------------- ------------------------
1 Grigorescu Dan

Cheia indexului poate fi coloana unui tabel sau concatenarea mai


multor coloane (numărul maxim de coloane care pot defini cheia
indexului este 32). Coloanele care apar în cheia indexului trebuie
declarate NOT NULL în tabel.
Indecşii sunt utilizaŃi şi întreŃinuŃi automat de către server-ul
Oracle. Odată creat indexul, el nu necesită o acŃiune directă din partea
utilizatorului.
Indecşii pot fi creaŃi în două moduri:
• automat, de server-ul Oracle (PRIMARY KEY, UNIQUE);

58
• manual, de către utilizator (CREATE INDEX).
Server-ul Oracle creează automat un index unic atunci când se
defineşte o constrângere PRIMARY KEY sau UNIQUE asupra unei
coloane sau unui grup de coloane. Numele indexului va fi acelaşi cu
numele constrângerii.
Indecşii, fiind obiecte ale schemei bazei, beneficiază de procesul de
definire a unui obiect.

Crearea unui index (care nu este obligatoriu unic) pe una sau mai
multe coloane ale unui tabel se face prin comanda:

CREATE[{UNIQUE | BITMAP} ] [UNIQUE] INDEX <nume_index>


ON [<nume_schema>.] <nume_tabel>
(<nume_col> [ASC | DESC], <nume_col> [ASC | DESC], …);

Cuvântul cheie opŃional UNIQUE defineşte indexul ca unic,


însemnând că nu pot exista două rânduri din tabel cu exact acceaşi
combinaŃie de valori în coloanele specificate. Această clauză nu poate
fi specificată alături de clauza BITMAP sau pentru un index
domeniu.
Clauza BITMAP determină crearea indexului cu o hartă de biŃi
(bitmap) pentru fiecare cheie distinctă, în loc de a indexa separat fiecare
linie. Fiecare bit din bitmap corespunde unei valori ROWID posibile.
Dacă un bit este setat, înseamnă că linia având valoarea ROWID
corespunzătoare acestuia conŃine valoarea cheii. Reprezentarea internă a
bitmap-urilor este adecvată aplicaŃiilor cu niveluri scăzute ale
tranzacŃiilor concurente (de exemplu, aplicaŃii data warehouse).

Cuvântul cheie opŃional ASC creează indexul în ordine crescătoare,


în timp ce DESC creează indexul în ordine descrescătoare. Dacă nu este
specificată nici una dintre cele două opŃiuni, ordinea prestabilită este
crescătoare.
Când este creat un index, un segment de date este rezervat automat
în spaŃiul tabel. Alocarea de memorie este controlată prin clauzele
INITIAL_EXTENT, PCT_INCREASE, PCT_FREE, NEXT, care pot să
apară în comanda CREATE INDEX.
Exemplu:
1) Să se creeze un index descrescător relativ la coloana adresa din
tabelul cititor.
CREATE INDEX cititor_idx

59
ON cititor (adresa DESC);
CREATE INDEX cit_den
ON cititor (DEN_CITITOR);
2) Să se afişeze informaŃiile referitoare la indexul cititor_idx.
SELECT TABLE_NAME
FROM USER_INDEXES
WHERE INDEX_NAME=’CITITOR_IDX’;
SELECT TABLE_NAME
FROM USER_INDEXES
WHERE INDEX_NAME=’CIT_DEN’;

3) Să se afişeze toate indexurile(numele tabelelor, numele indexului si


daca a fost sau nu generat)
SELECT TABLE_NAME, INDEX_NAME, TABLE_TYPE
FROM USER_INDEXES;
4)Să se creeze un index explicit, referitor la cheia primara a unui tabel.
Pentru a schimba numele unei chei altul decit cel dat de sistem oracle,
Sys_Cn;
CREATE TABLE exem
( cod_id NUMBER(6)
PRIMARY KEY USING INDEX
(CREATE INDEX cod_id_idx ON exem (cod_id)),
nume VARCHAR2(20));

Mai mulŃi indecşi asupra unui tabel nu implică întotdeuna


interogări mai rapide. Fiecare operaŃie LMD care este permanentizată
asupra unui tabel cu indecşi asociaŃi presupune actualizarea indecşilor
respectivi.
Prin urmare, este recomandată crearea de indecşi numai în
anumite situaŃii:
• coloana conŃine o varietate mare de valori;
• coloana conŃine un număr mare de valori null;
• una sau mai multe coloane sunt utilizate frecvent împreună într-
o clauză WHERE sau într-o condiŃie de join;
• tabelul este mare şi este de aşteptat ca majoritatea interogărilor
asupra acestuia să regăsească mai puŃin de 2-4% din linii.

60
Crearea unui index nu este recomandată în următoarele cazuri:
• tabelul este mic;
• coloanele nu sunt utilizate des în cadrul unei condiŃii dintr-o
cerere;
• majoritatea interogărilor regăsesc mai mult de 2-4% din liniile
tabelului;
• tabelul este actualizat frecvent;
• coloanele indexate sunt referite în expresii.
In concluzie, ce tabele sau ce coloane trebuie (sau nu) indexate?
• indexaŃi tabelele pentru care interogările selectează un număr redus
de rânduri (sub 5%);
• indexaŃi tabelele care sunt interogate folosind clauze SQL simple;
• nu indexaŃi tabelele ce conŃin puŃine înregistrări (accesul secvenŃial
este mai simplu);
• nu indexaŃi tabelele care sunt frecvent actualizate, deoarece
ştergerile, inserările şi modificările sunt îngreunate de indecşi;
• indexaŃi coloanele folosite frecvent în clauza WHERE sau în clauza
ORDER BY;
• nu indexaŃi coloanele ce conŃin date asemănătoare (puŃine valori
distincte);

Exemplu:
Pentru a asigura că server-ul Oracle utilizează indexul şi nu
efectuează o căutare asupra întregului tabel, valoarea funcŃiei
corespunzătoare expresiei indexate trebuie să nu fie null în interogările
ulterioare creării indexului. Următoarea instrucŃiune garantează utilizarea
indexului dar, în absenŃa clauzei WHERE, server-ul Oracle ar putea
cerceta întreg tabelul.
SELECT * FROM artist
WHERE UPPER(nume) IS NOT NULL
ORDER BY UPPER(nume);
Exemplu:
Să se creeze tabelul artist, specificându-se indexul asociat cheii
primare.
CREATE TABLE artist(
cod_artist NUMBER
PRIMARY KEY USING INDEX
(CREATE INDEX artist_cod_idx
ON artist(cod_artist)),

61
nume VARCHAR2(30) NOT NULL,
prenume VARCHAR2(30));

INSERT INTO ARTIST


VALUES(1,’Grigorescu’,’Dan’);
INSERT INTO ARTIST
VALUES(2,’ene’,’ana’);
INSERT INTO ARTIST
VALUES(4,’Adam’,’Horia’);

(trebuie creat privilegiu din Security ..query rewrite)


CREATE INDEX up_nume_id
ON artist(UPPER(nume));
Indexul creat prin instrucŃiunea precedentă facilitează prelucrarea
unor interogări precum:
SELECT * FROM artist
WHERE UPPER(nume) = 'ene';

Ştergerea unui index se face prin comanda:


DROP INDEX nume_index [ON [nume_schema.] nume_tabel]
Pentru a suprima indexul trebuie ca acesta să se găsească în schema
personală sau să ai privilegiul de sistem DROP ANY INDEX.

Pentru a reconstrui un index se pot folosi două metode:


• se şterge indexul (DROP INDEX) şi se recreează (CREATE
INDEX);
• se utilizează comanda ALTER INDEX cu opŃiunea REBUILD.
Modificarea parametrilor de stocare a indecşilor (STORAGE),
alocarea (ALLOCATE EXTENT) şi dealocarea (DEALLOCATE
UNUSED) manuală a spaŃiului utilizat de un index se pot realiza cu
ajutorul comenzii ALTER INDEX. Începând cu Oracle9i, este posibilă
modificarea structurii indecşilor prin comanda ALTER INDEX.
Validarea unui index, adică verificarea integrităŃii indexului
specificat pentru un tabel, se face prin comanda:
VALIDATE INDEX nume_index [ON nume_tabel] [WITH LIST]
VALIDATE INDEX artist_cod_idx;

InformaŃii referitoare la indecşi şi la coloanele care îi definesc pot


fi regăsite în vizualizările USER_INDEXES, respectiv

62
USER_IND_COLUMNS din dicŃionarul datelor. Dintre coloanele
tabelului USER_INDEXES se remarcă, dând
Desc USER_INDEXES;
INDEX_NAME Numele indexului
INDEX_TYPE Tipul indexului (NORMAL, LOB, CLUSTER etc.)
TABLE_OWNER Proprietarul tabelului indexat
TABLE_NAME Numele tabelului indexat
TABEL_TYPE Tipul tabelului indexat (TABLE, CLUSTER etc.)
UNIQUENESS Starea de unicitate (UNIQUE, NONUNIQUE)
TABLESPACE_NAME SpaŃiul tabel în care este stocat indexul
INITIAL_EXTENT SpaŃiul alocat pentru prima extensie
NEXT_EXTENT SpaŃiul alocat pentru următoarea extensie
MIN_EXTENTS Numărul minim de extensii alocate
MAX_EXTENTS Numărul maxim de extensii
PCT_INCREASE Procentul cu care cresc extensiile
BLEVEL Nivelul din B-arbore. Acesta arată adâncimea indexului de
la ramuri la frunze
LEAF_BLOCKS Numărul de blocuri frunză din index
DISTINCT_KEYS Numărul de chei distincte în index
STATUS Starea indexului (VALID, INVALID, DIRECT_LOAD)
NUM_ROWS Numărul de linii utilizate. Acesta nu trebuie să includă
valorile NULL din tabelul de bază
PARTITIONED Determină dacă indexul este partiŃionat (YES sau NO)
GENERATED Determină dacă sistemul a generat numele indexului (Y)
sau utilizatorul (N)

SELECT TABLE_NAME, INDEX_NAME, TABLE_TYPE


FROM USER_INDEXES;

63
Pentru a vedea informatiile din USER_IND_COLUMNS, avem
Desc USER_IND_COLUMNS;

Exemplu:
Să se obŃină informaŃii referitoare la indecşii tabelului carte.

64
SELECT a.index_name, a.column_name,
a.column_position poz, b.uniqueness
FROM user_indexes b, user_ind_columns a
WHERE a.index_name = b.index_name
AND a.table_name = ’CITITOR’;

SecvenŃe

Multe aplicaŃii necesită utilizarea de numere unice ca valori ale


cheilor primare. Pentru a obŃine astfel de numere, se pot implementa în
aplicaŃie unităŃi de program corespunzătoare sau se pot utiliza secvenŃe.
De obicei, secvenŃele sunt utilizate pentru crearea de valori ale
cheii primare care trebuie să fie unice pentru fiecare linie. SecvenŃa este
incrementată sau decrementată de către o rutină internă Oracle. Numerele
secvenŃei sunt stocate şi generate independent de tabele. Prin urmare,
aceeaşi secvenŃă poate fi utilizată pentru mai multe tabele.
O secvenŃă este un obiect al bazei de date, creat de utilizator. Acest
obiect poate fi folosit de mai mulŃi utilizatori pentru a genera numere
întregi unice în sistemele multi-utilizator, evitând apariŃia conflictelor şi a
blocării.
O secvenŃă poate fi creată de un utilizator şi poate fi partajată de
mai mulŃi utilizatori.

65
Crearea unei secvenŃe se face cu ajutorul comenzii:

CREATE SEQUENCE [<nume_schema>.]<nume_secventa>


[INCREMENT BY n] [START WITH m]
[{MAXVALUE n | NOMAXVALUE}]
[{MINVALUE n|NOMINVALUE}]
[{CACHE k | NOCACHE}]

OpŃiunea INCREMENT BY specifică diferenŃa dintre valorile


succesive ale secvenŃei. Dacă această opŃiune este omisă, numerele
generate de secvenŃă vor fi incrementate prin valoarea 1.
OpŃiunea START WITH specifică primul număr care va fi generat
de secvenŃă. Dacă această opŃiune este omisă, secvenŃa începe de la
valoarea 1.
OpŃiunile MAXVALUE, MINVALUE precizează valoarea maximă,
respectiv minimă pe care o poate genera secvenŃa. OpŃiunile
NOMAXVALUE, NOMINVALUE sunt implicite. NOMAXVALUE
specifică valoarea maximă de 1027 pentru o secvenŃă crescătoare şi -1
pentru o secvenŃă descrescătoare. NOMINVALUE specifică valoarea
minimă 1 pentru o secvenŃă crescătoare şi -1026 pentru o secvenŃă
descrescătoare.
OpŃiunile CYCLE şi NOCYCLE specifică dacă secvenŃa continuă să
genereze numere după obŃinerea valorii maxime sau minime. NOCYCLE
este opŃiunea implicită. Se recomandă să nu fie utilizată opŃiunea CYCLE
dacă secvenŃa este folosită pentru generarea de chei primare, cu excepŃia
cazului în care există un mecanism care şterge liniile vechi din tabel mai
repede decât ciclează secvenŃa.
CACHE k precizează numărul de valori pe care server-ul Oracle le
prealocă şi le păstrează în memorie. În mod implicit, acest număr de
valori este 20. OpŃiunea CACHE pemite accesul mai rapid la valorile
secvenŃei care sunt păstrate în memorie. Aceste valori sunt generate la
prima referinŃă asupra secvenŃei. Fiecare valoare din secvenŃă se
furnizează din secvenŃa memorată. După utilizarea ultimei valori
prealocate secvenŃei, următoarea solicitare a unei valori determină
încărcarea unui alt set de numere în memorie. Pentru a nu fi prealocate şi
reŃinute în memorie astfel de valori, se utilizează opŃiunea NOCACHE.

O secvenŃă este referită într-o comandă SQL cu ajutorul pseudo-


coloanelor:
• NEXTVAL – referă valoarea următoare a secvenŃei;
• CURRVAL – referă valoarea curentă a secvenŃei.

66
NEXTVAL şi CURRVAL pot fi folosite în:
• clauza VALUES a unei comenzi INSERT;
• clauza SET a unei comenzi UPDATE;
• lista SELECT a unei subcereri dintr-o comanda INSERT;
• lista unei comenzi SELECT.
NEXTVAL şi CURRVAL nu pot fi folosite în:
• subinterogare in SELECT, DELETE sau UPDATE;
• interogarea unei vizualizări;
• comandă SELECT cu operatorul DISTINCT;
• comandă SELECT cu clauza GROUP BY, HAVING sau ORDER
BY;
• clauza WHERE a unei comenzi SELECT;
• condiŃia unei constrângeri CHECK;
• valoarea DEFAULT a unei coloane într-o comandă CREATE
TABLE sau ALTER TABLE;
• comandă SELECT care este combinată cu altă comandă SELECT
printr-un operator mulŃime (UNION, INTERSECT, MINUS).
Din dicŃionarul datelor pot fi obŃinute informaŃii despre secvenŃe
folosind vizualizarea USER_SEQUENCES.

1) Să se creeze o secvenŃă domeniuseq care să fie utilizată pentru a


insera noi domenii în tabelul domeniu şi să se insereze un nou
domeniu.
2) Să se afişeze informaŃiile referitoare la secvenŃa domeniuseq.
CREATE SEQUENCE domeniuseq
START WITH 4
INCREMENT BY 1;

INSERT INTO domeniu


VALUES (domeniuseq.NEXTVAL,’Arta’);

67
SELECT INCREMENT_BY,MAX_VALUE, MIN_VALUE
FROM USER_SEQUENCES
WHERE SEQUENCE_NAME = 'DOMENIUSEQ’;
Modificarea unei secvenŃe se face prin comanda ALTER
SEQUENCE. Sintaxa comenzii este similară instrucŃiunii CREATE
SEQUENCE , dar:
• noua valoare maximă pentru MAXVALUE nu poate fi mai mică
decât valoarea curentă;
• opŃiunea START WITH nu poate fi modificată de comandă.

Exemplu: Să se schimbe pasul secventei de la 1 la 2


ALTER SEQUENCE DOMENIUSEQ
INCREMENT BY 2;

Suprimarea unei secvenŃe se face cu ajutorul comenzii:


DROP SEQUENCE [<nume_schema>.]<nume_secventa>;
După ce a fost ştearsă, secvenŃa nu mai poate fi referită. Pentru a
putea şterge sau modifica secvenŃa trebuie fie să fi proprietarul acesteia,
fie să ai privilegiul de sistem DROP ANY SEQUENCE, respectiv
privilegiul ALTER SEQUENCE.

DROP SEQUENCE domeniuseq;

Sinonime

68
Oracle oferă posibilitatea de a atribui mai multe nume aceluiaşi
obiect. Aceste nume adiŃionale sunt numite sinonime (synonymes). Ele
sunt utile deoarece permit simplificarea formulării cererii şi referirea la
obiecte, fără a fi nevoie să se specifice proprietarii obiectelor sau
localizarea acestora(schema).
Spre deosebire de alias a cărui durată de viaŃă este limitată la
cererea ce conŃine alias-ul, sinonimele sunt salvate în dicŃionarul datelor
şi pot fi reutilizate.
Sistemul Oracle permite crearea de sinonime pentru obiecte de
tipul: tabel, vizualizare, secvenŃă, funcŃie, procedură, pachet, clişeu,
sinonim.
Crearea unui sinonim se realizează prin comanda:

CREATE [PUBLIC] SYNONYM [schema.]nume_sinonim


FOR [schema.]obiect
Exemplu:
CREATE SYNONYM artist1 FOR artist;
SELECT * from user_objects;
SELECT * from artist1;

CREATE SYNONYM domeniu1seq for domeniuseq;

Administratorul bazei poate produce şi poate suprima sinonime


publice sau private, iar utilizatorii pot genera sau suprima doar sinonime
private. Pentru suprimarea unui sinonim din baza de date se utilizează
comanda:
DROP [PUBLIC] SYNONYM [schema.]nume_sinonim

69
Vizualizări

O vizualizare (view) nu conŃine date şi poate fi interpretată ca


o „fereastră“ prin care informaŃiile din tabele pot fi consultate şi
modificate. Un astfel de obiect al bazei de date extrage rezultatul
unei cereri şi îl tratează ca pe un tabel. Prin urmare, o vizualizare
poate fi considerată drept o cerere stocată sau un tabel virtual.
O vizualizare este o interogare SQL stocată, care poate fi referită
de instrucŃiunile SQL DML şi DQL ca şi cum ar fi un tabel real. Unii
consideră că vizualizările sunt „tabele virtuale", deoarece se
comportă la fel ca tabelele, dar nu există ca tabele fizice.

Numele vizualizării trebuie să respecte aceleaşi reguli de denumire


ca şi tabelele şi alte obiecte ale bazei de date.
Interogarea SQL inclusă în definiŃia vizualizării poate fi orice
instrucŃiunea SQL SELECT validă.
Vizualizarea (view) este un tabel logic (virtual) relativ la date din
una sau mai multe tabele sau vizualizări. Vizualizarea este definită
plecând de la o cerere a limbajului de interogare a datelor, moştenind
caracteristicile obiectelor la care se referă. Vizualizarea, fiind virtuală, nu
solicită o alocare de memorie pentru date. Ea este definită în DD cu
aceleaşi caracteristici ca şi un tabel.
Spre deosebire de tabele, pentru conŃinutul vizualizării nu se alocă
spaŃiu de stocare. SpaŃiul ocupat de o vizualizare este doar cel alocat
definiŃiei acesteia (cererii stocate) din dicŃionarul datelor. Tabelele din
care cererea stocată selectează date se numesc tabele de bază ale
vizualizării. Ele pot fi tabele sau chiar vizualizări, inclusiv vizualizări
materializate.

Textul cererii care defineşte vizualizarea este salvat în DD. Nucleul


Oracle determină fuzionarea cererii relative la vizualizare cu comanda de
definire a vizualizării, analizează rezultatul fuziunii în zona partajată şi
execută cererea.
Oracle transformă cererea referitoare la o vizualizare într-o cerere
relativă la tabelele de bază. Vizualizarea este memorata in DD sub forma
unui SELECT.
Dacă sunt utilizate clauzele UNION, GROUP BY şi CONNECT BY,
atunci Oracle nu determină fuzionarea, el va rezolva vizualizarea şi apoi
va aplica cererea rezultatului obŃinut.

70
O vizualizare reflectă la orice moment conŃinutul exact al tabelelor
de bază. Orice modificare efectuată asupra tabelelor se repercutează
instantaneu asupra vizualizării. Ştergerea unui tabel implică invalidarea
vizualizărilor asociate tabelului şi nu ştergerea acestora.
Vizualizările sunt definite pentru:
• furnizarea unui nivel mai înalt de securizare a bazei;
• simplificarea formulării unei cereri;
• mascarea complexităŃii datelor;
• afişarea datelor într-o altă reprezentare decât cea a tabelelor de
bază;
• asigurarea independenŃei datelor;
• asigurarea confidenŃialităŃii anumitor informaŃii;
• definirea constrângerilor de integritate;
• restricŃionarea acesului la date.
Vizualizările pot fi simple şi complexe. O vizualizare simplă
extrage date dintr-un singur tabel, nu conŃine funcŃii sau grupări de date şi
asupra ei pot fi efectuate operaŃii LMD.
O vizualizare este considerată complexă dacă extrage date din mai
multe tabele, conŃine funcŃii sau grupări de date şi nu permite întotdeauna
(prin intermediul său) operaŃii LMD asupra tabelelor de bază.
OperaŃiile LMD asupra vizualizărilor complexe sunt restricŃionate
de următoarele reguli:
• nu se poate insera, actualiza sau şterge o linie dintr-o vizualizare
dacă aceasta conŃine funcŃii grup, clauza GROUP BY, cuvântul
cheie DISTINCT sau pseudocoloana ROWNUM;
• nu se poate adăuga sau modifica o linie dintr-o vizualizare, dacă
aceasta conŃine coloane definite prin expresii;
• nu pot fi adăugate linii printr-o vizualizare, dacă tabelul de bază
conŃine coloane care au constrângerea NOT NULL şi nu apar în
lista SELECT a vizualizării.
Pentru a obŃine informaŃii referitoare la vizualizările definite, se pot
interoga vizualizările USER_VIEWS şi ALL_VIEWS din dicŃionarul
datelor. Textul instrucŃiunii SELECT care defineşte o vizualizare este
stocat într-o coloană de tip LONG, numită TEXT.
Atunci când datele sunt accesate prin intermediul unei vizualizări,
server-ul Oracle efectuează următoarele operaŃii:
• recuperează definiŃia acesteia din USER_VIEWS;
• verifică privilegiile de acces la tabelele ei de bază;
• converteşte cererea într-o operaŃie echivalentă asupra tabelelor
de bază.

71
Crearea unei vizualizări se realizează cu ajutorul comenzii:
CREATE [OR REPLACE][FORCE | NOFORCE] VIEW
[<nume_schema>.]<nume_view> [(<alias>[,<alias>]…)]
AS <cerere_SELECT>
[WITH {CHECK OPTION [CONSTRAINT <nume_constrangere>] |
READ ONLY }];
– OR REPLACE recreează vizualizarea dacă aceasta deja există.
– FORCE creează vizualizarea chiar dacă tabelul de bază nu există sau
chiar dacă vizualizarea face referinŃă la obiecte care încă nu sunt
create. Deşi vizualizarea va fi creată, utilizatorul nu poate să o
folosească.
– NO FORCE este implicită şi se referă la faptul că vizualizarea este
creată numai dacă tabelele de bază există.
– Cererea este o comandă SELECT care poate să conŃină alias pentru
coloane.
– WITH CHECK OPTION specifică faptul că reactualizarea datelor din
tabele (inserare sau modificare) se poate face numai asupra datelor
selectate de vizualizare (care apar în clauza WHERE).
– WITH READ ONLY asigură că nici o operaŃie LMD nu poate fi
executată asupra vizualizării.

Exemplu:
Să se genereze o vizualizare care conŃine informaŃii referitoare la
împrumutul cărŃilor şi în care să fie implementată constrîngerea că orice
carte, care există într-un singur exemplar, poate fi împrumutată maximum
15 zile.
CREATE VIEW imprumutare
AS SELECT *
FROM imprumuta
WHERE codel NOT IN
(SELECT codel
FROM carte
WHERE nrex = 1)
OR datares - dataim < 15
WITH CHECK OPTION;
Cererea care defineşte vizualizarea poate fi complexă, incluzând
join-uri, grupări şi subcereri, însă nu poate conŃine clauza ORDER BY.
Dacă este necesar, această clauză poate fi specificată la interogarea
vizualizării. Interogarea unei vizualizări este similară celei unui tabel.

72
Numărul coloanelor specificate în definiŃia vizualizării trebuie să fie egal
cu cel din lista asociată comenzii SELECT.
Asupra cererii care defineşte vizualizarea se impun următoarele
restricŃii:
• nu pot fi selectate pseudocoloanele CURRVAL şi NEXTVAL ale
unei secvenŃe;
• dacă sunt selectate pseudocoloanele ROWID, ROWNUM sau
LEVEL, acestora trebuie să li se specifice alias-uri;
• dacă cererea selectează toate coloanele unui tabel, utilizând
simbolul „*“, iar ulterior se adaugă coloane noi tabelului,
vizualizarea nu va conŃine acele coloane până la recrearea sa
printr-o instrucŃiune CREATE OR REPLACE VIEW;
• pentru vizualizările obiect, numărul şi tipul elementelor
selectate de cerere trebuie să coincidă cu cel al atributelor de pe
primul nivel al tipului obiect.
Aportul versiunii Oracle9i în ceea ce priveşte instrucŃiunea
CREATE VIEW constă în posibilitatea:
• creării de subvizualizări ale vizualizărilor obiect;
• definirii de constrângeri asupra vizualizărilor.
Exemplu:
a) Să se creeze o vizualizare care conŃine numele şi prenumele
artistului, numărul operelor sale şi valoarea medie a acestora.
CREATE VIEW artist_nr_val(nume, numar_opere, val_medie)
AS SELECT a.nume || ' ' || a .prenume "Nume si prenume",
COUNT(o. cod_opera) numar, AVG(o.valoare) medie
FROM opera o, artist a
WHERE o.cod_artist = a.cod_artist
GROUP BY o.cod_artist, a.nume, a.prenume;
b) Să se creeze vizualizarea sculptura ce va conŃine codul operei,
data achiziŃiei, codul artistului şi stilul operelor al căror tip este
„sculptura“.
CREATE OR REPLACE VIEW sculptura
(cod_sculptura, informatii, cod_sculptor, stil)
AS SELECT cod_opera,
'Sculptura ' || titlu ||
' a fost achizitionata la data ' ||
data_achizitiei, cod_artist, stil
FROM opera
WHERE tip = 'sculptura';

73
Modificarea unei vizualizări presupune modificarea definiŃiei

acesteia. Pentru a înlocui o vizualizare trebuie avut privilegiul de

sistem necesar pentru distrugerea şi crearea acesteia. Înlocuirea se

poate face în două moduri.

• Vizualizarea poate fi distrusă (DROP VIEW) şi apoi recreată


(CREATE) cu noua definiŃie. Atunci când este distrusă, toate
privilegiile sunt retrase. Aceste privilegii trebuie să fie create
pentru noua vizualizare.
• Vizualizarea poate fi recreată prin redefinire cu instrucŃiunea
CREATE VIEW, dar cu clauza OR REPLACE. Această metodă
conservă toate privilegiile curente.
In Oracle9i este posibila adaugarea de constrangeri unei vizualizari

prin comanda ALTER VIEW.

Modificarea unui vizualizări are următoarele efecte:

• definiŃia vizualizării din DD este actualizată;


• nici unul din obiectele de bază nu este afectat de înlocuire;
• toate restricŃiile care existau în vizualizarea originală sunt
distruse;
• toate vizualizările şi programele PL/SQL dependente de
vizualizarea înlocuită devin invalide.
Suprimarea unei vizualizări se realizează prin comanda DROP
VIEW care şterge definiŃia vizualizării din baza de date.
DROP VIEW <nume_view> [CASCADE CONSTRAINT];
Ştergerea vizualizării nu va afecta tabelele relativ la care a fost
definită vizualizarea. AplicaŃiile şi vizualizările care se bazează pe
vizualizarea suprimată devin invalide. Pentru a suprima o vizualizare,
utilizatorul trebuie să aibă privilegiul DROP ANY VIEW sau să fie
creatorul vizualizării respective.
Similar opŃiunii corespunzătoare din comanda DROP TABLE,
clauza CASCADE CONSTRAINTS permite suprimarea tuturor
constrângerilor de integritate referenŃială corespunzătoare cheilor primare
şi unice din vizualizarea supusă ştergerii. Dacă se omite această clauză şi

74
există astfel de constrângeri, instrucŃiunea DROP VIEW va eşua.
Recompilarea unei vizualizări permite detectarea eventualelor
erori referitoare la vizualizare, înaintea executării vizualizării. După
fiecare modificare a tabelelor de bază este recomandabil ca vizualizarea
să se recompileze:
ALTER VIEW <nume_view> COMPILE;
Reactualizarea tabelelor implică reactualizarea
corespunzătoare a vizualizărilor!!!
Reactualizarea vizualizărilor implică reactualizarea
tabelelor de bază? NU! Există restricŃii care trebuie
respectate!!!
• Nu pot fi modificate date din vizualizare sau adaugate date prin
vizualizare, daca aceasta contine coloane definite prin expresii.
• Nu pot fi înserate, şterse sau actualizate date din vizualizări ce
conŃin: operatorul DISTINCT; clauzele GROUP BY, HAVING,
START WITH, CONNECT BY; pseudo-coloana ROWNUM; funcŃii
grup; operatori de mulŃimi.
• Nu pot fi inserate sau actualizate date care ar încălca constrângerile
din tabelele de bază.
• Nu pot fi inserate sau actualizate valorile coloanelor care rezultă
prin calcul.
• Nu se pot face operaŃii LMD asupra coloanelor calculate cu
DECODE.
Alături de restricŃiile prezentate anterior, aplicabile tuturor
vizualizărilor, există restricŃii specifice, aplicabile vizualizărilor bazate pe
mai multe tabele.
Regula fundamentală este că orice operaŃie INSERT, UPDATE
sau DELETE pe o vizualizare bazată pe mai multe tabele poate modifica
datele doar din unul din tabelele de bază. In care???
Un tabel de bază al unei vizualizări este protejat prin cheie (key
preserved table) dacă orice cheie selectată a tabelului este de asemenea şi
cheie a vizualizării. Deci, un tabel protejat prin cheie este un tabel ale
cărui chei se păstrează şi la nivel de vizualizare. Pentru ca un tabel să fie
protejat prin cheie nu este necesar ca tabelul să aibă toate cheile selectate
în vizualizare. Este suficient ca, atunci când cheia tabelului este selectată,
aceasta să fie şi cheie a vizualizării.
Asupra unui join view pot fi aplicate instrucŃiunile INSERT,
UPDATE sau DELETE, doar dacă sunt îndeplinite următoarele condiŃii:
• instrucŃiunea LMD afectează numai unul dintre tabelele de bază;

75
• în cazul instrucŃiunii UPDATE, toate coloanele care pot fi
reactualizate trebuie să corespundă coloanelor dintr-un tabel
protejat prin cheie (în caz contrar, Oracle nu va putea identifica
unic înregistrarea care trebuie reactualizată);
• în cazul instrucŃiunii DELETE, rândurile unei vizualizări pot fi
şterse numai dacă există un tabel în join protejat prin cheie şi
numai unul (în caz contrar, Oracle nu ar şti din care tabel să
şteargă);
• în cazul instrucŃiunii INSERT, toate coloanele în care sunt inserate
valori trebuie să provină dintr-un tabel protejat prin cheie.
ALL_UPDATABLE_COLUMNS, DBA_UPDATABLE_COLUMNS
şi USER_UPDATABLE_COLUMNS sunt vizualizări din DD ce conŃin
informaŃii referitoare la coloanele vizualizărilor existente, care pot fi
reactualizate.
Exmplu:
1. Să se creeze un view ce conŃine câmpurile nume, prenume, job din
tabelul salariat.
2. Să se insereze, să se actualizeze şi să se şteargă o înregistrare în
acest view. Ce efect vor avea aceste acŃiuni asupra tabelului de
bază?
CREATE VIEW vederea2
AS SELECT nume, prenume, job
FROM salariat;
Nu se pot face inserari deoarece view-ul nu conŃine cheia primară!
INSERT INTO vederea2
VALUES ('Popescu','Valentin','grafician');
va genera eroarea:
ORA-01400: cannot insert NULL into
("SCOTT"."SALARIAT"."COD_SALARIAT")
Actualizarea job-ului salariatului având numele "Popescu":
UPDATE vederea2
SET job = 'programator'
WHERE nume = 'Popescu';
SELECT nume, prenume, job FROM salariat;
Ştergerea înregistrării referitoare la salariatul având numele
"Popescu":
DELETE vederea2
WHERE nume = 'Popescu';

76
OperaŃiile care se realizează asupra view-ului se realizează şi în
tabelul salariat. Pentru un caz mai general, când view-ul conŃine cheia
externă a tabelului de bază, sunt permise modificări ale view-ului, dacă
acestea nu afectează cheia externă.
Exemplu:
Să se creeze un view care conŃine câmpurile nume, prenume, job
din tabelul salariat. Să se introducă în view doar persoanele care sunt
graficieni.
CREATE VIEW vederea21
AS SELECT nume, prenume, job
FROM salariat
WHERE job = 'grafician'
WITH CHECK OPTION;
Să se creeze o vizualizare care să conŃină cod_salariat, nume,
prenume din tabelul salariat şi coloana tip din tabelul grafician. Apoi să
se insereze, să se actualizeze şi să se şteargă o înregistrare din acest view
(vizualizarea conŃine cheia primară cod_salariat din tabelele salariat şi
grafician).
CREATE VIEW vederea4
AS SELECT s.cod_salariat,nume,prenume,tip
FROM salariat s, grafician g
WHERE s.cod_salariat=g.cod_salariat;
În cazul inserării unei înregistrări pentru care se specifică toate
câmpurile:
INSERT INTO vederea4
VALUES
(30,'Popescu','Valentin','artist plastic');
va apare următoarea eroare:
ORA-01776: cannot modify more than one base TABLE
through a join view
Pot fi inserate date doar într-un tabel de bază (în oricare, dar în
unul singur) prin intermediul view-ului, astfel:
INSERT INTO vederea4 (cod_salariat, nume)
VALUES (30, 'Popescu');
Comanda pentru ştergerea unei înregistrări:
DELETE vederea4
WHERE cod_salariat = 3;
va genera următoarea eroare:

77
ORA-01752: cannot delete from view without
exactly one key-preserved TABLE.
Modificarea unei înregistrări se face prin secvenŃa care urmează.
Toate actualizările care se fac în view se fac şi în tabelele de bază.
UPDATE vederea4
SET tip = 'designer'
WHERE cod_salariat = 3;
Exemplu:
Care dintre coloanele unei vizualizări sunt actualizabile?
SELECT column_name, updatable
FROM user_updatable_columns
WHERE table_name = 'vederea4';
Exemplu:
1. Să se creeze un view (vederea3) care să conŃină, pentru fiecare
categorie de salariat, salariile medii şi numărul de angajaŃi din
tabelul salariat.
2. Să se insereze, să se actualizeze şi să se şteargă o înregistrare în
view.
CREATE VIEW vederea3 (nr, job, salmed)
AS SELECT COUNT(*), job, AVG(salariu)
FROM salariat
GROUP BY job;
Nu se pot face inserări, actualizări sau ştergeri într-un view ce
conŃine funcŃii grup. După oricare din aceste operaŃii apare acelaşi mesaj:
ORA-01732: data manipulation operation not legal
on this view
Exemplu:
Să se creeze o vizualizare care să conŃină coloanele
cod_contractant, adresa, telefon din tabelul contractant şi coloanele
nr_contract, tip_contract, data_incheiere din tabelul contract. Să se
insereze o înregistrare în vizualizare.
CREATE VIEW vederea44
AS SELECT c.cod_contractant, adresa, telefon,
co.nr_contract, tip_contract,
data_incheiere
FROM contractant c, contract co
WHERE
c.cod_contractant=co.cod_contractant;
La inserarea unei înregistrări căreia i se specifică valorile tuturor
câmpurilor din ambele tabele:

78
INSERT INTO vederea44(cod_contractant, adresa,
nr_contract,
data_incheiere)
VALUES (200, 'Str. Marmurei, 14', '6235',
TO_DATE('January 03,2002','Month
dd,yyyy'));
se obŃine eroarea:
ORA-01779: cannot modify a column which maps to a
non key-preserved TABLE
Cele două tabele de bază, contractant şi contract, se află într-o
relaŃie “one-to-many”, iar view-ul creat conŃine cheile primare din ambele
tabele.
Doar tabelul contract este protejat prin cheie şi, prin urmare, doar
el poate fi modificat prin intermediul view-ului. Aceasta, deoarece ar
putea exista mai multe înregistrări în view, cu aceeaşi valoare
corespunzătoare câmpului cod_contractant (CP în contractant).
Exact aceeaşi eroare se obŃine dacă încercăm inserarea unei
înregistrări în vederea44, specificând fie şi numai un câmp provenind din
tabela contractant (indiferent dacă el conŃine sau nu CP).
Singura operaŃie de inserare permisă este aceea efectuată prin
specificarea cheilor provenind doar din tabelul contract. Astfel, prin
executarea comenzii:
INSERT INTO vederea44(nr_contract, tip_contract)
VALUES ('6234', 0);
este creată o înregistrare, dar este modificat şi tabelul contract. Dacă la
inserŃie nu se specifică cheia primară din contract:
INSERT INTO vederea44(tip_contract)
VALUES (1);
ORA-01400: mandatory (NOT NULL) column is missing
or NULL during insert
Cererea din definiŃia vizualizării poate fi restricŃionată prin clauzele
WITH READ ONLY şi WITH CHECK OPTION. OpŃiunea WITH READ
ONLY asigură că nu pot fi efectuate operaŃii LMD asupra vizualizării.
Constrângerea WITH CHECK OPTION garantează faptul că va fi
permisă, prin intermediul vizualizării, numai inserarea sau actualizarea de
linii accesibile acesteia (care sunt selectate de cerere). Prin urmare,
această opŃiune asigură constrângeri de integritate şi verificări asupra
validităŃii datelor inserate sau actualizate.
OpŃiunea WITH CHECK OPTION nu poate funcŃiona dacă:
• există o cerere imbricată în cadrul subcererii vizualizării sau în
vreuna dintre vizualizările de bază;

79
• operaŃiile de inserare, ştergere şi modificare se fac prin
intermediul declanşatorilor INSTEAD OF.
Cuvântul cheie CONSTRAINT permite numirea constrângerii
WITH CHECK OPTION. În absenŃa acestei clauze, constrângerea va avea
un nume implicit de forma SYS_Cn, unde n este un număr întreg unic.
Exemplu:
Să se creeze o vizualizare ce conŃine artiştii de naŃionalitate
română, care au opere expuse în muzeu. DefiniŃia vizualizării nu va
permite modificarea naŃionalităŃii unui artist sau inserarea unui artist
având altă naŃionalitate decât cea română.
CREATE VIEW artist_roman
AS SELECT * FROM artist
WHERE nationalitate = 'romana'
WITH CHECK OPTION CONSTRAINT artist_roman_ck;
UPDATE artist_roman
SET nationalitate = 'engleza'
WHERE cod_artist = 25;
Încercarea de actualizare a unei linii prin instrucŃiunea anterioară
va genera eroarea „ORA-01402: view WITH CHECK OPTION where-
clause violation“.
Exemplu:
Să se creeze o vizualizare asupra tabelului galerie care să nu
permită efectuarea nici unei operaŃii LMD.
CREATE VIEW viz_galerie
AS SELECT cod_galerie, nume_galerie
FROM galerie
WITH READ ONLY;
DELETE FROM viz_galerie
WHERE cod_galerie = 10;
Încercarea de ştergere a unei linii din vizualizarea viz_galerie
determină apariŃia erorii „ORA-01752: cannot delete from view without
exactly one key-preserved table“. Dacă se încearcă modificarea sau
inserarea unei linii prin intermediul unei vizualizări asupra căreia a fost
definită o constrângere WITH READ ONLY, server-ul Oracle generează
eroarea „ORA-01733: virtual column not allowed here“.
Exemplu:
Să se creeze o vizualizare care conŃine codul şi titlul operelor de
artă, codul şi numele artiştilor care le-au creat, precum şi codul galeriilor
unde sunt expuse. Să se afle dacă este posibilă adăugarea unei noi
înregistrări prin intermediul acestei vizualizări.

80
CREATE VIEW opera_artist
AS SELECT o.cod_opera, o.titlu, o.cod_galerie,
a.cod_artist, a.nume
FROM opera o, artist a
WHERE o.cod_artist = a.cod_artist;
InstrucŃiunea următoare afişează numele coloanelor şi valorile
YES/NO, după cum aceste coloane sunt, sau nu, modificabile.
SELECT COLUMN_NAME, UPDATABLE
FROM USER_UPDATABLE_COLUMNS
WHERE TABLE_NAME = 'OPERA_ARTIST';
Se va obŃine că doar primele trei coloane ale vizualizării sunt
modificabile.
Indexul primar al coloanei cod_artist din tabelul artist nu este unic
în vizualizarea opera_artist. Prin urmare, tabelul artist nu este key-
preserved, iar coloanele sale nu sunt modificabile.
InstrucŃiunea următoare va genera eroarea „ORA-01776: cannot
modify more than one base table through a join view“.
INSERT INTO opera_artist
VALUES (200, 'Poeme de l''ame', 20, 147,
'Janmot');
În schimb, instrucŃiunea următoare va fi executată cu succes,
întrucât adaugă o înregistrare în tabelul de bază opera, ale cărui coloane
sunt modificabile.
INSERT INTO opera_artist (cod_opera, titlu,
cod_galerie)
VALUES (200, 'Poeme de l''ame', 20);
Constrângeri asupra vizualizărilor
Începând cu versiunea Oracle9i pot fi specificate constrângeri
pentru vizualizări. Se pot defini constrângeri la nivel de vizualizare,
respectiv la nivel de coloană sau atribut. Constrângerile asupra
vizualizărilor constituie o submulŃime a constrângerilor specifice
tabelelor.
Pot fi specificate explicit numai constrângerile UNIQUE,
PRIMARY KEY şi FOREIGN KEY. Constrângerea de tip CHECK poate fi
realizată prin precizarea clauzei WITH CHECK OPTION în comanda care
defineşte vizualizarea.
Constrângerile asupra vizualizărilor pot fi definite numai în modul
DISABLE NOVALIDATE. Aceste cuvinte cheie trebuie specificate la
declararea constrângerii, nefiind permisă precizarea altor stări.
Exemplu:

81
Să se creeze o vizualizare care conŃine codurile, numele şi adresele
galeriilor. Se va impune unicitatea valorilor coloanei adresa şi
constrângerea de cheie primară pentru coloana corespunzătoare codului
galeriei.
CREATE VIEW viz_galerie(
cod_gal, nume, adresa UNIQUE DISABLE NOVALIDATE,
CONSTRAINT cp_viz PRIMARY KEY (cod_gal) DISABLE
NOVALIDATE)
AS SELECT cod_galerie, nume_galerie, adresa
FROM galerie;

InformaŃii despre obiectele bazei de date

Pot fi obŃinute consultând DD(Dicționarul de Date). Dintre ele se


remarcă:
• definiŃiile tuturor obiectelor din baza de date;
• spaŃiul alocat şi spaŃiul utilizat în prezent de obiectele schemei;
• constrângerile de integritate;
• numele utilizatorilor bazei;
• privilegiile şi rolurile acordate fiecărui rol;
• alte informaŃii generale despre baza de date.
Tabelul USER_CATALOG conŃine informaŃii despre tabelele şi
vizualizările definite de un utilizator particular. Acest tabel poate fi referit
şi prin sinonimul său public CAT.
Tabelul USER_OBJECTS conŃine informaŃii despre toate obiectele
definite de utilizatorul curent. Tabelul are următoarea schemă relaŃională:
USER_OBJECTS (object_name, object_id, object_type, created,
last_ddl_time, timestamp, status)
Vizualizările cele mai importante ale dicŃionarului datelor conŃin:
• descrierea tabelelor definite de utilizatori (USER_ALL_TABLES),
• informaŃii despre constrângerile definite de
utilizator(USER_CONSTRAINTS),
• informaŃii despre legăturile bazei de date (USER_DB_LINKS),
• erorile curente ale obiectelor depozitate (USER_ERRORS),
• informaŃii despre indecşii creaŃi de utilizator (USER_INDEXES),
• informaŃii despre tabelele utilizatorului (USER_TABLES) etc.

82
Vizualizările din dicŃionarul datelor referitoare la tabele conŃin:
• USER_TAB_COLUMNS|COLS – informaŃii despre coloanele
tabelelor,
• USER_CONS_COLUMNS – informaŃii despre constrângeri la nivel
coloană,
• USER_TAB_COMMENTS – informaŃii despre comentarii la nivel
tabel,
• USER_COL_COMMENTS – informaŃii despre comentarii la nivel
coloană,
• USER_TAB_PARTITIONS – informaŃii despre partiŃiile tabelelor.

83
Limbajul de interogare a datelor(DQL)
Limbajul SQL de interogare a datelor (DQL – Data Query
Language) include o singură comandă SELECT, care este cea mai
folosită pentru a obŃine date din baza de date, astfel încât acestea să fie
prelucrate de o anumită aplicaŃie sau să fie afişate. Rezultatul unei
instrucŃiuni SELECT, numit şi set de rezultate, este returnat sub forma
unui tabel. Deoarece SQL este un limbaj neprocedural, se specifică
rezultatele pe care le doriŃi să le obŃineŃi, nu şi modul lor de obŃinere.

InstrucŃiunea SELECT de bază

Cererea (interogarea) este realizată de instrucŃiunea SELECT. Cu ajutorul


ei pot fi extrase submulŃimi de valori atât pe verticală (coloane), cât şi pe
orizontală (linii) din unul sau mai multe tabele. Sintaxa comenzii este
simplă, apropiată de limbajul natural.
SELECT [ALL | DISTINCT]
{* | listă de atribute selectate | expr AS alias}
FROM { [schema.]tabel [alias_tabel] }
[WHERE condiŃie]
[GROUP BY listă de expresii
[HAVING condiŃie]]
[ORDER BY {expresie | poziŃie | c_alias} [ASC | DESC]]

Forma elementară a instrucŃiunii SELECT conŃine două clauze:


SELECT [DISTINCT] - Specifică lista de coloane care
urmează să fie returnate în setul de rezultate, separate prin virgule. Se
poate folosi simbolul asterisc (*) în locul listei de coloane pentru a selecta
toate coloanele dintr-un tabel sau dintr-o vizualizare. Cuvântul cheie
DISTINCT poate fi adăugat după cuvântul cheie SELECT pentru a
elimina rândurile duplicate din rezultatele interogării.
FROM - Specifică lista tabelelor sau vizualizărilor din care
urmează să fie selectate datele. În locul numelor reale ale tabelelor sau
vizualizărilor se poate folosi sinonime, adică pseudonime pentru tabele
sau vizualizări definite în baza de date.
PrezenŃa clauzelor SELECT şi FROM este obligatorie deoarece acestea
specifică coloanele selectate, respectiv tabelele din care se vor extrage
datele. Tabelele specificate în clauza FROM pot fi urmate de un alias,
care va reprezenta numele folosit pentru referirea tabelului respectiv în
cadrul instrucŃiunii.

1
Eliminarea duplicatelor se poate realiza folosind clauza
DISTINCT. Dacă nu se specifică parametrul DISTINCT, parametrul ALL
este implicit şi are ca efect afişarea dublurilor.
Simbolul “*” permite selectarea tuturor atributelor din
tabelele asupra cărora se execută cererea. Atributele sau expresiile din
lista clauzei SELECT pot conŃine alias-uri, care vor reprezenta numele
câmpurilor respective în cadrul tabelului furnizat ca rezultat de
instrucŃiunea SELECT.
Clauza WHERE poate fi folosită pentru a impune anumite
condiŃii liniilor din care se vor extrage atributele specificate în clauza
SELECT.
Clauza GROUP BY grupează înregistrările după anumite
câmpuri; în cazul prezenŃei acestei clauze, clauza HAVING poate impune
restricŃii suplimentare asupra rezultatului final.
Ordonarea înregistrărilor se poate face cu ajutorul clauzei
ORDER BY. Cu ajutorul parametrilor ASC şi DESC se poate specifica
ordonarea crescătoare, respectiv descrescătoare a înregistrărilor. Pentru o
secvenŃă crescătoare valorile null sunt afişate ultimele. Dacă nu se face
nici o specificaŃie, atunci ordinea de returnare este la latitudinea server-
ului.

În exemplul următor se selectează coloanele:


COD_GEN_FILM, MPAA_RATING_COD şi TITLU_FILM din
tabelul FILM.
SELECT COD_GEN_FILM, COD_ RATING, TITLU_FILM
FROM FILM;

Pseudonime pentru numele coloanelor

In setul de rezultate din interogări numele coloanelor din tabel


apare automat ca titlu de coloane în interogare. Dacă se doreşte un alt
nume pentru coloanele unei interogări se folosesc pseudonime.
Pseudonimele (aliases) specificate devin numele coloanelor din setul
de rezultate. Pseudonimele nu există decât după rularea instrucŃiunii SQL,
aşa că nu pot fi folosite în alte părŃi ale instrucŃiunii SQL. Pseudonimul
unei coloane este specificat prin plasarea cuvântului cheie ”AS" după
numele coloanei în lista SELECT (cu cel puŃin un spaŃiu înainte şi după),
urmat de numele dorit pentru a fi atribuit coloanei în setul de rezultate.
SELECT COD_GEN_FILM AS GEN, MPAA_RATING_COD AS
RATING, TITLU_FILM AS FILM
FROM FILM;

2
Dacă în interiorul alias-ului apare un spaŃiu liber sau caractere
speciale, atunci alias-ul trebuie scris între ghilimele.
SELECT dateres–dataim ”numar zile”
FROM imprumuta;

Sortarea rezultatelor

Rezultatele interogărilor sunt deseori mult mai utile dacă se


specifică pentru rândurile returnate o ordine care să aibă o semnificaŃie
pentru persoana sau aplicaŃia care foloseşte informaŃiile. În SQL, acest
lucru este făcut prin adăugarea în instrucŃiunea SELECT a clauzei ORDER
BY, cu o listă de una sau mai multe coloane care vor fi folosite pentru
sortarea rândurilor în ordine ascendentă sau descendentă, în conformitate cu
valorile datelor din coloane. De asemenea, se Ńine seama de următoarele
aspecte:
Ordinea prestabilită pentru fiecare coloană este ascendentă, dar se
poate adăuga cuvântul cheie ASC după numele coloanei pentru obŃinerea
unei ordonări ascendente sau cuvântul cheie DESC pentru obŃinerea unei
ordonări descendente.
Nu este obligatoriu ca numele coloanelor din lista ORDER BY să
fie incluse şi în lista de rezultate (adică în lista SELECT).
Motorul SQL din SGBD va găsi cea mai bună cale de ordonare a
coloanelor. În general, sortarea datelor este un proces costisitor din punct
de vedere al resurselor de calcul, aşa că majoritatea sistemelor SGBD
folosesc un index pentru accesul la rânduri în ordinea dorită, presupunând
că există, şi fac o sortare propriu-zisă numai ca ultimă soluŃie.
Se poate folosi pseudonimele coloanelor în clauza ORDER BY,
dar dacă se face acest lucru se forŃează motorul SQL să sorteze rezultatele
abia după rularea interogării.
În locul coloanelor, se poate specifica în lista de ordonare poziŃia
relativă a coloanelor. De exemplu, clauza ORDER BY 1,2 va sorta
rezultatele în ordine ascendentă după primele două coloane din setul de
rezultate. Numărul specificat nu are nici o legătură cu poziŃia coloanei în
tabelul sau vizualizarea sursă. Această opŃiune nu este agreată în
programarea SQL formală, deoarece dacă ulterior cineva modifică
interogarea, este posibil să amestece coloanele din lista SELECT, fără să-
şi dea seama că astfel schimbă şi coloanele folosite pentru sortarea
rezultatelor.
Exemplu:
SELECT MPAA_RATING_COD AS RATING,
COD_GEN_FILM AS GEN, TITLU_FILM AS FILM

3
FROM FILM
ORDER BY MPAA_RATING_COD, COD_GEN_FILM ;

Dacă dorim să ordonăm acum crescător după rating şi descrescător


după gen, atunci instrucŃiunea de mai sus modificată va fi

SELECT MPAA_RATING_COD AS RATING,


COD_GEN_FILM AS GEN, TITLU_FILM AS FILM
FROM FILM
ORDER BY
MPAA_RATING_COD ASC, COD_GEN_FILM DESC;

ObservaŃie:
Oracle va afişa titlu de coloana la dimensiunea maximă a valorilor
din coloana(de ex. dacă în coloana RATING val cea mai mare este de 5
caractere, interogarea va afişa RATIN). În noua versiune de SQL produs
de Oracle, iSQL*Plus, nu mai prescurtează.

Exemplu :
SELECT titlu, autor, pret, coded as domeniu
from carte
order by coded, autor;

SELECT titlu, autor, pret, coded as domeniu


from carte
order by coded desc, pret;
Se observa ca domeniu este trunchiat la 5 caractere, DOMEN

4
Utilizarea clauzei WHERE pentru filtrarea rezultatelor

SQL foloseşte clauza WHERE pentru a filtra rândurile ce urmează


să fie afişate. O interogare fără o clauză WHERE returnează un set de
rezultate care conŃine toate rândurile din tabelele sau vizualizările referite
în clauza FROM. Dacă este inclusă o clauză WHERE, sunt folosite
regulile algebrei booleene, evaluând clauza WHERE pentru fiecare rând
de date. În rezultatele interogării sunt afişate numai rândurile pentru care
clauza WHERE este evaluată la valoarea logică „adevărat".

Operatorii utilizați în clauza WHERE se impart în patru categorii:

- Operatori de comparare
- Operatori conjuctivi
- Operatori logici
- Operatori aritmetici

Operatori de comparare

Operatorii de comparare sunt folosiŃi în clauza WHERE pentru


compararea a două valori, având ca rezultat o valoare logică de „adevărat" sau „fals".
Cele două valori comparare pot fi constante furnizate în clauza WHERE, valori ale
unor coloane din baza de date sau combinaŃii ale celor două. Operatorii de comparare
care pot fi folosiŃi în clauza WHERE sunt prezentaŃi în tabelul următor:

5
Operator Descriere
= Egal cu
< Mai mic decât
<= Mai mic sau egal
> Mai mare decât
>= Mai mare sau egal
!= Diferit de
<> Diferit de (standard ANSI)

Exemple din schema FILM:

• Să se afişeze toate filmele pentru care RATING are valoarea PG-13.


SELECT MPAA_RATING_COD AS RATING, TITLU_FILM
FROM FILM
WHERE MPAA_RATING_COD = 'PG-13'
ORDER BY TITLU_FILM;
• Să se afişeze filmele pentru care COD_RATING are altă valoare decât
PG-13.
SELECT COD_RATING AS RATING, TITLU_FILM
FROM FILM
WHERE COD_RATING <> 'PG-13'
ORDER BY TITLU_FILM;
• Să se afişeze toate filmele cu preŃul de vânzare cu amănuntul pentru
formatul DVD(DVD Retail Price) mai mare de 25.00, în ordinea
crescătoare a preŃurilor.
SELECT PRET_VANZARE_DVD, TITLU_FILM
FROM FILM
WHERE PRET_VANZARE_DVD >= 25.00
ORDER BY PRET_VANZARE_DVD DESC;

Exemple pe schema BIBLIOTECA

• Să se obtină codul cărtii care are data restituirii >..


SELECT codel
FROM imprumuta
WHERE datares >= ’05–oct–09’;

6
• Să se obŃină titlurile şi numărul de exemplare ale cărŃilor care au
nrex>100 ;
SELECT titlu, nrex
FROM carte
WHERE nrex>100;

Operatori conjunctivi

Uneori sunt necesare condiŃii multiple pentru a îngusta setul de


rezultate al unei interogări. Atunci când sunt folosite mai multe condiŃii,
ele trebuie să fie combinate din punct de vedere logic în clauza WHERE,
iar aceasta este sarcina operatorilor conjunctivi. Aceşti operatori sunt:
• AND (ŞI) - Clauza WHERE este evaluată ca „adevărată" dacă
toate condiŃiile conectate cu operatorul AND sunt adevărate.
• OR (SAU) - Clauza WHERE este evaluată ca „adevărată" dacă
oricare din condiŃiile conectate cu operatorul OR este adevărată.
Operatorul AND are prioritate mai mare şi, ca urmare, este evaluat
înaintea operatorilor OR.
Exemple de folosire a operatorilor conjunctivi:

• Să se afişeze toate filmele pentru care categoria RATING este PG-


13 şi preŃul de vânzare cu amănuntul pentru formatul DVD este
19.99 sau mai mic, în ordinea crescătoare a preŃurilor.

SELECT COD_RATING AS RATING,


PRET_VANZARE_DVD AS PRET, TITLU_FILM
FROM FILM
WHERE COD_RATING = 'PG-13'
AND PRET_VANZARE_DVD <= 20.00
ORDER BY PRET_VANZARE_DVD;

7
• Să se afişeze toate filmele pentru care categoria RATING este PG-
13 sau preŃul de vânzare cu amănuntul pentru formatul DVD este
19.99 sau mai mic, în ordinea crescătoare a preŃurilor.

SELECT COD_RATING AS RATING,


PRET_VANZARE_DVD AS PRET,
TITLU_FILM
FROM FILM
WHERE COD_RATING = 'PG-13' OR
PRET_VANZARE_DVD <= 20
ORDER BY PRET_VANZARE_DVD;

• AfişaŃi toate filmele pentru care categoria RATING este PG-13 şi


sunt din genul dramă sau acŃiune/aventură.

SELECT COD_RATING AS RATING,


PRET_VANZARE_DVD AS PRET, TITLU_FILM
FROM FILM
WHERE COD_GEN_FILM= 'ActAd'
OR COD_GEN_FILM = 'Drama'
AND COD_RATING = 'PG-13'
ORDER BY COD_GEN_FILM, COD_RATING;

• Să se adauge parantezele necesare, astfel încât să obŃinem filmele


cu categoria PG-13 şi genul acŃiune/aventură sau dramă.
SELECT COD_GEN_FILM AS GEN,
COD_RATING AS RATING, TITLU_FILM
FROM FILM
WHERE (COD_GEN_FILM = 'ActAd'
OR COD_GEM_FILM = 'Drama')
AND COD_RATING='PG-13'
ORDER BY COND_GEN_FILM, COD_RATING;

Operatori logici

Operatorii logici folosesc cuvinte cheie în locul simbolurilor la


formarea expresiilor de comparare. La oricare dintre aceşti operatori poate
fi adăugat cuvântul cheie NOT, pentru a inversa valoarea logică a
comparaŃiei.

8
IS NULL
Operatorul IS NULL este folosit pentru a determina dacă o valoare
este nulă.
Exemple:
• Să se găsească toate conturile de clienŃi active, adică toate conturile
pentru care coloana DATA–TERMINATA conŃine o valoare nulă:
SELECT ID_CONT_CLIENT
FROM CONT_CLIENT
WHERE DATA_INCHEIERE IS NULL;

• Să se găsească toate conturile inactive, adică toate conturile pentru


care coloana DATA–TERMINAT conŃine o altă valoare decât
NULL:
SELECT ID_CONT_CLIENT
FROM CONT_CLIENT
WHERE DATA_INCHEIERE IS NOT NULL;

BETWEEN
Operatorul BETWEEN este folosit pentru a determina dacă o
valoare se încadrează într-un interval special. Intervalul este specificat
folosind o valoare minimă şi o valoare maximă, fiind un interval inclusiv,
ceea ce înseamnă că include şi valori specificate.
Exemple:
• Să se afişeze toate filmele cu preŃul de vânzare cu amănuntul pentru
formatul DVD între 14.99 şi 19.99, ordonate crescător după preŃ.
SELECT TITLU_FILM, PRET_VANZARE_DVD
FORM FILM
WHERE PRER_VANZARE_DVD BETWEEN 14.99 AND 19.99
ORDER BY PRER_VANZARE_DVD;

• Să se afişeze toate filmele pentru care preŃul de vânzare cu amănuntul


pentru formatul DVD nu este în intervalul 14.99-19.99, ordonate
crescător după preŃ.
SELECT TITLU_FILM, PRET_VANZARE_DVD
FORM FILM
WHERE PRET_VANZARE_DVD NOT BETWEEN 14.99 AND 19.99
ORDER BY PRET_VANZARE_DVD;
• Să se afişeze toate conturile de clienŃi în luna ianuarie 2009.
SELECT ID_CONT_CLIENT, DATA_INSCRIERE
FROM CONT_CLIENT
WHERE DATA_INSCRIERE BETWEEN ”2009/01/01”
AND „2009/01/31”;

9
Tabelul DUAL se află în schema SYS şi poate fi accesat de către
toŃi utilizatorii. Tabelul este util atunci când se afişează valoarea unei
constante, pseudocoloane sau expresii care nu este construită pe baza
datelor vreunui tabel. În general, tabelul DUAL este utilizat pentru a
completa sintaxa instrucŃiunii SELECT, întrucât clauzele SELECT şi
FROM sunt obligatorii.
Să se afişeze data şi ora curentă.
SELECT TO_CHAR(SYSDATE,’DD/MM/YY HH24:MI:SS’)
FROM DUAL;

LIKE
Operatorul LIKE este folosit pentru a compara o valoare de tip
caracter cu un tipar*(pattern), returnând valoarea logică “adevărat” dacă
valoarea de tip caracter se încadrează în tipar şi “fals" în caz contrar.
Pentru definirea tiparului pot fi folosite două caractere de înlocuire:
• LiniuŃa de subliniere (_) - Caracterul liniuŃă de subliniere poate fi
folosit drept caracter de înlocuire poziŃional, ceea ce înseamnă că se
potriveşte cu orice caracter aflat pe poziŃia respectivă în şirul de
caractere evaluat.
• Procent (%) - Simbolul procent (%) poate fi folosit drept caracter
de înlocuire nepoziŃional, ceea ce înseamnă că se potriveşte cu
orice număr de caractere, indiferent de lungime, reprezentând orice
secvenŃă de zero sau mai multe caractere, şi „_“, reprezentând un
singur caracter.

Exemple de tipare:

Tipar Interpretare
Now% Se potriveşte cu orice şir de caractere care incepe cu
„Now".
N_w Se potriveşte cu orice şir de caractere format din
exact trei caractere, care începe cu „N" şi se termină
cu „w".

10
%N-w% Se potriveşte cu orice şir de caractere care conŃine
litera „N", urmată de orice alt caracter, urmat de litera
„w" (1a începutul, la sfârşitul sau undeva în mijlocul
şirului de caractere)
%Now% Se potriveşte cu orice şir de caractere care conŃine
„Now" (1a inceput, la sfârşit sau în mijloc).
%Now Se potriveşte cu orice şir de caractere care se termină
cu „Now".

Datele din bazele de date relaŃionale fac întotdeauna diferenŃierea


literelor mari de cele mici. O literă mica din date nu se potriveşte cu o
literă mare din tiparul unei clauze LIKE, şi invers.
Exemple de utilizare a operatorului LIKE:
• Să se afişeze toate titlurile de filme care conŃin şirul de caractere
„on":
SELECT TITLU_FILM
FROM FILM
WHERE TITLU_FILM LIKE '%on%';
• Dacă se intenŃionează să se găsească titlurile care conŃin cuvântul
„on", nu literele „on" din alte cuvinte, ar fi trebuit să includă în
tipar şi spatiile necesare, ca în exemplul următor:

Exemple
Să se afişeze cartile ale căror titlu conŃine cuvântul „Baza“, sau
pentru care al treilea caracter din autor este „p“.
SELECT titlu, autor
FROM carte
WHERE titlu LIKE '%Baza%' OR autor LIKE '__p%';

11
IN
Operatorul IN este folosit pentru a determina dacă o valoare face
parte dintr-o listă de valori. Lista poate fi specificată ca valori literale,
folosind o listă de valori separate prin virgule şi încadrate între paranteze,
sau poate fi selectată din baza de date folosind o subselecŃie (o
subinterogare), care este o interogare în cadrul unei alte interogări.

Exemple de utilizare a operatorului IN:


• Să se afişeze toate filmele pentru care COD_GEN_FILM este
Drama, Forgn.

SELECT COD_GEN_FILM AS GEN, TITLU_FILM


FROM FILM
WHERE COD_GEN_FILM IN ('Drama', 'Forgn')
ORDER BY COD_GEN_FILM, TITLU_FILM;

• Să se afişeze toate filmele pentru care descrierea genului conŃine


cuvântul „and". AveŃi nevoie de o subinterogare prin care să
găsiŃi toate valorile COD_GEN_FILM care conŃin cuvântul
„and" în descriere. Operatorul IN este apoi folosit pentru a găsi
filmele care au unul dintre codurile selectate de subinterogare.

SELECT COD_GEN_FILM AS GEN, TITLU_FILM


FROM FILM
WHERE COD_GEN_FILM IN
(SELECT COD_GEN_FILM
FROM GEN_FILM
WHERE GEN_FILM DESCRIPTION LIKE '% and %')
ORDER BY COD_GEN_FILM AS GEN, TITLU_FILM;

• Să se afişeze toate cartile din domeniile ’I’si ’M’.


SELECT TITLU, AUTOR
FROM CARTE
WHERE CODED IN(’I’,’M’);

12
EXISTS

Operatorul EXISTS este folosit pentru a detemina dacă o


subinterogare conŃine înregistrări. Dacă în setul de rezultate al
subinterogării nu există nici un rând, operatorul returnează valoarea
„false”; dacă setul de rezultate conŃine cel puŃin un rând, valoarea devine
„adevărat”.
Exemple de utilizare a operatorului EXIST:

• Proprietarul magazinului a auzit că filmul The Last Samurai se


închiriază bine atât în format DVD, cât şi-n format VHS şi vrea să
se asigure că în inventarul magazinului există o copie VHS.
Tabelul FILM_COPIAT conŃine un rând pentru fiecare copie a
unui film din inventarul magazinului, aşa că puteŃi folosi o
subinterogare pentru a afla dacă există copii VHS ale filmului în
inventar. De cele mai multe ori, operatorul EXISTS este folosit in
conjuncŃie cu o formă mai complexă de subinterogare, numită
subinterogare corelat. (correlated subquery),în care valorile
datelor din interogarea externă (ID_FILM, în acest caz) sunt
comparate cu rândurile din interogarea intenă.

SELECT ID_FILM, TITLU_FILM


FROM FILM M
WHERE TITLU_FILM = 'The Last Samurai'
AND EXISTS
(SELECT ID_FILM
FROM FILM_COPIAT C
WHERE M. ID_FILM = C. ID_FILM);
• Dacă inversaŃi logica, folosind operatorul NOT EXISTS, puteŃi
afişa titlul filmului numai dacă nu există o copie VHS în inventar.
SELECT ID_FILM, TITLU_FILM
FROM FILM M
WHERE TITLU_FILM = 'The Last Samurai'
AND NOT EXISTS
(SELECT ID_FILM
FROM FILM_COPIAT C
WHERE M. ID_FILM = C. ID_FILM);

13
Operatori aritmetici

În SQL, operatorii aritmetici sunt folosiŃi pentru efectuarea


calculelor matematice – la fel ca şi în formulele dintr-o foaie de calcul
tabelar sau într-un limbaj de programare, precum Java sau C. Cei patru
operatori aritmetici din SQL sunt:

Operator Descriere
+ Adunare
- Scădere
* ÎnmulŃire
/ ÎmpărŃire

Ca şi în cazul operatorilor conjunctivi, dacă se amestecă operatorii


aritmetici în aceeaşi instrucŃiune SQL fără a folosi paranteze, ordinea în
care sunt evaluate operaŃiile este determinată de prioritatea predefinită.
Din fericire, prioritatea operatorilor din SQL este cea pe care o folosim în
operaŃiile matematice obişnuite.
Exemple de utilizare a operatorilor aritmetici:
• Cât v-ar costa să cumpăraŃi copiile VHS şi DVD ale filmului The Last
Samurai?
SELECT PRET_VANZARE_VHS + PRET_VANZARE _DVD
AS COST
FROM FILM
WHERE TITLU_FILM = 'The Last Samurai';

• Cât v-ar costa aceeaşi achiziŃie dacă aŃi avea un bon valoric de 8 ron?
SELECT (PRET_VANZARE _VHS + PRET_VANZARE _DVD) - 8
AS COST
FROM FILM
WHERE TITLU_FILM = 'The Last Samurai';
• Dacă taxele sunt de 8.25% (0.0825), cât reprezintă taxele de vânzare
din costul achiziŃiei anterioare?
SELECT (PRET_VANZARE _VHS+ PRET_VANZARE _DVD) *
0.0825 AS TAX
FROM FILM
WHERE TITLU_FILM = 'The Last Samurai';
• Care este costul mediu pentru o copie a filmului The Last Samurai?
SELECT (PRET_VANZARE_VHS+PRET_VANZARE _DVD) / 2
AS AVG_COST
FROM FILM
WHERE TITLU_FILM = 'The Last Samurai'

14
FuncŃii SQL elementare

O funcŃie este un tip special de program, care returnează o singură


valoare de fiecare data când este apelată. Termenul provine de la
conceptul matematic al unei funcŃii. În SQL, funcŃiile necesită
întotdeauna specificarea unei expresii, care deseori include numele unei
coloane. Cel mai des, funcŃiile sunt folosite în lista de coloane a unei
instrucŃiuni SELECT, sunt apelate pentru fiecare rând prelucrat de
interogare şi, ca urmare, returnează o singură valoare pentru fiecare rând
din setul de rezultate. Uneori este folosit termenul funcŃie de coloană,
pentru a indica faptul că o funcŃie este aplicată unei coloane dintr-un tabel
sau o vizualizare. Un număr de funcŃii sunt furnizate de producătorul
DBMS şi se pot scrie propriile funcŃii, folosind un limbaj special livrat
împreună cu sistemul DBMS, cum ar fi PL/SQL pentru Oracle sau
Transact SQL pentru Microsoft SQL Server şi Sybase Adaptive Server.
AtenŃie la folosirea funcŃiilor SQL în condiŃiile WHERE. În cele
mai multe situaŃii, pentru o coloană căreia îi este aplicată o funcŃie nu
poate fi folosită indexarea. Ca urmare, în cazul tabelelor mari, utilizarea
funcŃiilor în condiŃiile WHERE poate duce la probleme de performanŃă cu
adevărat memorabile.
FuncŃiile pot fi clasificate în multe moduri, dar majoritatea
specialiştilor le împart după ceea ce fac.

FuncŃii pentru caractere

FuncŃiile pentru caractere sunt numite astfel deoarece manipulează


date de tip text.

Concatenarea şirurilor de caractere


FuncŃia de concatenare a şirurilor de caractere reuneşte mai multe
şiruri de caractere pentru a forma o singură valoare în rezultatele
interogării. FuncŃia standard de concatenare a şirurilor de caractere din
SQL este apelată cu două bare verticale (||), dar există şi excepŃii, cum ar
fi Microsoft SQL Server, care foloseşte semnul plus (+) pentru
concatenarea şirurilor de caractere.
Exemple de concatenare a şirurilor de caractere:
• Magazinul de produse video vrea să trimită fiecărui client o
scrisoare care începe cu formula "Client", plus prenumele şi
numele persoanei. Numele sunt stocate în tabelul PERSON. SoluŃia
acestei cerintŃe în Oracle:
SELECT 'Client' || NUME_PERSOANA||
' ' || NUME_FAMILIE_PERSOANA AS SALUT_CLIENT
FROM PERSOANA;

15
Aceeaşi soluŃie, modificată pentru a funcŃiona în Microsoft SQL
Server :
SELECT ‚Client' + NUME_PERSOANA +
' ' + NUME_FAMILIE_PERSOANA AS SALUT_CLIENT
FROM PERSOANA;
<nume angajat> castiga <salariu> lunar, dar doreste <salariu de 3
ori mai mare>
SELECT last_name||'castiga'||salary||'lunar, dar doreste'||salary*3 "salariul
ideal"
FROM employees;

UPPER
FuncŃia UPPER este deseori folosită în condiŃiile WHERE.
FuncŃia UPPER transformă literele dintr-un şir de caractere în litere mari.
Numerele şi caracterele speciale sunt lăsate ca stare.
Exemple:
• Să se afişeze comediile (COD_GEN_FILM = 'Comdy') scriind
titlurile cu majuscule.
SELECT UPPER(TITLU_FILM) AS TITLU_FILM
FROM FILM
WHERE COD_GEN_FILM = 'Comdy';

• Să presupunem că nu vă amintiŃi dacă valorile COD_GEN_FILM


au fost stocate cu litere mari, litere mici sau combinaŃii ale
acestora. Dacă în condiŃia WHERE transformaŃi valorile în litere
mari, puteŃi obŃine rezultatele corecte indiferent de modul de
stocare.
SELECT UPPER(TITLU_FILM) AS TITLU_FILM
FROM FILM
WHERE UPPER(COD_GEN_FILM) = 'COMDY';

LOWER
FuncŃia LOWER este inversa funcŃiei UPPER — transformă
literele dintr-un * de caractere în litere mici.
Exemple de utilizare a funcŃiei LOWER:
• Să se afişeze comediile (GEN_COD_FILM = 'Comedy') scriind
titlurile cu minuscule.
SELECT LOWER(TITLU_FILM) AS TITLU_FILM
FROM FILM
WHERE GEN_COD_FILM = 'Comedy';

16
• Se poate folosi funcŃia LOWER într-o clauză WHERE, atunci când
nu ştiti sigur ce tip de litere obŃine textul pe care vreŃi să-1
comparaŃi. AfişaŃi toate filmele care au în titlu cuvântul „of ",
indiferent dacă este scris cu litere mari sau mici.
SELECT TITLU_FILM
FROM FILM
WHERE LOWER(TITLU_FILM) LIKE ' % of %'
OR LOWER(TITLU_FILM) LIKE 'of % '
OR LOWER(TITLU_FILM) LIKE ' % of ';

SUBSTR

FuncŃia SUBSTR apare în majoritatea implementărilor SQL, dar


uneori are un nume puŃin diferit. De exemplu, funcŃia se numeşte
SUBSTRING în Microsoft SQL Server, Sybase Adaptive Server şi
MySQL, dar SUBSTR în Oracle şi D132. FuncŃia returnează o porŃiune a
şirului de caractere, în funcŃie de parametrii furnizaŃi, care specifică
numele coloanei, poziŃia de început a subşirului în datele coloanei şi
lungimea subşirului returnat (numărul de caractere). Deşi este o utilizare
mai puŃin obişnuită, funcŃia SUBSTR acceptă şi un şir de caractere literal
în locul numelui unei coloane. Iată forma generală a funcŃiei, urmată de
un exemplu:
SUBSTR (numele coloanei, poziŃia de început, lungimea subşirului
• În tabelul PERSON, unele persoane au al doilea nume în întregime,
alŃii au numai initiale. Afişati numele complet al persoanelor al
căror nume de familie începe cu litera „B", sub forma unui singur
şir de caractere care conŃine prenumele, iniŃiala şi numele de
familie.

SELECT NUME_PERSOANA || ' ' ||


SUBSTR(PRENUME_PERSOANA, 1, 1) || ' . ' ||
NUME_FAMILIE_PERSOANA AS NUME_INTREG
FROM PERSOANA
WHERE SUBSTR(NUME_FAMILIE_PERSOANA, 1, 1)='B'

ObservaŃi folosirea funcŃiei SUBSTR în clauza WHERE pentru a


elimina din rezultate persoanele al căror nume de familie nu începe cu
litera „B". Ar trebui să vă puteŃi deja gândi la alte moduri de a face acest
lucru, prin folosirea operatorului LIKE.

17
LENGTH

FuncŃia LENGTH returnează lungimea unui şir de caractere.


Microsoft SQL Server şi Sybase Adaptive Server folosesc numele LEN
pentru versiunea proprie a acestei funcŃii.
Exemple:
• Să se afişeze lungimea titlului pentru filmul a cărui valoare
ID_FILM este 1. Presupunem că folosiŃi o bază de date oracle,
DB2 sau MySQL.

SELECT TITLU_FILM, LENGTH (TITLU_FILM) AS LENGTH
FROM FILM
WHERE ID_FILM = 1;

SELECT TITLU_FILM, LENGTH (TITLU_FILM) AS LENGTH
FROM FILM
WHERE LENGTH (TITLU_FILM) < 10;

FunŃii matematice
FuncŃiile matematice manipulează valori numerice, în conformitate
cu regulile matematicii.

ROUND
FuncŃia ROUND rotunjeşte o valoare la un număr specificat
de zecimale. Valoarea numerică este furnizată prin primul parametru, iar
numărul de zecimale prin cel de-al doilea. În continuare este prezentat
formatul general al funcŃiei ROUND.
ROUND (expresie numerică, număr de poziŃii zecimale)
• Care este costul mediu al unei copii a filmului The Last Samurai,
rotunjit la două zecimale?
SELECT ROUND((PRET_VANZARE_VHS +
PRET_VANZARE _DVD) / 2, 2) AS AVG_COST
FROM FILM
WHERE TITLU_FILM = 'The Last Samurai';

Alte funcŃii matematice


Tabelul care urmează prezintă funcŃiile matematice cel mai
des întâlnite. Pentru toate, sintaxa generală este aceeaşi:
NUME_FUNCTIE (expresie)

18
FuncŃie Descriere
ABS Valoarea absolută a unui număr dat
COS Cosinusul trigonometric al unui unghi specificat în radiani
EXP Valoarea exponenŃială a unui număr dat
POWER Ridică un număr la o putere (numărul şi puterea sunt fumizate
ca parametri)
SIN Sinusul trigonometric al unui unghi specificat în radiani
TAN Tangenta trigonometrică a unui unghi specificat în radiani

FuncŃii de conversie
FuncŃiile de conversie transformă date dintr-un tip de date în altul.

CAST
FuncŃia CAST transformă date dintr-un tip de date în altul. Iată
sintaxa generală a funcŃiei CAST, urmată de un exemplu:
CAST (expresie AS tip de date)
• Afişati preŃul pentru formatul DVD al filmului The Last Samurai,
cu un simbol dolar în faŃa sumei. Valoarea numerică trebuie să fie
convertită într-un şir de caractere pentru a putea fi concatenată cu o
valoare literală conŃinând simbolul dolar.
SELECT '$' || CAST(PRET_VANZARE _DVD AS
VARCHAR(6)) AS PRET
FROM FILM
WHERE TITLU_FILM = 'The Last Samurai';

FuncŃii de agregare şi gruparea rândurilor


O funcŃie de agregare (aggregate functions) este o funcŃie care
combină mai multe rânduri de date într-un singur rând. Tabelul următor
prezintă funcŃiile de agregare acceptate în majoritatea implementărilor
SQL:

FuncŃie Descriere
AVG Calculează valoarea medie pentru o coloană sau o
expresie.
COUNT Numără valorile dintr-o coloană.
MAX Găseşte valoarea maxină dintr-o coloană.
MIN Găseşte valoarea minimă dintr-o coloană.
SUM Însumează valorile dintr-o coloană.
Exemple:
• Care este preŃul mediu al unui DVD?

19
SELECT ROUND(AVG(PRET_VANZARE _DVD),2) AS
AVG_PRET
FROM FILM;
• Câte filme există în tabelul FILM?
SELECT COUNT(*) AS NUM_FILM
FROM FILM;
• Câte genuri diferite de filme sunt reprezentate în tabelul FILM?
SELECT COUNT(DISTINCT COD_GEN_FILM) AS NUM_GEN
FROM FILM;
• Care sunt lungimea minimă şi maximă a titlurilor filmelor?
SELECT MIN(LENGTH(TITLU_FILM)) AS MIN_LENGTH,
MAX(LENGTH(TITLU_FILM)) AS MAX_LENGTH
FROM FILM;

Clauza GROUP BY

GROUP BY cere sistemului DBMS să grupeze rândurile selectate


de interogare pe baza valorilor din una sau mai multe coloane şi să aplice
funcŃia (sau funcŃiile) de agregare fiecărui grup, returnând un rând pentru
fiecare grup din setul de rezultate.
Sistemul DBMS va ordona rândurile selectate de interogare după
coloanele din clauza GROUP BY, aşa că grupurile vor fi returnate în
ordine ascendentă, exceptând cazul în care se adăugă o clauză ORDER
BY care specifică un alt mod de ordonare.
Iată un exemplu:
• Afişati fiecare cod de gen, împreună cu numărul de filme asociate
fiecărui cod.
SELECT COD_GEN_FILM AS GEN, COUNT(*) AS COUNT
FROM FILM
GROUP BY COD_GEN_FILM;
Ce se întâmplă dacă scoateŃi clauza GROUP BY din această
interogare? Sistemul DBMS retumează un mesaj de eroare şi, din
nefericire, mesajul de eroare este deseori destul de criptic. Functia
COUNT(*) este o functie de agregare şi, în absenta clauzei GROUP BY,
retumează un singur rând de date.
Exemplele care urmează arată modul general de constituire a
subansamblelor virtuale folosind clauza GROUP BY. Fiecare expresie
care apare în SELECT trebuie să aibă aceeaşi valoare pentru toate liniile
care aparŃin aceleiaşi partiŃii. Numele coloanelor din GROUP BY nu
trebuie să figureze obligatoriu în lista de la SELECT.
Clauza WHERE are prioritate fata de GROUP BY. Nu se poate
utiliza alias de coloana in clauza GROUP BY.

20
Pentru a returna informatie corespunxatoare fiecarui grup, pot fi
utilizate functiile agregat. Acestea pot aparea in clauzele SELECT,
ORDER BY si HAVING. Se poate utiliza functie grup in clauza WHERE?
Este corect …WHERE AVG(sal) > 200? NU!
Cand se utilizeaza GROUP BY, server-ul sorteaza implicit
multimea rezultata in ordinea crescatoare a valorilor coloanelor dupa care
se realizeaza gruparea.
Grupurile sunt formate si functiile grup sunt calculate, inainte ca
clauza HAVING sa fie aplicata grupurilor.
Exemplu:
Să se obŃină numărul de câte ori a fost împrumutată fiecare carte.
SELECT codel, COUNT(*)
FROM imprumuta
GROUP BY codel;
Exemplu:
Pentru fiecare domeniu de carte să se obŃină numărul cărŃilor din
domeniu, media preŃurilor şi numărul total de exemplare.
SELECT coded,COUNT(*), AVG(pret),SUM(nrex)
FROM carte
GROUP BY coded;
Dacă în comanda SELECT apar atribute coloană (nu funcŃii grup) şi
se utilizează clauza GROUP BY atunci aceste coloane trebuie obligatoriu
să apară în clauza GROUP BY.
Exemplu:
Să se obŃină pentru fiecare autor, media preŃurilor cărŃilor din
bibliotecă.
SELECT autor, AVG(pret)
FROM carte
GROUP BY autor;
Exemplu:
Pentru departamentele în care salariul maxim depăşeşte 5000$ să
se obŃină codul acestor departamente şi salariul maxim pe departament.
SELECT deptno, MAX(sal)
FROM emp
GROUP BY deptno
HAVING MAX(sal)>5000;

21
Exemplu:
SELECT MAX(AVG(pret))
FROM carte
GROUP BY autor;
Exemplu:
Să se afişeze numele şi salariul celor mai prost plătiŃi angajaŃi
din fiecare departament.
SELECT ename, sal
FROM emp
WHERE (deptno, sal) IN
(SELECT deptno, MIN(sal)
FROM emp
GROUP BY deptno);
Exemplu:
Să se obŃină pentru fiecare carte, codul său şi numărul de
exemplare care nu au fost încă restituite.
SELECT codel, COUNT(*)
FROM imprumuta
WHERE dataef IS NULL
GROUP BY codel;
Exemplu:
Să se obŃină numărul cărŃilor împrumutate cel puŃin o dată.
SELECT COUNT(DISTINCT codel)
FROM imprumuta;
Exemplu:
Să se afişeze numărul cărŃilor împrumutate cel puŃin de două ori
(pentru fiecare carte împrumutată mai mult decât o dată să se obŃină
numărul de câte ori a fost împrumutată).
SELECT COUNT(COUNT(codel))
FROM imprumuta
GROUP BY codel
HAVING COUNT(*)>1;

22
În cererea anterioară COUNT(codel), reprezintă numărul care arată
de câte ori a fost împrumutată fiecare carte, iar COUNT(COUNT(codel)),
reprezintă numărul total al cărŃilor împrumutate.
Exemplu:
Pentru fiecare departament codul dep si numarul de angajati.
1 select department_id, count(*)
2 from employees
3* group by department_id
SQL> /

DEPARTMENT_ID COUNT(*)
------------- ----------
10 1
20 2
30 6
40 1
50 45
60 5
70 1
80 34
90 3
100 6
110 2
1
12 rows selected.
Pentru departamentele cu mai mult de un angajat se afiseaza codul dep si
numarul de angajati.
1 select department_id, coun
2 from employees
3 group by department_id
4* having count(*)>1
SQL> /

DEPARTMENT_ID COUNT(*)
------------- ----------
20 2
30 6
50 45
60 5
80 34
90 3

23
100 6
110 2

8 rows selected.
Se afiseaza numarul departamentelor cu mai mult de un angajat.

1 select count(count(*))
2 from employees
3 group by department_id
4* having count(*)>1
SQL> /

COUNT(COUNT(*))
---------------
8

Exemplu:
Sa se afiseze numărul de cărŃi imprumutate din fiecare domeniu.
SELECT d.intdom, COUNT(*)
FROM domeniu d, carte c, imprumuta I
WHERE c.codel = i. codel
AND c.coded = d.coded
GROUP BY intdom;

Exemplu:
Lista codurilor cititorilor care au mai mult de 3 cărŃi nerestituite la
termen.
SELECT codec
FROM imprumuta
WHERE dataef IS NULL AND datares < SYSDATE
GROUP BY codec
HAVING COUNT(*) > 2;
Exemplu:
Pentru fiecare domeniu de carte care conŃine cel puŃin o carte şi
unde preŃul oricărei cărŃi nu depăşeşte o valoare dată, să se obŃină: codul
domeniului, numărul cărŃilor din domeniu şi numărul mediu de
exemplare.
SELECT coded, COUNT(*), AVG(nrex)
FROM carte
GROUP BY coded

24
HAVING COUNT(*) >= 1
AND MAX(pret) < &pret_dat;
Exemplu:
Codurile domeniilor care nu contin carti.
SELECT coded
FROM carte
GROUP BY coded
HAVING COUNT(*) = 0;
Nu este corect, deoarece se iau in considerare NUMAI codurile
domeniilor care apar in tabelul CARTE.
SELECT intdom
FROM domeniu d
WHERE 0 = (SELECT COUNT(*)
FROM carte
WHERE coded = d.coded);
Urmatoarea cerere este corecta?
SELECT intdom
FROM domeniu d,(SELECT coded, COUNT(*) a
FROM carte
GROUP BY coded) b
WHERE b.coded = d.coded)
AND b.a = o;
Exemplu:
În ce interogări este necesară utilizarea cuvântului cheie
HAVING?
A. când este necesar să eliminăm linii duble din rezultat;
B. când este necesar să ordonăm mulŃimea rezultat;
C. când este necesar să efectuăm un calcul pe grup;
D. când este necesar să restricŃionăm grupurile de linii returnate.

Operatori pentru interogări compuse


Uneori este util să se ruleze interogări multiple şi să se combine
rezultatele într-un singur set de rezultate.

UNION
Operatorul UNION adaugă rândurile din setul de înregistrări al
unei interogări la cel al unei alte inregistrări şi, în acelaşi timp, elimină
rândurile duplicate, într-un mod similar cu cel al cuvântului cheie

25
DISTINCT. OperaŃia este permisă numai dacă interogările sunt
compatibile din punctul de vedere al uniunii, ceea ce înseamnă că au
acelaşi număr de coloane şi că tipurile de date ale coloanelor
corespondente sunt compatibile.
Iată un exemplu:
• AfişaŃi pe o singură coloană toate valorile nenule pentru taxa de
inchiriere şi taxa de întârziere din tabelul FILM_ÎNCHIRIAT.
SELECT INCHIRIAT_FEE AS FEE
FROM FILM_INCHIRIAT
WHERE INCHIRIAT _FEE IS NOT NULL
UNION
SELECT LATE_OR_LOSS_FEE AS FEE
FROM FILM_INCHIRIAT
WHERE LATE _OR_ LOSS FEE IS NOT NULL;

UNION ALL
UNION ALL funcŃionează la fel ca şi operatorul UNION,
exceptând faptul că rândurile duplicate nu sunt eliminate.

INTERSECT
Operatorul INTERSECT găseşte valorile selectate dintr-o
interogare, care apar şi într-o altă interogare. În esenŃă, găseşte intersecŃia
valorilor din cele două interogări. Totuşi, doar un număr mic de sisteme
DBMS (cele mai importance fiind Oracle şi DB2) implementează acest
operator. Nu-1 veŃi găsi în Microsoft SQL Server sau MySQL.
Iată un exemplu:
• Există în tabelul FILM filme pentru care preŃul pentru DVD este
egal cu preŃul pentru VHS?
SELECT INCHIRIAT_FEE AS FEE
FROM FILM_ INCHIRIAT
WHERE INCHIRIAT _FEE IS NOT NULL
INTERSECT
SELECT LATE_OR_LOSS_FEE AS FEE
FROM FILM_ INCHIRIAT
WHERE LATE OR_ LOSS FEE IS NOT NULL

EXCEPT
EXCEPT este operatorul standard ANSI/ISO care găseşte
diferenŃele dintre două seturi de rezultate, returnând, în esenŃă, valorile

26
din prima interogare care nu apar în cea de-a doua interogare. Foarte
puŃine sisteme DBMS implementează acest operator. În unele
implementări, precum Oracle, operatorul se numeşte MINUS, nu
EXCEPT.

27
Cereri multi – relaţie
Comanda SELECT oferă posibilitatea de a consulta informaţii care provin
din mai multe tabele. Operatorii care intervin în astfel de cereri pot fi:
operatori pe mulţimi (UNION, UNION ALL, INTERSECT, MINUS);
operatori compunere care implementează diferite tipuri de JOIN.
Există două moduri de realizare a cererilor multi-relaţie:
forma procedurală, în care trebuie indicat drumul de acces la informaţie
prin imbricarea de comenzi SELECT;
forma relaţională, în care drumul de acces la informaţie este în sarcina
sistemului.
Exemplu:
Să se obţină, utilizând aceste două forme, codurile şi titlurile cărţilor
împrumutate.
a) Forma procedurală (imbricare de comenzi SELECT):
SELECT codel, titlu
FROM carte
WHERE codel IN (SELECT DISTINCT codel
FROM imprumuta);
b) Forma relaţională:
SELECT carte.codel, titlu
FROM carte, imprumuta
WHERE carte.codel = imprumuta.codel;

Operatori pe mulţimi sau Operatori pentru interogări


compuse (UNION, UNION ALL, INTERSECT, MINUS)

Uneori este util să se ruleze interogări multiple şi să se combine rezultatele


într-un singur set de rezultate.
Operatorii pe mulţimi combină rezultatele obţinute din două sau mai multe
interogări. Cererile care conţin operatori pe mulţimi se numesc cereri compuse.
Există patru operatori pe mulţimi: UNION, UNION ALL, INTERSECT şi
MINUS(în unele implementeri oracle operatorul MINUS se numeşte EXCEPT).
Toţi operatorii pe mulţimi au aceeaşi precedenţă. Dacă o instrucţiune SQL
conţine mai mulţi operatori pe mulţimi, server-ul Oracle evaluează cererea de la
stânga la dreapta (sau de sus în jos). Pentru a schimba această ordine de evaluare,
se pot utiliza paranteze.
În mod implicit, pentru toţi operatorii cu excepţia lui UNION ALL, rezultatul
este ordonat crescător după valorile primei coloane din clauza SELECT.
Pentru o cerere care utilizează operatori pe mulţimi, cu excepţia lui UNION
ALL, server-ul Oracle elimină liniile duplicat.
În instrucţiunile SELECT asupra cărora se aplică operatori pe mulţimi,
coloanele selectate trebuie să corespundă ca număr şi tip de date. Nu este necesar
ca numele coloanelor să fie identice. Numele coloanelor din rezultat sunt
determinate de numele care apar în clauza SELECT a primei cereri.
În cazul în care cererile componente selectează date de tip caracter, tipul
de date al valorii returnate poate fi CHAR, dacă valorile selectate de ambele
cereri sunt de tip CHAR, sau VARCHAR2, dacă valorile selectate de cel puţin
una din cele două cereri sunt de tip VARCHAR2.

Observaţii:
Comenzile SELECT, care intervin în cereri ce conţin operatori pe mulţimi,
trebuie să satisfacă anumite condiţii:
toate comenzile SELECT trebuie să aibă acelaşi număr de coloane;
opţiunea DISTINCT este implicită (excepţie UNION ALL);
numele coloanelor sunt cele din prima comandă SELECT;
dimensiunea coloanei implicit este cea mai mare dintre cele două coloane;
sunt admise combinaţii de forma:
1. SELECT1 UNION SELECT2 INTERSECT SELECT3 şi ordinea de
execuţie este de la stânga la dreapta;
2. SELECT1 UNION (SELECT2 INTERSECT SELECT3) şi ordinea
este dată de paranteze.

UNION

Operatorul UNION adaugă rândurile din setul de înregistrări al unei


interogări la cel al unei alte interogări şi, în acelaşi timp, elimină rândurile
duplicate, într-un mod similar cu cel al cuvântului cheie DISTINCT.
Operatorul UNION returnează deci toate liniile selectate de două cereri,
eliminând duplicatele. Operaţia este permisă numai dacă interogările sunt
compatibile din punctul de vedere al uniunii, ceea ce înseamnă că au acelaşi număr
de coloane şi că tipurile de date ale coloanelor corespondente sunt compatibile.
Acest operator nu ignoră valorile null şi are precedenţă mai mică decât operatorul
IN.
Exemplu:
Să se afişeze pe o singură coloană toate valorile nenule pentru taxa de
inchiriere şi taxa de întârziere din tabelul FILM_ÎNCHIRIAT.
SELECT taxa_inchiriat AS TAXA
FROM FILM_INCHIRIAT
WHERE taxa_inchiriat IS NOT NULL UNION
SELECT taxa_intarziere AS TAXA
FROM FILM_INCHIRIAT
WHERE taxa_intarziere IS NOT NULL;

Exemplu:
Să se afişeze codurile operelor de artă pentru care a fost încheiată o poliţă
de asigurare sau care beneficiază de un sistem de securitate. Fiecare cod va fi
afişat o singură dată.
SELECT cod_opera
FROM polita_asig
UNION
SELECT cod_opera
FROM securitate;

Uneori, pentru a respecta regula conform căreia expresiile din clauzele


SELECT trebuie să concorde ca număr şi tip de date, se pot utiliza coloane
artificiale şi funcţii de conversie pentru tipurile de date.

Exemplu:
Să se listeze codul operelor de artă, codul şi numele artiştilor.
SELECT cod_opera, cod_artist, TO_CHAR(null) nume
FROM opera
UNION
SELECT TO_NUMBER(null), cod_artist, nume
FROM artist;

UNION ALL
Operatorul UNION ALL funcţionează la fel ca şi operatorul UNION,
exceptând faptul că rândurile duplicate nu sunt eliminate.
Precizările făcute asupra operatorului UNION sunt valabile şi în cazul
operatorului UNION ALL. În cererile asupra cărora se aplică UNION ALL nu poate
fi utilizat cuvântul cheie DISTINCT.
Exemplu:
Să se determine codul operelor de artă pentru care s-a încheiat o poliţă de
asigurare sau pentru care s-a achiziţionat un sistem de securitate. Să se afişeze
firma şi data contractării, respectiv a instalării sistemului. Întrucât o operă poate
avea mai multe poliţe de asigurare sau mai multe sisteme de securitate
încheiate, respectiv instalate la aceeaşi firmă şi dată, nu se vor suprima liniile
duplicat. Rezultatul va fi ordonat după codul operelor.
SELECT cod_opera, firma, semnat_contract
FROM polita_asig
UNION ALL
SELECT cod_opera, firma, data_inst
FROM polita_asig
ORDER BY cod_opera;

Clauza ORDER BY poate apărea numai o singură dată într-o cerere compusă.
Dacă se utilizează, clauza trebuie plasată la sfârşitul cererii şi acceptă nume de
coloane, alias-uri sau notaţia poziţională. Numele de coloane şi alias-urile din
clauza ORDER BY trebuie să fie din lista SELECT a primei instrucţiuni.

INTERSECT
Operatorul INTERSECT găseşte valorile selectate dintr-o interogare, care
apar şi într-o altă interogare. În esenţă, găseşte intersecţia valorilor din cele două
interogări. Acest operator nu ignoră valorile null.
Totuşi, doar un număr mic de sisteme DBMS (cele mai importance fiind
Oracle şi DB2) implementează acest operator. Nu-1 veţi găsi în Microsoft SQL
Server sau MySQL.

Exemplu:

Există în tabelul FILM filme pentru care preţul pentru DVD este egal cu
preţul pentru VHS?
SELECT taxa_inchiriat AS TAXA
FROM FILM_INCHIRIAT
WHERE taxa_inchiriat IS NOT NULL
INTERSECT
SELECT taxa_intarziere AS TAXA
FROM FILM_INCHIRIAT
WHERE taxa_intarziere IS NOT NULL;
Exemplu:

Să se afişeze codul operelor de artă, respectiv data la care s-a încheiat o


poliţă de asigurare şi s-a instalat un sistem de securitate.
SELECT cod_opera, semnat_contract
FROM polita_asig
INTERSECT
SELECT cod_opera, data_inst
FROM securitate;

Exemplu:

Să se obţină, utilizând operatorul INTERSECT, codurile cărţilor din care sunt


mai puţin de 15 exemplare şi care au fost împrumutate de cel puţin trei ori.
SELECT codel
FROM carte
WHERE nrex < 15
INTERSECT
SELECT codel
FROM imprumuta
GROUP BY codel
HAVING COUNT(*) > 3;

MINUS

Operatorul MINUS sau EXCEPT găseşte diferenţele dintre două seturi de


rezultate, returnând, în esenţă, valorile din prima interogare care nu apar în cea de-
a doua interogare. Pentru ca operatorul MINUS să funcţioneze, este necesar ca
toate coloanele din clauza WHERE să se afle şi în clauza SELECT. Foarte puţine
sisteme DBMS implementează acest operator. În unele implementări, precum
Oracle, operatorul se numeşte MINUS, nu EXCEPT.

Exemplu:
Să se determine codul şi valoarea operelor de artă al căror preţ nu este de
20 de ori mai mare decât valoarea poliţei de asigurare.
SELECT cod_opera, valoare
FROM opera
MINUS
SELECT cod_opera, valoare*20
FROM polita_asig;
Exemplu:
Să se afişeze codurile cititorilor care nu au împrumutat cărţi.
SELECT codec
FROM cititor
MINUS
SELECT DISTINCT codec
FROM imprumuta;

Operatorii pe mulţimi pot fi utilizaţi în subcereri. Coloanele care apar în


clauza WHERE a interogării trebuie să corespundă, ca număr şi tip de date, celor
din clauza SELECT a subcererii.

Exemplu:

Să se determine codul operelor de artă, codul autorilor şi titlul pentru


operele a căror valoare este mai mare decât 5000 sau pentru cele având valoarea
de 20 de ori mai mare decât cea a poliţei de asigurare.
SELECT cod_opera, cod_artist, titlu
FROM opera
WHERE (cod_opera, valoare)
IN (SELECT cod_opera, valoare
FROM opera
WHERE valoare > 5000
UNION
SELECT cod_opera, valoare*20
FROM polita_asig);
Operaţia de compunere (JOIN)

S-au prezentat până acum instrucţiuni SQL care selectează date dintr-un
singur tabel. Deseori, este util să se combine date din tabele multiple într-o singură
interogare. De exemplu, în listingul celor trei coloane ale tabelului FILM din
figura următoare, observaţi valorile afişate pentru coloană FILM_GEN_COD.
Atunci când s-a proiectat baza de date pentru magazinul de produse video, s-au
folosit coduri în locul descrierilor complete pentru genurile filmelor în tabelul
FILM. Din discuţia despre procesul de normalizare, s-a evitat anomalia de
actualizare – dacă se schimbă descrierea unui gen, nu este nevoie să actualizăm
acea descriere pentru toate filmele asociate genului respectiv în tabelul FILM. În
timpul normalizării, descrierea genurilor a fost mutată în tabelul, FILM_GEN, iar
coloană FILM_GEN_COD a devenit cheie externă în tabelul FILM, referind
coloană cheie primară (cu acelaşi nume) din tabelul FILM_GEN. S-a optat pentru
folosirea unui cod mnemonic pentru codurile genurilor.

Tabelul FILM (trei coloane)


FILM_COD FILM_GEN_COD FILM_TITLU
1 Drama Mystic River
2 ActAd The Last Samurai
3 Comedie Something's Gotta Grve
4 ActAd The Italian
5 ActAd Kill Bill: Voi. 1
6 ActAd Pirates of the Caribbean: Trie Curse of the Black Pearl
7 Drama Big Fish
8 ActAd Man on Fire
9 ActAd Master and Commander The Far Side of the World
10 Drama LosI în Translation
11 Rmce Two Weeks Notice
12 Comedie 50 First Dates
13 Comedie Matchstick Men
14 Drama Cold Mountain
15 Drama Road to Perdition
16 Comedie The School of Rock
17 Rmce 13 Going on30
18 Drama Monster
19 ActAd The Day After Tomorrow
20 Forgn Das Boot
Evident, nu puteţi afişa pe pagina web a magazinului de produse video,
tabelul FILM aşa cum este prezentat în figura de mai sus - trebuie să obţineţi
descrierea completă a genurilor din tabelul FILM_GEN. Aceasta este ideea
capitolului de faţă: combinarea datelor din mai multe tabele într-o singură
interogare. Figura următoare prezintă un listing al tabelului FILM_GEN.

Tabelul FILM_GEN

FILM_GEN_COD FILM_GEN_DESCRIERE
ActAd Actiune
Anime Animatie
ChFam Copii şi Familie
Class Clasic
Comedie Comedie
Doc Documentar
Drama Drama
Forgn Strain
Hor Horror
Indep Independent
Music Muzical
Rmce Romance(Romantic, Idila)
SciFi Stiintifico-Fantastic
Sport Sport
Thriller Groaza

Uniuni (join)

O uniune (join) este o operaţie într-o bază de date relaţionale care combină
coloane din două sau mai multe tabele în rezultatele unei singure interogări. O
uniune apare de fiecare dată când clauza FROM a unei instrucţiuni SELECT
specifică numele mai multor tabele.
De exemplu:
SELECT FILM_ID, FILM_GEN_DESCRIERE AS GEN, FILM_TITLU
FROM FILM, FILM_GEN
ORDER BY FILM_ID;
FILM_ID GEN FILM_TITLU
1 Actiune şi Aventura Mystic River
1 Animatie Mystic River
1 Clasic Mystic River
1 Documentar Mystic River
1 Strain Mystic River
1 Independent Mystic River
1 Groaza Mystic River
1 Sport Mystic River
1 SF Mystic River
1 Musical Mystic River
1 Horror Mystic River
1 Drama Mystic River
1 Comedie Mystic River
1 Copii şi Familie Mystic River
1 Actiune şi Aventura The Last Samurai
2 Thriller The Last Samurai
2 Sport The Last Samurai
2 SF The Last Samurai
2 Romantic The Last Samurai
2 Musical The Last Samurai
2 Independent The Last Samurai
2 Horror The Last Samurai
2 Animatie The Last Samurai
2 Copii şi Familie The Last Samurai
2 Documentar The Last Samurai
2 Strain The Last Samurai
2 Drama The Last Samurai
2 Comedie The Last Samurai
2 Clasic The Last Samurai
.. ... ...............
Setul de rezultate al interogării a fost trunchiat după primele două titluri de
filme. Problema este că am cerut bazei de date să unească tabelele, dar nu i-am
spus care este corespondenţa dintre rândurile celor două tabele. Rezultatul este
cunoscut sub numele de produs cartezian (după numele filozofului şi
matematicianului francez Rene Descartes) şi, în bazele de date relaţionale, este un
set de rezultate obţinut prin uniunea dintre fiecare rând al unui tabel cu fiecare rând
dintr-un alt tabel.
Soluţia este să specificăm cum se va face unirea tabelelor. Trebuie indicat ce
coloane ar trebui să se potrivească pentru a uni două rânduri din cele două tabele,
în mod normal, cele două coloane vor fi cheia primară dintr-un tabel şi cheia
externă din celălalt tabel, dar pot există şi excepţii. Pentru a realiza acest lucru
trebuie să se facă o o uniune standard relaţională, cunoscut şi sub numele de
uniune de egalitate (equijoin).

Join-ul este operaţia de regăsire a datelor din două sau mai multe tabele, pe
baza valorilor comune ale unor coloane. De obicei, aceste coloane reprezintă cheia
primară, respectiv cheia externă a tabelelor.
Condiţia de join se scrie în clauza WHERE a instrucţiunii SELECT. Într-o
instrucţiune SELECT care uneşte tabele prin operaţia de join, se recomandă ca
numele coloanelor să fie precedate de numele tabelelor pentru claritate şi
pentru îmbunătăţirea timpului de acces la baza de date. Dacă acelaşi nume de
coloană apare în mai mult de două tabele, atunci numele coloanei se prefixează
obligatoriu cu numele tabelului corespunzător. Pentru a realiza un join între n
tabele, va fi nevoie de cel puţin n – 1 condiţii de join.
Equijoin-ul corespunde situaţiei în care valorile de pe coloanele ce apar în
condiţia de join trebuie să fie egale. Un astfel de join mai poartă numele de join
simplu sau inner join. Un nonequijoin este o condiţie de join care conţine alţi
operatori decât operatorul egalitate. Un self join realizează compunerea unui tabel
cu el însuşi.

Uniuni de egalitate (equijoin)

Avem o uniune de egalitale (equijoin), numită şi uniune internă (inner join),


atunci când legăm una sau mai multe coloane dintr-un tabel (de obicei, o cheie
externă) cu coloane similare dintr-un alt tabel (de obicei, cheia primară), folosind
condiţia de egalitale, aceasta fiind cea mai des folosită formă de uniune. Totusi,
termenul uniune de egalitate (equijoin) este rareori folosit în afara mediilor
academice, find preferate denurmirile uniune internă (inner join) sau uniune
standard (standard join).
Există două modalităţi de specificare a coloanelor corespondente: folosind
clauza WHERE sau folosind clauza JOIN. Clauza JOIN a fost adăugată relativ
recent în standardul SQL, aşa că programatorii mai vechi sunt obisnuiţi cu metoda
bazată pe clauza WHERE.
Realizarea uniunilor folosind clauza WHERE

Folosirea clauzei WHERE pentru unirea tabelelor seamănă cu folosirea


acesteia pentru eliminărea rândurilor de care nu aveţi nevoie din setul de rezultate.
Totuşi, există unele diferenţe.
În clauza WHERE :
Se compară o coloană cu o altă coloană, nu o coloană cu o constantă sau o
expresie.
Atunci când coloanele din cele două tabele au acelaşi nume (o soluţie
recomandată) trebuie să specificati numele complet al coloanelor (adică numele cu
calificator), astfel încât motorul SQL să ştie care dintre cele două coloane este
referită. Motorul SQL cere să se refere toate coloanele specificate într-o
instrucţiune SQL. Aceasta nu înseamnă numai coloanele din clauza WHERE, ci
din orice alt loc al instrucţunii, inclusiv în lista SELECT. Cea mai simplă formă de
calificator este chiar numele tabelului, separat cu caracterul punct de numele
coloanei. În continuare este prezentat un exemplu de uniune realizată prin clauza
WHERE, cu numele coloanelor specificate complet, folosind numele tabelelor.
Observaţi că interogarea selectează coloanele FILM_ID şi FILM_TITLU din
tabelul FILM şi genul corespunzător (FILM_GEN_DESCRIERE) din tabelul
FILM_GEN.

SELECT FILM_ID, FILM_GEN_DESCRIERE AS GEN, FILM_TITLU


FROM FILM, FILM_GEN
WHERE FILM.FILM_GEN_COD= FILM_GEN.FILM_GEN_COD
ORDER BY FILM_ID;

FILM_ID FILM_GEN FILM_TITLU


1 Drama Mystic River
2 Actiune şi Aventura The Last Samurai
3 Comedie Something's Gotta Give
4 Actiune şi Aventura The Italian Job
5 Actiune şi Aventura Kill Bill Vol. 1
6 Actiune şi Aventura Pirates of the Caribbean
7 Drama Big Fish
8 Actiune şi Aventura Man on Fire
9 Actiune şi Aventura Master and Commander
10 Drama Lost în Translation
11 Romantic Two Weeks Notice
12 Comedie 50 First Dates
13 Comedie Matchstick Men
14 Drama Cold Mountain
15 Drama Road to Perdition
16 Comedie The School of Rock
17 Romantic 13 Going on 30
18 Drama Monster
19 Actiune şi Aventura The Day After Tomorrow
20 Strain Das Boot

Exemplu:
Să se obţină codurile şi titlurile cărţilor împrumutate.
SELECT carte.codel, titlu
FROM carte, imprumuta
WHERE carte.codel = imprumuta.codel;

Folosirea numelor complete ale tabelelor pentru specificarea coloanelor


poate fi obositoare şi consumatoare de timp, mai ales deoarece numele tabelelor
pot avea 30 sau mai multe caractere în sistemele DBMS moderne. Din această
cauză, în SQL este permisă şi folosirea pseudonimelor (aliases) pentru numele
tabelelor. Acestea funcţionează la fel ca şi pseudonimele coloanelor din clauza
SELECT, exceptând faptul că nu este folosit cuvântul cheie „AS" (în cele mai
multe implementări SQL) - doar lăsaţi un spaţiu între numele tabelului şi
pseudonim în lista FROM. Deşi unii folosesc mnemonice pentru pseudonimul
tabelelor, este mult mai des întâlnită folosirea secvenţelor de majuscule (adică „A",
„B”,”C” şi aşa mai departe). După ce se asociază un pseudonim unui nume de tabel
în clauza FROM, trebuie să folosiţi pseudonimul în locul numelui de tabel în
întreaga instrucţiune SQL. Folosirea pseudonimelor în clauza SELECT poate părea
puţin ciudată la început deoarece folosiţi un pseudonim înainte de a-l defini (clauza
SELECT precede clauza FROM şi s-ar putea să pară mai simplu să completaţi
clauza FROM înainte de a completa lista de coloane din clauza SELECT atunci
când scrieţi instrucţiunile SQL.
Exemplul următor prezintă instrucţiunea anterioară, după adăugarea
pseudonimelor pentru numele tabelelor. Deşi nu era necesar, pseudonimele au fost
adăugate şi în lista de coloane din clauzele SELECT şi ORDER BY, pentru a va
arăta cum sunt folosite.
Exemplu:
SELECT A.FILM_ID, B.FILM_GEN_DESCRIERE AS GEN, A.FILM_TITLU
FROM FILM A, FILM_GEN B
WHERE A.FILM_GEN_COD = B.FILM_GEN_COD
ORDER BY A.FILM_ID;

Exemplu:
a) Să se afişeze informaţii despre operele de artă achiziţionate în 2008 şi
galeriile în care au fost expuse.

SELECT cod_opera, titlu, o.cod_galerie, nume_galerie, adresa


FROM opera o, galerie g
WHERE o.cod_galerie = g.cod_galerie
AND TO_CHAR(data_achizitiei, 'yyyy') = '2008';

b) Să se afişeze informaţii referitoare la operele de artă, artiştii care le-au


creat şi galeriile în care sunt expuse.

SELECT cod_opera, titlu, data_crearii,


a.cod_artist, nume, prenume,
g.cod_galerie, nume_galerie, adresa
FROM opera o, galerie g, artist a
WHERE o.cod_artist = a.cod_artist
AND o.cod_galerie = g.cod_galerie;

S-ar putea ca tabelele legate prin operaţia de compunere să nu aibă coloane


comune (non-equijoin). În acest caz în clauza WHERE nu apare operatorul
egalitate şi sunt folosiţi operatorii: <=, >=, BETWEEN.
Un self join realizează compunerea unui tabel cu el însuşi.

Exemplu:

Să se obţină pentru fiecare salariat numele, salariul şi grila de salarizare (Θ


join).

SELECT e.name, e.sal, s.grade


FROM emp e, salgrade s
WHERE e.sal BETWEEN s.lasal AND s.hisal;
Exemplu:
Să se obţină titlurile şi preţurile cărţilor mai scumpe decât cartea având titlul
“Baze de date”, al cărui autor este POPA (self join).

SELECT x.titlu, x.pret


FROM carte x, carte y
WHERE x.pret > y.pret
AND y.titlu = ’Baze de date’
AND y.autor = POPA;

Realizarea uniunilor folosind clauza JOIN

Clauza JOIN este scrisă ca o referinţă de tabel din clauza FROM şi combină
lista de tabele din clauza FROM şi condiţia de legătură scrisă anterior în clauza
WHERE într-o singură clauză. Sintaxa generală a clauzei JOIN pentru o uniune
internă, urmată de câteva exemple.

Sintaxa corespunzătoare standardului SQL3 este următoarea:


SELECT tabel_1.nume_coloană, tabel_2.nume_coloană
FROM tabel_1
[CROSS JOIN tabel_2]
| [NATURAL JOIN tabel_2]
| [JOIN tabel_2 USING (nume_coloană) ]
| [JOIN tabel_2 ON (tabel_1.nume_coloană = tabel_2.nume_coloană) ]
| [LEFT | RIGHT | FULL OUTER JOIN tabel_2
ON (tabel_1.nume_coloană = tabel_2.nume_coloană) ];

Clauza ON permite specificarea unei condiţii similare cu cea din clauza


WHERE .
Clauza USING specifică numele coloanelor folosite pentru legarea
rândurilor. Totuşi, clauza USING acţionează numai atunci când coloanele pe care
se face legătură au nume identice în ambele tabele. JOIN tabel_2 USING
nume_coloană efectuează un equijoin pe baza coloanei cu numele specificat în
sintaxă. Această clauză este utilă dacă există coloane având acelaşi nume, dar
tipuri de date diferite. Coloanele referite în clauza USING trebuie să nu conţină
calificatori (să nu fie precedate de nume de tabele sau alias-uri) în nici o apariţie a
lor în instrucţiunea SQL. Clauzele NATURAL JOIN şi USING nu pot coexista în
aceeaşi instrucţiune SQL.
JOIN tabel_2 ON tabel_1.nume_coloană = tabel_2.nume_coloană
efectuează un equijoin pe baza condiţiei exprimate în clauza ON. Această clauză
permite specificarea separată a condiţiilor de join, respectiv a celor de căutare sau
filtrare (din clauza WHERE).

Exemple:
• JOIN cu condiţie ON:

SELECT FILM_ID, FILM_GEN_DESCRIERE AS GEN, FILM_TITLU


FROM FILM JOIN FILM_GEN ON
FILM.FILM_GEN_COD = FILM_GEN.FILM_GEN_COD
ORDER BY FILM_ID;

• JOIN cu pseudonime în loc de nume de tabele:

SELECT FILM_ID, FILM_GEN_DESCRIERE AS GEN, FILM_TITLU


FROM FILM A JOIN FILM_GEN B ON
A.FILM_GEN_COD = B.FILM_GEN_COD
ORDER BY FILM_ID;

• JOIN folosind cuvântul cheie USING (în locul condiţiei ON) o scurtatură
elegantă atunci când coloanele din cele două tabele au acelaşi nume (nu e
recunoscută de toate SGBD-urile).

SELECT FILM_ID, FILM_GEN_DESCRIERE AS GEN, FILM_TITLU


FROM FILM JOIN FILM_GEN USING (FILM_GEN_COD)
ORDER BY FILM_ID;

• JOIN cu cheie externă pe mai multe coloane.

Această interogare afişează lista cu copiile filmelor din tabelul FILM_COPY


care nu au fost vândute (coloană DATA_VANZARE conţine o valoare nulă dacă
nu a fost vândută) şi care au fost închiriate (uniune cu tabelul FILM_INCHIRIAT)
dar nu au fost încă returnate (coloană RETUR_DATA conţine o valoare nulă până
la returnarea filmului).
SELECT FILM_ID, COPY_NUMAR, DATA_RETURNARII
FROM FILM_COPY JOIN FILM__INCHIRIAT
USING (FILM_ID, COPY_NUMAR)
WHERE DATA_VANZARE IS NULL
AND RETUR_DATA IS NULL;

FILM _ID COPY_NUMAR DATA_RETURNARII


2 2 02/27/2009
3 2 03/04/2009
5 1 02/27/2009
5 2 02/19/2009
10 1 03/04/2009
17 1 03/04/2009

Instrucţiunile care folosesc clauza JOIN sunt mai scurte. Interogarea


precedentă scrisă folosind condiţii de legătură în clauza WHERE. Se remarcă
faptul că în acest caz trebuie specificat numele complet al coloanelor FILM_ID şi
COPY_NUMAR, pentru a evita referirea ambiguă a lor. Instrucţiunea de mai jos
afişează aceleaşi rezultate ca şi instrucţiunea anterioară.

SELECT A.FILM_ID, A.COPY_NUMAR, DATA_RETURNARII


FROM FILM_COPY A, FILM_INCH B
WHERE A.FILM_ID = B.FILM_ID
AND A.COPY_NUMAR = B.COPY_NUMAR
AND DATA_VANZARE IS NULL
AND RETURN_DATA IS NULL;

Uniuni naturale

O uniune naturală (natural join) se bazează pe toate coloanele cu acelaşi


nume din două tabele, în esenţă, toate uniunile de egalitate sunt uniuni naturale.
Totuşi, sintaxa unei uniuni naturale este mult mai simplă, deoarece nu este necesar
să specificaţi o condiţie sau o listă de coloane - se înţelege de la sine care sunt
coloanele folosite. Nu toate SGBD-urile acceptă această sintaxă pentru clauza
JOIN (accepta sigur Oracle şi MySQL ).

Exemplu: uniunea tabelelor FILM şi FILM_GEN, rescrisă sub forma unei


uniuni naturale:

SELECT FILM_ID, FILM_GEN_DESCRIERE AS GEN, FILM_TITLU


FROM FILM NATURAL JOIN FILM_GEN
ORDER BY FILM_ID;
Uniunile pot implica mai mult de două tabele. Exemplul următor prezintă o
uniune naturală care obţine coloana FILM_ID din tabelul FILM, coloana
FILM_GEN_DESCRIERE din tabelul FILM_GEN şi din tabelul
MPAA_RATING, coloana MPAA_RATING_DESCRIERE , pentru primele trei
filme din tabelul FILM. Folosirea clauzei WHERE permte să se elimine din setul
de rezultate rândurile de care nu avem nevoie.
Exemplul foloseşte două clauze JOIN. Prima clauză JOIN cere motorului
SQL să lege tabelele FILM şi FILM_GEN, iar a două clauză JOIN îi cere să lege
rândurile deja unite (în esenţă, un set de rezultate intermediar) cu tabelul
MPAA_RATING.

SELECT FILM_ID, FILM_GEN_DESCRIERE AS GEN,


MPAA_RATING_COD AS RATING, MPAA_RATING_DESCRIERE AS
RATING_DESC
FROM FILM NATURAL JOIN FILM_GEN NATURAL JOIN
MPAA_RATING
WHERE FILM_ID < 4 ORDER BY FILM_ID;

FILM_ID GEN RATING RATING_DESC

1 Drama R Sub 17 ani acompaniati de parinti

2 Acţiune si Aventura R Sub 17 ani acompaniati de parinti

3 Comedie PG-13 Cu acordul strict a parintilor

Dacă se foloseşte o implementare SQL care nu acceptă uniunile naturale,


aceeaşi interogare scrisă folosind cuvintele cheie JOIN şi ON este:

SELECT A.FILM_ID, B.FILM_GEN_DESCRIERE AS GEN,


C.MPAA_RATING__COD AS RATING,
C.MPAA_RATING__DESCRIERE AS
RATING_DESC
FROM FILM A JOIN FILM_GEN B ON
A.FILM_GEN_COD = B.FILM_GEN_COD
JOIN MPAA_RATING C ON
A.MPAA_RATING_COD = C.MPAA_RATING_COD
WHERE FILM_ID < 4 ORDER BY FILM_ID;
Exemple la schema galerii de arta
a) Să se determine titlul operelor de artă expuse în galeriile având codul 10
sau 30, respectiv numele şi prenumele artiştilor care le-au realizat.
SELECT titlu, nume, prenume
FROM opera NATURAL JOIN artist
WHERE cod_galerie IN (10, 30);

Folosind clauza USING, acest exemplu poate fi rescris astfel:


SELECT titlu, nume, prenume
FROM opera JOIN artist USING (cod_artist)
WHERE cod_galerie IN (10, 30);

Următoarea cerere va returna eroarea „ORA-25154: column part of USING


clause cannot have qualifier“, întrucât coloana specificată în clauza USING apare,
în clauza WHERE, precedată de un alias de tabel.

SELECT o.titlu, a.nume, a.prenume


FROM opera o
JOIN artist a USING (cod_artist)
WHERE a.cod_artist IN (50,60);

b) Să se afişeze titlurile operelor de artă, firmele la care sunt asigurate şi


descrierea poliţelor de asigurare corespunzătoare.
SELECT o.titlu, p.firma, p.descriere
FROM opera o JOIN polita_asig p ON
(o.cod_opera = p.cod_opera);

Uniuni externe (outer joins)

Toate uniunile pe care le-am descris până acum sunt uniuni exclusiv (uniuni
interne), ceea ce înseamnă că singurele rânduri care apar în setul de rezultate sunt
cele pentru care a fost găsită o legătură în toate tabelele unite.
Există situaţii în care se doreşte să includeţi în rezultatele interogării şi
rânduri pentru care nu există o legătură. De exemplu, dacă se doreşte o listă cu
toate genurile de filme, împreună cu toate titlurile asociate cu fiecare gen?
O uniune externă (outer join) - pentru care un nume mai potrivit ar fi uniune
inclusivă - include în setul de rezultate şi rândurile pentru care nu există legături
din cel puţin unul dintre tabele. Atunci când există rânduri fără legături, datele
selectate din tabelul în care nu a fost găsită o legătură primesc valoarea nulă.
Un outer join este utilizat pentru a obţine în rezultat şi înregistrările care nu
satisfac condiţia de join. Operatorul pentru outer join este semnul plus inclus între
paranteze (+), care se plasează în acea parte a condiţiei de join care este deficientă
în informaţie. Efectul acestui operator este de a uni liniile tabelului care nu este
deficient în informaţie şi cărora nu le corespunde nici o linie în celălalt tabel cu o
linie cu valori null. Operatorul (+) poate fi plasat în orice parte a condiţiei de join,
dar nu în ambele părţi.
O condiţie care presupune un outer join nu poate utiliza operatorul IN şi nu
poate fi legată de altă condiţie prin operatorul OR.
Exemplu:
Se presupune că tabelul artist conţine şi artişti care nu au opere expuse în
muzeu. Să se afişeze artiştii şi operele acestora, inclusiv cei care nu au opere
corespunzătoare în tabelul opera.
SELECT a.cod_artist, nume, prenume, cod_opera, titlu
FROM artist a, opera o
WHERE a.cod_artist = o.cod_artist (+);

Există trei tipuri de bază:


Uniune externă către stânga (left outer join). Returnează toate rândurile
din tabelul din stânga (cel specificat primul în clauza JOIN), împreună cu toate
rândurile din tabelul din dreapta pentru care poate fi găsită o legătură.
(asemănatoare interogărilor din tabele aflate in relaţia 1:m)
Uniune externă către dreapta (right outer join). Returnează toate rândurile
din tabelul din dreapta (cel specificat al doilea în clauza JOIN), împreună cu toate
rândurile din tabelul din stânga pentru care poate fi găsită o legătură, în esenţă, o
uniune externă către stânga poale fi rescrisă ca o uniune externă către dreapta
inversând ordinea de specificare a tabelelor şi înlocuind cuvântul cheie LEFT cu
RIGHT.
Uniune externă completă (full outer join). Returnează toate rândurile din
ambele tabele. Acest tip de uniune este cel mai puţin probabil să fie acceptată de
toate implementari;e SQL. Această uniune nu este acelaşi lucru cu un produs
cartezian, care leagă fiecare rând dintr-un tabel cu fiecare rând din celălalt tabel. O
uniune externă completă leagă fiecare rând dintr-un tabel cu zero sau mai multe
rânduri corespondente din celălalt tabel.
Este folosită mai mult pentru tabelele aflate in relaţia m:m

Sintaxa generală pentru o uniune externă este:

nume_tabel {RIGHT | LEFT | FULL} [OUTER] JOIN nume_tabel {


ON condiţie | USING (nume_coloană [ ,nume_coIoană. ..]) }

Exemple de uniuni externe:

• Să se afişeze toate descrierile genurilor de filme, împreună cu filmele


asociate fiecărui gen. În setul de rezultate rândurile care nu au nici o valoare în
coloană FILM_TITLU - acestea sunt genurile de filme care nu au filme asociate.
Dacă implementarea DBMS nu acceptă uniuni realizate cu cuvântul cheie USING,
modificaţi instrucţiunea astfel încât să utilizeze cuvântul cheie ON, ca în exemplul
care urmează după acesta.

SELECT FILM_GEN_DESCRIERE AS GEN, FILM_TITLU


FROM FILM_GEN LEFT OUTER JOIN FILM USING
(FILM_GEN_COD);

GEN FILM_TITLU
Actiune şi Aventura Kill Bill: Vol. 1
Actiune şi Aventura Man on Fire
Actiune şi Aventura Pirates of the
Caribbean
Actiune şi Aventura Master and
Commander
Actiune şi Aventura The Day After
Tomorrow
Actiune şi Aventura The Last Samurai
Actiune şi Aventura The Italian Job
Anime and
Animation
Copii şi Familie
Clasic
Comedie 50 First Dates
Comedie Matchstick Men
Comedie The School of Rock
Comedie Something's Gotta
Give
Documentar
Drama Big Fiah
Drama Road to Perdition
Drama Mystic River
Drama Monster
Drama Cold Mountain
Drama Lost în Translation
Strain Das Boot
Horror
Independent
Musical
Romantic 13 Going on 30
Romantic Two Weeks Notice

• Interogarea anterioară, rescrisă ca uniune externă către dreapta,


cu condiţie ON.

SELECT FILM_GEN_DESCRIERE AS GEN, FILM_TITLU


FROM FILM RIGHT OUTER JOIN FILM_GEN
ON FILM.FILM_GEN_COD =FILM_GEN.FILM_GEN_COD;

• Interogarea anterioară, rescrisă ca uniune externă completă. Deoarece


fiecare film trebuie să aibă asociat un gen, această interogare va produce aceleaşi
rezultate ca şi uniunea externă către dreapta din interogarea anterioară. Totuşi, dacă
genurile filmelor ar fi opţionale, uniunea externă completă v-ar fi permis să afişaţi
atât genurile care nu au filme asociate, cât şi filmele care nu au genuri asociate.

SELECT FILM_GEN_DESCRIERE AS GEN, FILM_TITLU


FROM FILM FULL OUTER JOIN FILM_GEN
ON FILM.FILM_GEN_COD = FILM_GEN.FILM_GEN_COD;

• Afişaţi descrierile genurilor care nu au nume asociate. Există şi alte


moduri de a face acest lucru, dar exemplul de faţă foloseşte faptul că rândurile
pentru care nu există legături returnează valori nule pentru a selecta numai genurile
care nu au nume asociate.
SELECT FILM_GEN_DESCRIERE AS GEN
FROM FILM RIGHT OUTER JOIN FILM_GEN
ON FILM.FILM_GEN_COD = FILM_GEN.FILM_GEN_COD
WHERE FILM_TITLU IS NULL;

GEN

Animatie
Copii şi Familie
Clasic
Documentar
Horror
Independent
Musical
SF
Special Interes
Sport
Thriller

Ca răspuns la cererile clienţilor, mai mulţi producători de baze de date


relaţionale au introdus uniunile externe inainte de standardizarea clauzei JOIN.
Secţiunile următoare prezintă câteva implementări specifice ale sintaxei uniunii
externe. Aceste soluţii particulare sunt prezentate aici numai pentru că s-ar putea să
le intâlniţi în instrucţiuni SQL mai vechi

Exemplu:

a) Să se afişeze titlurile operelor de artă şi firmele la care acestea sunt


asigurate. Se vor lua în considerare şi operele de artă pentru care nu au fost
încheiate poliţe de asigurare.
SELECT titlu, firma
FROM opera o
LEFT OUTER JOIN polita_asig p ON (o.cod_opera = p.cod_opera);

b) Să se afişeze artiştii (nume, prenume) şi operele acestora, inclusiv cei


care nu au opere expuse în cadrul muzeului.
SELECT nume, prenume, titlu
FROM opera o
RIGHT OUTER JOIN artist a ON (o.cod_artist = a.cod_artist);
c) Să se afişeze numele şi prenumele artiştilor, precum şi titlurile operelor
create de aceştia. Se vor afişa şi artiştii care nu au opere expuse în cadrul muzeului,
precum şi titlurile operelor al căror autor este necunoscut.
SELECT nume, prenume, titlu
FROM opera o
FULL OUTER JOIN artist a ON (o.cod_artist = a.cod_artist);

Specificarea condiţiilor suplimentare ale unei interogări poate fi făcută atât


în clauza WHERE, cât şi în clauza ON. Următoarea instrucţiune este corectă şi are
acelaşi efect dacă în locul operatorului AND ar apărea clauza WHERE.

SELECT o.titlu, p.firma, p.descriere


FROM opera o
JOIN polita_asig p ON (o.cod_opera = p.cod_opera)
AND o.cod_opera = 180;
Să se obţină titlurile cărţilor şi numele domeniului căruia îi aparţin,

remarcând si situaţiile în care domeniul nu ar avea cărţi (dacă domeniul este

fără cărţi atunci apare null la titlul cărţii).

SELECT titlu, intdom


FROM carte, domeniu
WHERE carte.coded(+) = domeniu.coded;
Exemplu:
Considerăm că tabelele dept şi emp au următorul conţinut:
dept emp
deptno dname empno deptno
1 algebra 101 null
2 analiza 102 null
103 null
105 1
106 1
Interogarea următoare furnizează lista tuturor salariaţilor si informatii
despre departamentele in care lucreaza, inclusiv a celor care nu sunt asignaţi
nici unui departament (right outher join).
SELECT a.deptno, a.dname, b.empno, b.deptno
FROM dept a, emp b
WHERE a.deptno(+) = b.deptno;
Rezultatul cererii anterioare va fi:
a.deptno a.dname b.empno b.deptno
101
102
103
1 algebra 105 1
1 algebra 106 1
Interogarea următoare afişează lista departamentelor, inclusiv a celor
care nu au salariaţi (left outer join).
SELECT a deptno, a.dname, b.empno, b.deptno
FROM dept a, emp b
WHERE a.deptno = b.deptno(+);
Rezultatul cererii anterioare va fi:
a.deptno a.dname b.empno b.deptno
1 algebra 105 1
1 algebra 106 1
2 analiza null null
Interogarea următoare produce ca rezultat departamentele, chiar şi cele
fără funcţionari, şi funcţionarii, chiar şi cei care nu sunt asignaţi nici unui
departament (full outer join).
SELECT NVL(TO_CHAR(b.empno),’***’) id,
NVL(a.dname,’***’) nume_dep
FROM dept a, emp b
WHERE a.deptno = b.deptno(+)
UNION
SELECT NVL(TO_CHAR(b.empno),’***’) id,
NVL(a.dname,’***’) nume_dep
FROM dept a, emp b
WHERE a.deptno(+) = b.deptno;
Rezultatul cererii va fi:
id nume_dep
*** analiza
101 ***
102 ***
103 ***
105 algebra
106 algebra
c) Să se afişeze numele şi prenumele artiştilor, precum şi titlurile operelor
create de aceştia. Se vor afişa şi artiştii care nu au opere expuse în cadrul muzeului,
precum şi titlurile operelor al căror autor este necunoscut.
SELECT nume, prenume, titlu
FROM opera o
FULL OUTER JOIN artist a ON (o.cod_artist = a.cod_artist);
Specificarea condiţiilor suplimentare ale unei interogări poate fi făcută atât
în clauza WHERE, cât şi în clauza ON. Următoarea instrucţiune este corectă şi are
acelaşi efect dacă în locul operatorului AND ar apărea clauza WHERE.

SELECT o.titlu, p.firma, p.descriere


FROM opera o
JOIN polita_asig p ON (o.cod_opera = p.cod_opera)
AND o.cod_opera = 180;

Uniuni încrucişate (cross joins)

O uniune încrucişată (cross join) nu este altceva decât sintaxa standard


pentru un produs cartezian. Interogarea care unea tabelele FILM şi FILM_GEN şi
obţinea un produs cartezian
SELECT FILM_ID, FILM_GEN_DESCRIERE AS GEN, FILM_TITLU
FROM FILM, FILM_GEN
ORDER BY FILM_ID;

poate fi rescrisă ca mai jos, folosind o uniune încrucişată:

SELECT FILM_ID, FILM_GEN_DESCRIERE AS GEN, FILM_TITLU


FROM FILM CROSS JOIN FILM_GEN
ORDER BY FILM_ID;

Subinterogări

O caracteristică foarte puternică a limbajului SQL sunt subinterogările


(numite şi selecţii), care, aşa cum sugerează şi numele, se referă la o instrucţiune
SELECT care contine o instrucţiune SELECT subordonată. De obicei,
subinterogările sunt folosite în clauza WHERE, ca modalitate de limitare a
rândurilor returnate în setul de rezultate al interogării externe. Aceasta poate fi o
modalitate foarte flexibilă de selectare a datelor.
O regulă esenţială de sintaxă este ca subinterogarea să fie încadrată de
paranteze.
Orice operaţie efectuată cu o subinterogare poate fi facută şi printr-o uniune.

Subinterogări necorelate

O subinterogare necorelată (noncorrelated subselect) este o subinterogare în


care interogarea internă nu face nici o referire la interogarea externă care o conţine.
Aceasta înseamnă că poate fi rulată mai intâi interogarea internă, apoi setul de
rezultate obţinut poate fi folosit în interogarea externă.
Exemple:

• Afişaţi toate limbile în care nu există nici un film în inventarul magazinului


de produse video.

SELECT LIMBA_COD, LIMBA_NUME


FROM LIMBA
WHERE LIMBA_COD NOT IN
(SELECT DISTINCT LIMBA_COD
FROM FILM_LIMBA)
ORDER BY LIMBA_COD

LIMBA_COD LIMBA_NUME
Ja Japoneza
Ko Coreana
ni Olandeza
ru Rusa
zh Chineza

Interogarea internă returnează o listă cu codurile de limbă asociate


filmelor în tabelul FILM_LIMBA. Cuvântul cheie DISTINCT elimină rândurile
duplicate din setul de rezultate .
Interogarea internă rulată independent, pentru a vă ajuta să înţelegeţi
cum funcţionează:
SELECT DISTINCT LIMBA_COD FROM FILM_LIMBA;
LIMBA_COD
-------------------------------------------
de (Germana)
en (Engleza)
es (Spaniola)
fr (Franceza)

• Proprietarul magazinului vrea să vadă efectul recentei creşteri de preţuri


şi are nevoie de o listă a tranzacţiilor (TRANZACTIE_ID) în care clientul a plătit
mai mult decât taxa medie (INCHIRIAT_TAXA) pentru un film. Iată cum arată
interogarea:

SELECT DISTINCT TRANZACTIE_ID


FROM FILM_INCHIRIAT
WHERE INCHIRIAT_TAXA>
(SELECT AVG(INCHIRIAT_TAXA) FROM FILM_INCHIRIAT)

Interogarea internă calculează media taxelor de închiriere, iar interogarea


externă găseşte apoi toate rândurile din tabelul FILM_INCHIRIAT pentru care
valoarea INCHIRIAT_TAXA depăşeşte media.
Cuvântul cheie DISTINCT elimină tranzacţiile duplicate.

• Rezultatele interogării anterioare ar fi mai utile pentru proprietarul magazinului


dacă ar include şi data tranzacţiei. O modalitate de a realiza acest lucru este şi
adăugăm o uniune cu tabelul CLIENT_TRANZACTIE în interogarea externă.
Totuşi, deoarece tocmai aţi învăţat despre subinterogari, să facem acelaşi lucru
folosind încă o subinterogare. Iată cum arată interogarea:

SELECT TRANZACTIE_ID, TRANZACTIE_DATA AS TRANZ_DATA


FROM CLIENT_TRANZACTIE
WHERE TRANZACTIE_ID IN
(SELECT DISTINCT TRANZACTIE_ID FROM FILM_INCH,
WHERE INCH_TAXA > (SELECT AVG ( INCHIRIAT_TAXA)
FROM FILM_INCHIRIAT)

TRANZACTIE_ID TRANZ_DATA
9 03/01/2005
10 03/01/2005

Subinterogări corelate

O subinterogare corelată (correlated subselect) este o subinterogare în care


interogarea internă referă valorile furnizate de interogarea externă. Aceste
subinterogari sunt mult mai puţin eficiente decât subinterogările necorelate,
deoarece interogarea internă trebuie să fie apelată pentru fiecare rând găsit de
interogarea externă.
Exemplu:
Proprietarul magazinului vrea să transmită prin poştă un cupon valoric
tuturor clienţilor care au plătit mai mult de 15$ pentru o singură tranzacţie de
închiriere.

SELECT DISTINCT CLIENT_CONT_ID


FROM CLIENT_TRANZACTIE A
WHERE 15 < (SELECT SUM (INCHIRIAT_TAXA)
FROM FILM_INCHIRIATB
WHERE A.TRANZACTIE _ID = B.TRANZACTIE_ID)

CLIENT_CONT_ID
2
7
9
Observaţi pseudonimele asociate numelor de tabele din interogările
internă şi externă, precurn şi folosirea acestora în clauza WHERE a interogării
interne. Acesta este elementul de identificare al unei subinterogări corelate.
Interogarea externă selectează o lista de valori CLIENT_CONT_ID distincte din
tabelul CLIENT_TRANZACTIE. Fiecare valoare găsită este transmisă interogării
interne, care este rulată pentru a calcula suma taxelor de închiriere din tranzacţia
respectivă. Dacă suma taxelor de închiriere este mai mare sau egală cu 15, atunci
clauza WHERE din interogarea externă ia valoarea logică „adevărat", iar rândul
CLIENT_ID este adăugat în setul de rezultate.

Vizualizări în linie

Foarte puţine implementări, printre care Oracle, permit folosirea unei


subinterogări în clauza FROM a unei interogări, într-o construcţie numită
vizualizare în linie (inline view). Această construcţie permite care setul de rezultate
al unei interogări să fie tratat ca şi cum ar fi un tabel sau o vizualizare predefinită.
Iată un exemplu:
• Această interogare află numărul maxim de închirieri ale unui singur film;

SELECT MAX(INCHIRIAT_NUMAR) AS MAX_INCHIRIAT_NUMAR


FROM (SELECT FILM_ID, NUMAR(*) AS INCHIRIAT_NUMAR
FROM FILM_INCHIRIAT GROUP BY FILM_ID)
MAX_INCH_NUMAR
5

Interogarea internă calculează numărul de închirieri pentru fiecare valoare


FILM_ID. Interogarea externă selectează valoarea maximă INCHIRIAT_NUMAR
din interogarea internă, tratată ca şi cum ar fi o vizualizare predefinită. Nu există
nici o limită în privinţa modurilor de utilizare a vizualizărilor în linie - puteţi chiar
să le uniţi cu alte tabele sau vizualizări.
Subinterogări (Subcereri)

O caracteristică foarte puternică a limbajului SQL sunt subinterogările


(numite şi selecţii), care, aşa cum sugerează şi numele, se referă la o instrucţiune
SELECT care conţine o instrucţiune SELECT subordonată.
De cele mai multe ori, pentru a implementa anumite interogări, nu este
suficientă o singură cerere SELECT ci sunt necesare subcereri.
Subcererile sunt comenzi SELECT încapsulate în oricare din clauzele ,
SELECT, WHERE, HAVING, FROM, numită instrucţiune „părinte“.
Dacă subcererea urmează clauzei WHERE sau HAVING, ea poate conţine
unul dintre operatorii ALL, ANY, IN (=ANY), EXIST, NOT IN (!=ALL) care sunt
specifici cererilor care întorc mai multe linii (multiple-row subquery) sau unul
dintre operatorii de comparare (=, <, >, >=, <=, <>) care sunt specifici cererilor
care întorc o singură linie (single-row subquery).
Utilizând subcereri, se pot construi interogări complexe pe baza unor
instrucţiuni simple. Subcererile mai sunt numite instrucţiuni SELECT imbricate
sau interioare.

Subcererea returnează o valoare care este utilizată de către instrucţiunea


„părinte“. Utilizarea unei subcereri este echivalentă cu efectuarea a două cereri
secvenţiale şi utilizarea rezultatului cererii interne ca valoare de căutare în cererea
externă (principală).
Subcererile pot fi utilizate în următoarele situaţii:
pentru a furniza valori care intervin în condiţiile din clauzele WHERE,
HAVING şi START WITH ale instrucţiunilor SELECT;
pentru a defini o mulţime de linii care urmează să fie inserată în tabelul
destinaţie al unei instrucţiuni INSERT sau CREATE TABLE;
pentru a defini o mulţime de linii care urmează să fie inserate într-o
vizualizare sau vizualizare materializată, prin intermediul unei
instrucţiuni CREATE VIEW sau CREATE MATERIALIZED VIEW;
pentru a defini una sau mai multe valori care urmează să fie atribuite unor
linii existente într-o instrucţiune UPDATE;
pentru a defini un tabel asupra căruia va opera cererea externă (plasarea
subcererii în clauza FROM sau în instrucţiunile INSERT, UPDATE,
DELETE).
Subcererile trebuie incluse între paranteze şi trebuie plasate în partea dreaptă
a operatorului de comparare. Subcererea nu poate conţine clauza ORDER BY.
De obicei, subinterogările sunt folosite în clauza WHERE, ca modalitate de
limitare a rândurilor returnate în setul de rezultate al interogării externe. Aceasta
poate fi o modalitate foarte flexibilă de selectare a datelor.
O regulă esenţială de sintaxă este ca subinterogarea să fie încadrată de paranteze.
Orice operaţie efectuată cu o subinterogare poate fi făcută şi printr-o uniune.

Exemplu:
Să se obţină numele şi salariul angajaţilor, având salariul minim.
SELECT name, sal
FROM angajati
WHERE sal=(SELECT MIN(sal)
FROM angajati);
Exemplu:
Să se obţină job-ul pentru care salariul mediu este minim. Sa se afiseze si
salariul mediu.
SELECT job, AVG(sal)
FROM angajati
GROUP BY job
HAVING AVG(sal)=(SELECT MIN(AVG(sal))
FROM angajati
GROUP BY job);

Operatorul ANY presupune că este adevărată condiţia dacă comparaţia este


adevărată pentru cel puţin una din valorile returnate. Sunt evidente relaţiile:
< ANY  mai mic ca maximul;
> ANY  mai mare ca minimul;
= ANY  IN.
Pentru operatorul ALL se presupune că este adevărată condiţia, dacă
comparaţia este adevărată pentru toate elementele listei returnate. Pentru operatorul
ALL sunt evidente relaţiile:
< ALL  mai mic ca minimul;
> ALL  mai mare ca maximul;
! = ALL  NOT IN.
Exemplu:
WHERE codec > ALL („C1‟, „C2‟)  este superior tuturor elementelor din listă;
WHERE codec > ANY („C1‟, „C2‟)  este superior cel puţin unui element din
listă.
Exemplu:
Să se obţină salariaţii al căror salariu este mai mare ca salariile medii din
toate departamentele.

SELECT nume, job


FROM angajati
WHERE sal > ALL(SELECT AVG(sal)
FROM angajati
GROUP BY cod_dep);
Există subcereri care au ca rezultat mai multe coloane (multiple-column
subquery). Aceste interogări au următoarea sintaxă generală:
SELECT col,col,…
FROM tabel
WHERE (col,col,…) IN (SELECT col,col,…
FROM tabel
WHERE condiţie);

Dacă una din valorile returnate de subcerere este valoarea null atunci cererea
nu întoarce nici o linie. Prin urmare, dacă valoarea null poate să facă parte din
rezultatul subcererii nu trebuie utilizat operatorul NOT IN. Problema nu mai apare
dacă se utilizează operatorul IN.

Exemplu:
Să se obţină salariaţii care nu au subordonaţi.
SELECT a.nume
FROM angajati a
WHERE a.cod_ang NOT IN (SELECT m.mgr
FROM angajati m);
În acest caz, instrucţiunea SQL nu întoarce nici o linie deoarece una din
valorile furnizate de subcerere este valoarea null.
Subinterogări necorelate (nesincronizate)

O subinterogare necorelată (noncorrelated subselect) este o subinterogare în


care interogarea internă nu face nici o referire la interogarea externă care o conţine.
Subcererile necorelate returnează o valoare care este utilizată de cererea
externă (cererea principală). Cererile care conţin subcereri necorelate sunt evaluate
în modul următor:
cererea internă este executată prima şi determină o valoare (sau o
mulţime de valori);
cererea externă se execută o singură dată, utilizând valorile returnate de
cererea internă.
În general, o cerere imbricată, necorelată are următoarea formă:
SELECT lista_select
FROM nume_tabel
WHERE expresie operator (SELECT lista_select
FROM nume_tabel);
În această sintaxă, identificatorul operator poate fi de tip:
single-row operator (>, =, >=, <, <>, <=), care poate fi utilizat dacă
subcererea returnează o singură linie;
multiple-row operator (IN, ANY, ALL), care poate fi folosit dacă
subcererea returnează mai mult de o linie.
Operatorul ANY, care este sinonim cu operatorul SOME, determină
compararea unei valori cu fiecare valoare returnată de o subcerere. Astfel, <ANY
are semnificaţia „mai mic decât maximul“; >ANY înseamnă „mai mare decât
minimul“; =ANY este echivalent cu operatorul IN. Operatorul ALL compară o
valoare cu toate valorile returnate de o subcerere. Astfel, <ALL are semnificaţia
„mai mic decât minimul“, iar >ALL este echivalent cu „mai mare decât maximul“.
Operatorul NOT poate fi utilizat în combinaţie cu IN, ANY şi ALL.
În utilizarea unei subcereri se impun anumite reguli.
Subcererea trebuie inclusă între paranteze.
Pentru claritate, subcererea se plasează în partea dreaptă a operatorului de
comparaţie.
Înainte de versiunea Oracle8i, subcererile nu puteau să conţină clauza
ORDER BY. Începând cu Oracle8i, clauza ORDER BY poate fi utilizată şi
este chiar obligatorie în subcerere pentru a efectua analiza top-n (cererea
care efectuează analiza top-n returnează cele mai mari sau cele mai mici
n valori ale unei coloane).
Operatorul folosit trebuie să fie conform cu tipul cererii. Cererea va
genera o eroare dacă este utilizat un operator single-row în faţa unei
subcereri care returnează mai mult de o linie. De asemenea, dacă
subcererea nu returnează nici o linie, apare o eroare.
Server-ul Oracle nu impune nici o limită asupra numărului de subcereri.
Limita acestora depinde de dimensiunea buffer-ului pe care îl utilizează cererea.

Exemple:

• Afişaţi toate limbile în care nu există nici un film în inventarul magazinului de


produse video.

SELECT LIMBA_COD, LIMBA_NUME


FROM LIMBA
WHERE LIMBA_COD NOT IN
(SELECT DISTINCT LIMBA_COD
FROM FILM_LIMBA)
ORDER BY LIMBA_COD

LIMBA_COD LIMBA_NUME
Ja Japoneza
Ko Coreana
ni Olandeza
ru Rusa
zh Chineza

Interogarea internă returnează o listă cu codurile de limbă asociate filmelor în


tabelul FILM_LIMBA. Cuvântul cheie DISTINCT elimină rândurile duplicate din
setul de rezultate .
Interogarea internă rulată independent, pentru a vă ajuta să înţelegeţi cum
funcţionează:

SELECT DISTINCT LIMBA_COD FROM FILM_LIMBA;


LIMBA_COD
-------------------------------------------
de (Germana)
en (Engleza)
es (Spaniola)
fr (Franceza)
• Proprietarul magazinului vrea să vadă efectul recentei creşteri de preţuri şi are
nevoie de o listă a tranzacţiilor (TRANZACTIE_ID) în care clientul a plătit mai
mult decât taxa medie (INCHIRIAT_TAXA) pentru un film. Iată cum arată
interogarea:

SELECT DISTINCT TRANZACTIE_ID


FROM FILM_INCHIRIAT
WHERE INCHIRIAT_TAXA>
(SELECT AVG(INCHIRIAT_TAXA) FROM FILM_INCHIRIAT)

Interogarea internă calculează media taxelor de închiriere, iar interogarea externă


găseşte apoi toate rândurile din tabelul FILM_INCHIRIAT pentru care valoarea
INCHIRIAT_TAXA depăşeşte media.
Cuvântul cheie DISTINCT elimină tranzacţiile duplicate.

• Rezultatele interogării anterioare ar fi mai utile pentru proprietarul magazinului


dacă ar include şi data tranzacţiei. O modalitate de a realiza acest lucru este şi
adăugăm o uniune cu tabelul CLIENT_TRANZACTIE în interogarea externă.
Totuşi, deoarece tocmai aţi învăţat despre subinterogari, să facem acelaşi lucru
folosind încă o subinterogare. Iată cum arată interogarea:

SELECT TRANZACTIE_ID, TRANZACTIE_DATA AS TRANZ_DATA


FROM CLIENT_TRANZACTIE
WHERE TRANZACTIE_ID IN
(SELECT DISTINCT TRANZACTIE_ID FROM FILM_INCH,
WHERE INCH_TAXA > (SELECT AVG ( INCHIRIAT_TAXA)
FROM FILM_INCHIRIAT)

TRANZACTIE_ID TRANZ_DATA
9 03/01/2005
10 03/01/2005

Exemplu(din galeria de arta):


a) Să se afişeze titlul, codul artistului şi valoarea operelor create de artistul
căruia îi aparţine opera având codul 180 şi care se află expuse în aceeaşi galerie cu
operele al căror cod este 100 sau 110. Se presupune că o operă are un singur autor.
SELECT titlu, cod_artist, valoare
FROM opera
WHERE cod_artist = (SELECT cod_artist
FROM opera
WHERE cod_opera = 180)
AND cod_galerie IN (SELECT cod_galerie
FROM opera
WHERE cod_opera IN (100, 110));
b) Să se determine artistul pentru care valoare medie a operelor sale de artă
este minimă.
SELECT cod_artist, AVG(valoare)
FROM opera
GROUP BY cod_artist
HAVING AVG(valoare) = (SELECT MIN(AVG(valoare))
FROM opera
GROUP BY cod_artist);
c) Pentru fiecare artist, să se afişeze titlul şi valoarea celei mai ieftine opere
de artă expuse în muzeu.
SELECT titlu, cod_artist, valoare
FROM opera
WHERE valoare IN (SELECT MIN(valoare)
FROM opera
GROUP BY cod_artist);
d) Să se afişeze operele de artă care nu sunt expuse în galeria având codul
30 şi a căror valoare este mai mică decât a unei opere din galeria 30.
SELECT cod_opera, titlu, valoare
FROM opera
WHERE valoare < ANY (SELECT valoare
FROM opera
WHERE cod_galerie = 30)
AND cod_galerie <> 30;
Dacă operatorul ANY se înlocuieşte cu operatorul ALL, cererea precedentă
returnează operele care nu sunt expuse în galeria 30 şi a căror valoare este mai
mică decât a oricărei opere din galeria respectivă.
e) Să se afişeze cele mai scumpe 3 opere de artă din muzeu.
SELECT ROWNUM "Nr.Crt", titlu, valoare
FROM (SELECT titlu, valoare
FROM opera
ORDER BY valoare DESC)
WHERE ROWNUM <= 3;
Exemplu:
Din punct de vedere logic, următoarea cerere ar trebui să returneze titlurile
operelor care nu sunt expuse în galeriile unde se află lucrările artistului având
codul 60.
SELECT titlu
FROM opera
WHERE cod_galerie NOT IN (SELECT cod_galerie
FROM opera
WHERE cod_artist = 60);
Dacă pentru una dintre opere valoarea coloanei cod_galerie este null,
întreaga cerere nu va returna nici o linie, chiar dacă există înregistrări cu
proprietatea cerută. Justificarea este că toate condiţiile în care unul dintre operanzi
este null au, de asemenea, valoarea null. Prin urmare, ori de câte ori este posibil ca
în rezultatul subcererii să apară valori null, nu trebuie folosit operatorul NOT IN.
Operatorul NOT IN este echivalent cu <>ALL. Dacă se utilizează operatorul IN, nu
mai este nici o problemă dacă în rezultatul subcererii apar valori null. Operatorul
IN este echivalent cu =ANY.
Exemplu:
Să se afişeze titlurile operelor care sunt expuse în galeriile unde se află
lucrările artistului având codul 60.
SELECT titlu
FROM opera
WHERE cod_galerie IN (SELECT cod_galerie
FROM opera
WHERE cod_artist = 60);
Pentru a evita obţinerea de valori null în rezultatul unei cereri care utilizează
operatorul NOT IN, se poate specifica o condiţie în subcerere:
SELECT titlu
FROM opera
WHERE cod_galerie NOT IN (SELECT cod_galerie
FROM opera
WHERE cod_artist = 60
AND cod_galerie IS NOT NULL);
Subcereri (Subinterogări) corelate (incuibarite sau sincronizate)
O subinterogare corelată (correlated subselect) este o subinterogare în care
interogarea internă referă valorile furnizate de interogarea externă.
Subcererile corelate sunt utilizate pentru procesarea linie cu linie a
interogărilor. O subcerere este corelată dacă face referinţă la o coloană dintr-un
tabel specificat în instrucţiunea „părinte“. O astfel de subcerere este evaluată o dată
pentru fiecare linie procesată de instrucţiunea „părinte“, care poate fi SELECT,
UPDATE sau DELETE.
Subcererile corelate permit compararea valorilor unei linii cu date
determinate pe baza acestor valori.
Cererile corelate se execută astfel:
cererea externă determină o linie candidat;
cererea internă este executată utilizând valoarea liniei candidat;
valorile rezultate din cererea internă sunt utilizate pentru calificarea sau
descalificarea liniei candidat;
paşii precedenţi se repetă până când nu mai există linii candidat.
Forma generală a unei subcereri corelate este următoarea:
SELECT nume_coloană_1[, nume_coloană_2 …]
FROM nume_tabel_1 extern
WHERE expresie operator
(SELECT nume_coloană_1 [, nume_coloană_2 …]
FROM nume_tabel_2
WHERE expresie_1 = extern.expresie_2);

Exemplu:

Proprietarul magazinului vrea să transmită prin poştă un cupon valoric


tuturor clienţilor care au plătit mai mult de 15$ pentru o singură tranzacţie de
închiriere.

SELECT DISTINCT CLIENT_CONT_ID


FROM CLIENT_TRANZACTIE A
WHERE 15 < (SELECT SUM (INCHIRIAT_TAXA)
FROM FILM_INCHIRIATB
WHERE A.TRANZACTIE _ID = B.TRANZACTIE_ID)

CLIENT_CONT_ID
2
7
9
Observaţi pseudonimele asociate numelor de tabele din interogările internă
şi externă, precurn şi folosirea acestora în clauza WHERE a interogării interne.
Acesta este elementul de identificare al unei subinterogări corelate. Interogarea
externă selectează o lista de valori CLIENT_CONT_ID distincte din tabelul
CLIENT_TRANZACTIE. Fiecare valoare găsită este transmisă interogării interne,
care este rulată pentru a calcula suma taxelor de închiriere din tranzacţia
respectivă. Dacă suma taxelor de închiriere este mai mare sau egală cu 15, atunci
clauza WHERE din interogarea externă ia valoarea logică „adevărat", iar rândul
CLIENT_ID este adăugat în setul de rezultate.

Vizualizări în linie

Foarte puţine implementări, printre care Oracle, permit folosirea unei subinterogări
în clauza FROM a unei interogări, într-o construcţie numită vizualizare în linie
(inline view). Această construcţie permite care setul de rezultate al unei interogări
să fie tratat ca şi cum ar fi un tabel sau o vizualizare predefinită. Iată un exemplu:

• Această interogare află numărul maxim de închirieri ale unui singur film;

SELECT MAX(INCHIRIAT_NUMAR) AS MAX_INCHIRIAT_NUMAR


FROM (SELECT FILM_ID, NUMAR(*) AS INCHIRIAT_NUMAR
FROM FILM_INCHIRIAT GROUP BY FILM_ID)

MAX_INCH_NUMAR
5

Interogarea internă calculează numărul de închirieri pentru fiecare valoare


FILM_ID. Interogarea externă selectează valoarea maximă INCHIRIAT_NUMAR
din interogarea internă, tratată ca şi cum ar fi o vizualizare predefinită. Nu există
nici o limită în privinţa modurilor de utilizare a vizualizărilor în linie - puteţi chiar
să le uniţi cu alte tabele sau vizualizări.

Exemplu de subcereri corelate pentru galeria de arta):

a) Să se afişeze informaţii despre operele de artă a căror valoare depăşeşte


valoarea medie a celor expuse în aceeaşi galerie.
SELECT titlu, valoare, cod_galerie
FROM opera o
WHERE valoare > (SELECT AVG(valoare)
FROM opera
WHERE cod_galerie = o.cod_galerie);
b) Să se afişeze codul, numele şi prenumele artiştilor care au cel puţin două
opere de artă expuse în muzeu.
SELECT cod_artist, nume, prenume
FROM artist a
WHERE 2 <= (SELECT COUNT(*)
FROM opera
WHERE cod_artist = a.cod_artist);
Server-ul Oracle evaluează subcererea corelată precedentă urmând
succesiunea de paşi prezentată în continuare.
1) Selectează o linie din tabelul specificat în cererea externă (aceasta va fi
linia candidat curentă).
2) Reţine valoarea coloanei referite în subcerere din această linie candidat
(în cazul subcererii de mai sus, coloana referită în subcerere este
a.cod_artist).
3) Efectuează subcererea, considerând condiţia acesteia ca facând referinţă
la valoarea liniei candidat din cererea externă (în exemplul precedent,
funcţia COUNT(*) este evaluată pe baza valorii lui a.cod_artist
determinată la pasul 2).
4) Evaluează clauza WHERE a cererii externe pe baza rezultatelor returnate
de cererea internă la pasul 3. Adică, se determină dacă linia candidat este
selectată în rezultatul cererii (în exemplul precedent, numărul de opere
ale unui artist, evaluat de subcerere, este comparat cu 2 în clauza WHERE
a cererii externe, iar dacă această condiţie este satisfăcută, linia
corespunzătoare artistului respectiv va face parte din rezultat).
5) Procedura se repetă pentru următoarele linii candidat din tabel, până când
sunt procesate toate liniile tabelului.

Operatorul EXISTS
În instrucţiunile SELECT imbricate, este permisă utilizarea oricărui operator
logic. Pentru a testa dacă valoarea recuperată de cererea externă există în mulţimea
valorilor regăsite de cererea internă corelată, se poate utiliza operatorul EXISTS.
Dacă subcererea returnează cel puţin o linie, operatorul returnează valoarea TRUE.
În caz contrar, va fi returnată valoarea FALSE.
Operatorul EXISTS asigură că nu mai este continuată căutarea în cererea
internă după ce aceasta regăseşte o linie.
Exemplu:
a) Să se determine codul, numele şi prenumele artiştilor care au cel puţin o
operă de artă expusă în muzeu.
SELECT cod_artist, nume, prenume
FROM artist a
WHERE EXISTS (SELECT 'x'
FROM opera
WHERE cod_artist = a.cod_artist);
Întrucât nu este necesar ca instrucţiunea SELECT interioară să returneze o
anumită valoare, se poate selecta o constantă. De altfel, din punct de vedere al
performanţei, selectarea unei constante asigură mai multă rapiditate decât
selectarea unei coloane.
Ca alternativă a lui EXISTS, poate fi utilizat operatorul IN. Exemplul
precedent poate fi rezolvat prin instrucţiunea următoare:
SELECT cod_artist, nume, prenume
FROM artist
WHERE cod_artist IN (SELECT cod_artist
FROM opera);
b) Să se determine operele care nu sunt menţionate în nici o sursă
bibliografică.
SELECT cod_opera, titlu
FROM opera o
WHERE NOT EXISTS (SELECT 'x'
FROM mentionata_in
WHERE cod_opera = o.cod_opera);
Acest exemplu poate fi rezolvat şi printr-o subcerere necorelată, utilizând
operatorul NOT IN:
SELECT cod_opera, titlu
FROM opera
WHERE cod_opera NOT IN (SELECT cod_opera
FROM ment_in
WHERE cod_opera IS NOT NULL);
Clauza WITH
Cu ajutorul clauzei WITH se poate defini un bloc de cerere înainte ca acesta
să fie utilizat într-o interogare. Clauza permite reutilizarea aceluiaşi bloc de cerere
într-o instrucţiune SELECT complexă. Acest lucru este util atunci când o cerere
face referinţă de mai multe ori la acelaşi bloc de cerere, care conţine operaţii join şi
funcţii agregat. Folosind clauza WITH, server-ul Oracle regăseşte rezultatele unui
bloc de cerere şi le stochează în spaţiul tabel temporar al utilizatorului, ceea ce
poate determina îmbunătăţirea performanţelor.
Exemplu:
Utilizând clauza WITH, să se scrie o cerere care afişează numele artiştilor şi
valoarea totală a operelor acestora. Se vor considera artiştii a căror valoare totală a
operelor este mai mare decât media valorilor totale ale operelor tuturor artiştilor.
WITH
val_artist AS (SELECT nume, SUM(valoare) AS total
FROM opera o, artist a
WHERE o.cod_artist = a.cod_artist
GROUP BY nume),
val_medie AS (SELECT SUM(total)/COUNT(*) AS medie
FROM val_artist)
SELECT *
FROM val_artist
WHERE total > (SELECT medie
FROM val_medie)
ORDER BY nume;
Intern, clauza WITH este tratată ca o vizualizare inline (subcerere în clauza
FROM) sau ca un tabel temporar. Optimizorul alege decizia adecvată pe baza
costului sau beneficiului stocării temporare a rezultatelor clauzei WITH.
Observaţii:
Clauza WITH poate fi folosită numai pentru instrucţiuni SELECT.
Un nume de cerere este vizibil tuturor blocurilor din clauza WITH
definite ulterior (inclusiv subcererilor acestora). De asemenea, un nume
de cerere este vizibil cererii principale şi subcererilor acesteia.
Când un nume de cerere coincide cu numele unui tabel, numele blocului
de cerere are precedenţă asupra numelui tabelului.
Clauza WITH poate conţine mai mult decât o singură cerere. În acest caz,
cererile sunt separate prin virgule.
2.4.4. Funcţii grup şi clauza GROUP BY

Clauza GROUP BY este utilizată pentru a diviza liniile unui tabel în grupuri.
Pentru a returna informaţia corespunzătoare fiecărui astfel de grup, pot fi utilizate
funcţiile agregat. Ele pot apărea în clauzele SELECT, ORDER BY şi HAVING.
Server-ul Oracle aplică aceste funcţii fiecărui grup de linii şi returnează un singur
rezultat pentru fiecare mulţime.
Dintre funcţiile grup definite în sistemul Oracle, se pot enumera: AVG,
SUM, MAX, MIN, COUNT, STDDEV, VARIANCE, DENSE_RANK, RANK, FIRST,
LAST, GROUP_ID, GROUPING, GROUPING_ID etc. Tipurile de date ale
argumentelor funcţiilor grup pot fi CHAR, VARCHAR2, NUMBER sau DATE.
Funcţiile AVG, SUM, STDDEV şi VARIANCE operează numai asupra valorilor
numerice. Funcţiile MAX şi MIN pot opera asupra valorilor numerice, caracter sau
de tip dată calendaristică.
Toate funcţiile grup, cu excepţia lui COUNT(*), ignoră valorile null.
COUNT(expresie) returnează numărul de linii pentru care expresia dată nu are
valoarea null. Funcţia COUNT returnează un număr mai mare sau egal cu zero şi
nu întoarce niciodată valoarea null.
Când este utilizată clauza GROUP BY, server-ul sortează implicit mulţimea
rezultată în ordinea crescătoare a valorilor coloanelor după care se realizează
gruparea.
În clauza GROUP BY a unei cereri se pot utiliza operatorii ROLLUP şi
CUBE. Aceştia sunt disponibili începând cu versiunea Oracle8i.

Operatorul ROLLUP
Operatorul ROLLUP produce o mulţime care conţine liniile obţinute în urma
grupării obişnuite şi linii pentru subtotaluri. Acest operator furnizează valori
agregat şi superagregat corespunzătoare expresiilor din clauza GROUP BY.
Operatorul ROLLUP poate fi folosit pentru extragerea de statistici şi informaţii
totalizatoare din mulţimile rezultate. Acest operator poate fi util la generarea de
rapoarte, diagrame şi grafice.
Operatorul ROLLUP creează grupări prin deplasarea într-o singură direcţie,
de la dreapta la stânga, de-a lungul listei de coloane specificate în clauza GROUP
BY. Apoi, se aplică funcţia agregat acestor grupări. Dacă sunt specificate n expresii
în operatorul ROLLUP, numărul de grupări generate va fi n + 1. Liniile care se
bazează pe valoarea primelor n expresii se numesc linii obişnuite, iar celelalte se
numesc linii superagregat.
Dacă în clauza GROUP BY sunt specificate n coloane, pentru a produce
subtotaluri fără operatorul ROLLUP ar fi necesare n + 1 instrucţiuni SELECT
conectate prin UNION ALL. Aceasta ar face execuţia cererii ineficientă deoarece
fiecare instrucţiune SELECT determină accesarea tabelului. Operatorul ROLLUP
determină rezultatele efectuând un singur acces la tabel şi este util atunci când sunt
implicate multe coloane în producerea subtotalurilor.
Exemplu:

Să se afişeze codurile de galerii mai mici decât 50, iar pentru fiecare dintre
acestea şi pentru fiecare autor care are opere expuse în galerie, să se listeze
valoarea totală a lucrărilor sale. De asemenea, se cere valoarea totală a operelor
expuse în fiecare galerie. Rezultatul va conţine şi valoarea totală a operelor din
galeriile având codul mai mic decât 50, indiferent de codul autorului.
SELECT cod_galerie, cod_artist, SUM(valoare)
FROM opera
WHERE cod_galerie < 50
GROUP BY ROLLUP(cod_galerie, cod_artist);
Instrucţiunea precedentă va avea un rezultat de forma:
COD_GALERIE COD_ARTIST SUM(VALOARE)
10 50 14000
10 60 10000
10 24000
40 50 8080
40 8080
32080

În rezultatul prezentat anterior se pot distinge 3 tipuri de linii.


1) Prima linie reprezintă suma operelor artistului care are codul 50, expuse
în galeria având codul 10. În mod similar se interpretează a doua şi a
patra linie din rezultat.
2) Linia a treia şi a cincea din rezultat conţin valoarea totală a operelor din
galeria al cărei cod este 10, respectiv 40. Aceste linii se disting prin faptul
că valoarea coloanei cod_artist este null.
3) Ultima linie conţine suma valorilor tuturor operelor din galeriile al căror
cod este 10 sau 40. Valoarea afişată este obţinută prin însumarea valorilor
de pe a treia, respectiv a cincea linie. Întrucât această linie corespunde
totalului general, ea conţine valoarea null pe toate coloanele, cu excepţia
câmpului SUM(valoare).
Operatorul CUBE
Operatorul CUBE grupează liniile selectate pe baza valorilor tuturor
combinaţiilor posibile ale expresiilor specificate şi returnează câte o linie
totalizatoare pentru fiecare grup. Acest operator este folosit pentru a produce
mulţimi de rezultate care sunt utilizate în rapoarte. În vreme ce ROLLUP produce
subtotalurile doar pentru o parte dintre combinaţiile posibile, operatorul CUBE
produce subtotaluri pentru toate combinaţiile posibile de grupări specificate în
clauza GROUP BY, precum şi un total general.
Dacă există n coloane sau expresii în clauza GROUP BY, vor exista 2n
combinaţii posibile superagregat. Din punct de vedere matematic, aceste
combinaţii formează un cub n-dimensional, de aici provenind numele operatorului.
Pentru producerea de subtotaluri fără ajutorul operatorului CUBE ar fi necesare 2n
instrucţiuni SELECT conectate prin UNION ALL.

Exemplu:

Să se afişeze valoarea totală a operelor de artă ale unui autor, expuse în


cadrul fiecărei galerii având codul mai mic decât 50. De asemenea, să se afişeze
valoarea totală a operelor din fiecare galerie având codul mai mic decât 50,
valoarea totală a operelor fiecărui autor indiferent de galerie şi valoarea totală a
operelor din galeriile având codul mai mic decât 50.
SELECT cod_galerie, cod_artist, SUM(valoare)
FROM opera
WHERE cod_galerie < 50
GROUP BY CUBE(cod_galerie, cod_artist);
Instrucţiunea precedentă va genera un rezultat de forma următoare:
COD_GALERIE COD_ARTIST SUM(VALOARE)
10 50 14000
10 60 10000
10 24000
40 50 8080
40 8080
50 22080
60 10000
32080

În plus faţă de rezultatul corespunzător operaţiei ROLLUP, operatorul CUBE


a produs linii care reprezintă suma valorilor operelor pentru fiecare artist care a
expus în galerii având codul mai mic decât 50. Aceste linii se disting prin faptul că
valoarea coloanei cod_galerie este null.

Funcţia GROUPING
Funcţia GROUPING poate fi utilizată alături de operatorii CUBE şi
ROLLUP pentru a arăta modul cum a fost obţinută o valoare totalizatoare. Această
funcţie acceptă un singur argument, care trebuie să fie una dintre expresiile
specificate în clauza GROUP BY.
O valoare null a expresiei din argumentul funcţiei GROUPING poate
proveni din tabelul de bază (valoare null stocată) sau poate fi o valoare null creată
de operaţia ROLLUP sau CUBE ca rezultat al unei funcţii grup asupra expresiei
respective.
Funcţia GROUPING returnează valoarea 0 sau 1. Valoarea 0 returnată de
funcţia GROUPING pe baza unei expresii poate indica fie că expresia a fost
utilizată pentru calculul valorii agregat, fie că valoarea null a expresiei este o
valoare null stocată. Valoarea 1 returnată de funcţia GROUPING pe baza unei
expresii poate indica fie că expresia nu a fost utilizată pentru calculul valorii
agregat, fie că valoarea null a expresiei este creată de ROLLUP sau CUBE ca
rezultat al grupării.
Valorile returnate de funcţia GROUPING sunt utile pentru:
determinarea nivelului de agregare al unui subtotal dat, adică a grupului
sau grupurilor pe care se bazează subtotalul respectiv;
identificarea provenienţei unei valori null a unei expresii calculate, dintr-
una din liniile mulţimii rezultat.
Exemplu:
SELECT cod_galerie, cod_artist, SUM(valoare),
GROUPING(cod_galerie), GROUPING(cod_artist)
FROM opera
WHERE cod_galerie < 50
GROUP BY ROLLUP(cod_galerie, cod_artist);
SUM GROUPING GROUPING
COD_GALERIE COD_ARTIST
(VALOARE) (COD_GALERIE) (COD_ARTIST)
10 50 14000 0 0
10 60 10000 0 0
10 24000 0 1
40 50 8080 0 0
40 8080 0 1
32080 1 1
Pe prima linie din acest rezultat, valoarea totalizatoare reprezintă suma
valorilor operelor artistului având codul 50, în cadrul galeriei 10. Pentru a calcula
această valoare au fost luate în considerare coloanele cod_galerie şi cod_artist.
Prin urmare, expresiile GROUPING(cod_galerie) şi GROUPING(cod_artist) au
valoarea 0 pentru prima linie din rezultat.
Pe linia a treia se află valoarea totală a operelor din galeria având codul 10.
Această valoare a fost calculată luând în considerare doar coloana cod_galerie,
astfel încât GROUPING (cod_galerie) şi GROUPING(cod_artist) au valorile 0,
respectiv 1.
Pe ultima linie din rezultat se află valoarea totală a operelor din galeriile
având codul mai mic decât 50. Nici una dintre coloanele cod_galerie şi cod_artist
nu au intervenit în calculul acestui total, prin urmare valorile corespunzătoare
expresiilor GROUPING(cod_galerie) şi GROUPING(cod_artist) sunt 0.
Clauza GROUPING SETS
GROUPING SETS reprezintă o extensie a clauzei GROUP BY care permite
specificarea unor grupări multiple de date. Utilizarea acestei opţiuni facilitează
analiza datelor în mai multe dimensiuni.
Această extensie, apărută în sistemul Oracle9i, permite scrierea unei singure
instrucţiuni SELECT pentru a specifica grupări diferite (care pot conţine operatorii
ROLLUP şi CUBE), în loc de mai multe instrucţiuni SELECT combinate prin
operatorul UNION ALL. De altfel, reuniunea rezultatelor mai multor cereri este
ineficientă întrucât necesită mai multe parcurgeri ale aceloraşi date.
Operatorii ROLLUP şi CUBE pot fi consideraţi cazuri particulare de mulţimi
de grupări. Au loc următoarele echivalenţe:
CUBE(a, b, c) GROUPING SETS
((a, b, c), (a, b), (a, c), (b, c), (a),
(b), (c), ())
ROLLUP(a, b, GROUPING SETS
c) ((a, b, c), (a, b), (a), ())
Exemplu:
Considerând galeriile al căror cod este mai mic decât 50, să se calculeze
media valorilor operelor:
pentru fiecare galerie şi, în cadrul acesteia, pentru fiecare artist;
pentru fiecare artist şi, în cadrul acestuia, pentru anii de achiziţie
corespunzători.
SELECT cod_galerie, cod_artist,
TO_CHAR(data_achizitiei, 'yyyy') "an achizitie",
AVG(valoare) "Valoare medie"
FROM opera
WHERE cod_galerie < 50
GROUP BY GROUPING SETS
((cod_galerie, cod_artist),
(cod_artist, TO_CHAR(data_achizitiei, 'yyyy')));
Mulţimea rezultat este constituită din valorile medii pentru fiecare dintre
cele două grupuri şi are forma următoare:
COD_GALERIE COD_ARTIST an a Valoare medie
10 50 3500
10 60 2500
40 50 2020
50 2000 2380
50 2002 2300
60 2001 2000
60 2003 3000

Exemplul precedent poate fi rezolvat şi prin următoarea instrucţiune


compusă:
SELECT cod_galerie, cod_artist, NULL "an achizitie",
AVG(valoare) "Valoare medie"
FROM opera
GROUP BY cod_galerie, cod_artist
UNION ALL
SELECT NULL, cod_artist,
TO_CHAR(data_achizitiei, 'yyyy'), AVG(valoare)
FROM opera
GROUP BY cod_artist, TO_CHAR(data_achizitiei, 'yyyy');
În absenţa unui optimizor care analizează blocurile de cerere şi generează
planul de execuţie, cererea precedentă va parcurge de două ori tabelul de bază
(opera), ceea ce poate fi ineficient. Din acest motiv, este recomandată utilizarea
extensiei GROUPING SETS.

Concatenarea grupărilor
Concatenarea grupărilor reprezintă o modalitate concisă de a genera
combinaţii de grupări. Acestea se specifică prin enumerarea mulţimilor de grupări
(grouping sets) şi a operaţiilor ROLLUP, CUBE separate prin virgulă. De exemplu,
expresia GROUP BY GROUPING SETS(a, b), GROUPING SETS(c, d) defineşte
grupările (a, c), (a, d), (b, c), (b, d).
Concatenarea mulţimilor de grupări este utilă atât pentru uşurinţa dezvoltării
cererilor, cât şi pentru aplicaţii. Codul SQL generat de aplicaţiile OLAP implică
deseori concatenarea mulţimilor de grupări, în care fiecare astfel de mulţime
defineşte grupările necesare pentru o dimensiune.

Exemplu:
Să se determine media valorilor operelor luând în considerare următoarele
grupări: (cod_galerie, cod_artist, an_achizitie), (cod_galerie, cod_artist),
(cod_galerie, an_achizitie), (cod_galerie).
SELECT cod_galerie, cod_artist,
TO_CHAR(data_achizitiei, 'yyyy') an_achizitie,
AVG(valoare)
FROM opera
GROUP BY cod_galerie, ROLLUP(cod_artist),
CUBE(TO_CHAR(data_achizitiei, 'yyyy'));
PROBLEME-SUBCERERI

De cele mai multe ori, pentru a implementa anumite interogări, nu este


suficientă o singură cerere SELECT ci sunt necesare subcereri. Subcererile sunt
comenzi SELECT încapsulate în oricare din clauzele SELECT, WHERE, HAVING,
FROM.
Dacă subcererea urmează clauzei WHERE sau HAVING, ea poate conţine
unul dintre operatorii ALL, ANY, IN (=ANY), EXIST, NOT IN (!=ALL) care sunt
specifici cererilor care întorc mai multe linii (multiple-row subquery) sau unul
dintre operatorii de comparare (=, <, >, >=, <=, <>) care sunt specifici cererilor
care întorc o singură linie (single-row subquery).
Subcererile trebuie incluse între paranteze şi trebuie plasate în partea dreaptă
a operatorului de comparare. Subcererea nu poate conţine clauza ORDER BY.
Exemplu:
Să se obţină numele salariaţilor, salariile, codul departamentului în care
lucrează şi salariul mediu pe departament pentru toţi angajaţii care au salariul mai
mare ca media salariilor din departamentul în care lucrează (folosirea subcererii în
clauza FROM).
SELECT a.nume, a.sal, a.cod_dep, b.salavg
FROM angajati a, (SELECT dept ,avg(sal) salavg
FROM angajati
GROUP BY cod_dep) b
WHERE a. cod_dep =b. cod_dep
AND a.sal>b.salavg

Exemplu:
Să se obţină lista celor mai scumpe cărţi.
SELECT titlu
FROM carte
WHERE pret = (SELECT MAX(pret)
FROM carte);

Exemplu:
Să se obţină lista scriitorilor care au în bibliotecă un număr de exemplare
mai mare decât numărul mediu al cărţilor din bibliotecă.
SELECT DISTINCT autor
FROM carte
WHERE nrex > (SELECT AVG(nrex)
FROM carte);
Exemplu:
Să se obţină informaţii despre cărţile al căror preţ depăşeşte media preţurilor
cărţilor ce aparţin aceluiaşi domeniu
SELECT *
FROM carte c
WHERE pret > (SELECT AVG(pret)
FROM carte
WHERE coded = c.coded);
Exemplu:
Să se obţină lista cititorilor care au împrumutat cel puţin o carte.
SELECT nume
FROM cititor
WHERE codec IN (SELECT DISTINCT codec
FROM imprumuta);
Exemplu:
Să se obţină codurile cititorilor care nu au împrumutat niciodată cărţi.
SELECT codec
FROM cititor
WHERE codec NOT IN
(SELECT DISTINCT codec
FROM imprumuta);
Exemplu:
Să se obţină lista cititorilor care sunt în întârziere cu predarea cărţilor.
SELECT nume
FROM cititor
WHERE codec IN (SELECT DISTINCT codec
FROM imprumuta
WHERE dataef IS NULL
AND dares<SYSDATE);
Exemplu:
Să se obţină numele cititorilor care au împrumutat cel puţin o carte scrisă de
ZOLA.
SELECT nume
FROM cititor
WHERE codec IN
(SELECT DISTINCT codec
FROM imprumuta
WHERE codel IN
(SELECT codel
FROM carte
WHERE autor=‟ZOLA‟));
Exemplu:
Să se obţină numele cititorilor care nu au împrumutat nici o carte scrisă de
ZOLA.
SELECT nume
FROM cititor
WHERE codec NOT IN
(SELECT DISTINCT codec
FROM imprumuta
WHERE codel IN
(SELECT codel
FROM carte
WHERE autor=‟ZOLA‟));
Operatorul IN poate fi înlocuit cu = ANY (un element este în listă dacă şi
numai dacă este egal cu un element al listei), iar operatorul NOT IN poate fi
înlocuit prin !=ALL.
Exemplu:
Să se obţină codurile cititorilor care au împrumutat o carte de algebră.
SELECT DISTINCT codec
FROM imprumuta
WHERE codel IN
(SELECT codel
FROM carte
WHERE coded=
(SELECT coded
FROM domeniu
WHERE intdom=‟ALGEBRA‟));
Exemplu:
Să se obţină cititorii care au împrumutat numai cărţi scrise de „ZOLA‟.
SELECT nume
FROM cititor
WHERE codec NOT IN
(SELECT DISTINCT codec
FROM imprumuta
WHERE codel NOT IN
(SELECT codel
FROM carte
WHERE autor=‟ZOLA‟));

Exemplu:
Să se obţină numele cititorilor care au împrumutat cel puţin o carte de
informatică (procedural).
SELECT nume
FROM cititor
WHERE codec IN
(SELECT DISTINCT codec
FROM imprumuta
WHERE codel IN
(SELECT codel
FROM carte
WHERE coded=
(SELECT coded
FROM domeniu
WHERE intdom= ‟INFORMATICA‟)));
Exemplu:
Să se obţină numele cititorilor şi titlurile cărţilor de informatică împrumutate
de aceşti cititori (relational).
SELECT nume, titlu
FROM cititor, carte, imprumuta, domeniu
WHERE imprumuta.codel = carte.codel
AND carte.coded = domeniu.coded
AND imprumuta.codec = cititor.codec
AND intdom = ‟INFORMATICA‟;

Subcererile pot fi executate corelat (cu sincronizare) sau încuibărit (fără


sincronizare).
Subcererile fără sincronizare sunt caracterizate de faptul că se execută
cererea cea mai interioară care întoarce un rezultat ce este transmis cererii de nivel
superior, care întoarce un rezultat s.a.m.d.
Subcererile cu sincronizare sunt caracterizate de faptul că evaluarea
subcererii face referinţă la o coloană a cererii principale, iar evaluarea cererii
interioare se face pentru fiecare linie a cererii (principale) care o conţine.
Exemplu:
Să se obţină, utilizând sincronizarea subcererii cu cererea principală, titlurile
cărţilor care au toate exemplarele împrumutate (se selectează un titlu din carte şi
pentru acest titlu se numără câte exemplare sunt împrumutate).
SELECT titlu
FROM carte
WHERE nrex=(SELECT COUNT(*)
FROM imprumuta
WHERE codel = carte.codel
AND dataef IS NULL);
Exemplu:
Să se obţină codurile cititorilor şi codul ultimei cărţi împrumutate.
SELECT codec, codel
FROM imprumuta i
WHERE dataim>=ALL (SELECT dataim
FROM imprumuta
WHERE codec=i.codec);
Pentru această interogare, clauza WHERE putea fi scrisă şi sub forma:
WHERE dataim=(SELECT MAX(dataim)
FROM imprumuta
WHERE codec=i.codec);
Exemplu:
Să se obţină lista codurilor cărţilor împrumutate şi codul primului cititor care
a împrumutat aceste cărti.
SELECT codel,codec
FROM imprumuta i
WHERE dataim<=ALL (SELECT dataim
FROM imprumuta
WHERE i.codel=codel);
Exemplu:
Să se obţină codurile cărţilor din care cel puţin un exemplar este împrumutat.
SELECT codel
FROM carte
WHERE EXISTS
(SELECT codel
FROM imprumuta
WHERE codel = carte.codel
AND dataef IS NULL);
Operatorul WHERE EXISTS (subcerere) presupune că predicatul este
adevărat dacă subcererea întoarce cel puţin un tuplu, iar WHERE NOT EXISTS
(subcerere) presupune că predicatul este adevărat dacă subcererea nu întoarce nici
un tuplu.  EXISTS şi NOT EXISTS cer sincronizarea subcererii.
Exemplu:
Să se obţină titlurile cărţilor care sunt momentan împrumutate.
Soluţia 1 (cu sincronizare):
SELECT titlu
FROM carte
WHERE EXISTS
(SELECT *
FROM imprumuta
WHERE codel = carte.codel
AND dataef IS NULL);
Soluţia 2 (fără sincronizare):
SELECT titlu
FROM carte
WHERE codel IN
(SELECT DISTINCT codel
FROM imprumuta
WHERE dataef IS NULL);
Exemplu:
Să se obţină codurile cărţilor care nu au fost împrumutate niciodată.
Soluţia 1 (cu sincronizare)
SELECT codel
FROM carte
WHERE NOT EXISTS
(SELECT codel
FROM imprumuta
WHERE codel = carte.codel);
Soluţia 2 (fără sincronizare)
SELECT codel
FROM carte
WHERE codel NOT IN
(SELECT DISTINCT codel
FROM imprumuta);
Exemplu:
Să se obţină lista salariaţilor având salariul minim în departamentul în care
lucrează.
SELECT ename,sal
FROM emp e
WHERE sal=(SELECT MIN(sal)
FROM emp
WHERE deptno=e.deptno);
Exemplu:
Să se obţină numele primilor trei salariaţi având retribuţia maximă (ideea
rezolvării este de a verifica dacă numărul salariaţilor care au leafa mai mare decât
leafa salariatului considerat, este mai mic decât 3).
SELECT ename
FROM emp a
WHERE 3>(SELECT COUNT(*)
FROM emp
WHERE sal > a.sal);
Exemplu:
Să se obţină numele cititorilor care au împrumutat cel puţin aceleaşi cărţi ca
şi cititorul având codul C19 (ideea problemei este de a selecta cititorii pentru care
este vidă lista cărţilor împrumutatede C19 mai puţin lista cărţilor împrumutate de
acei cititori).
SELECT nume
FROM cititor
WHERE NOT EXISTS
(SELECT codel
FROM imprumuta
WHERE codec=‟C19‟
MINUS
SELECT codel
FROM imprumuta
WHERE codec= cititor.codec);
Dacă problema era modificată în sensul că „cel puţin”este înlocuit prin „cel
mult” atunci trebuiau inversate interogările legate prin MINUS.
Exemplu:
Să se obţină codurile cititorilor care au împrumutat aceleaşi cărţi ca şi
cititorul având un cod specificat.
Rezolvarea problemei se bazează pe ideea: A = B  A B şi B A  (A-
B) = şi (B-A) =  A-B şi B-A nu furnizează nici un tuplu rezultat.
SELECT codec
FROM imprumuta i
WHERE NOT EXISTS
(SELECT codel
FROM imprumuta
WHERE codec=i.codec
MINUS
SELECT codel
FROM imprumuta
WHERE codec=‟&ccc‟)
AND NOT EXISTS
(SELECT codel
FROM imprumuta
WHERE codec=‟&ccc‟
MINUS
SELECT codel
FROM imprumuta
WHERE codec=i.codec)
AND codec!=‟&ccc‟);
Ultimul operator (AND), asigură să nu apară în rezultat cititorul specificat.
În cazul formei relaţionale de rezolvare a cererii, drumul de acces la
informaţie este în sarcina SGBD-lui şi prin urmare nu mai apar cereri imbricate.
Exemplu:
Să se obţină numele cititorilor care au împrumutat cel puţin o carte.
Soluţia 1 (forma relaţională):
SELECT DISTINCT nume
FROM cititor,imprumuta
WHERE cititor.codec=imprumuta.codec;

Soluţia 2 (forma procedurală):


SELECT nume
FROM cititor
WHERE codec IN
(SELECT DISTINCT codec
FROM imprumuta);
Exemplu:
Să se obţină numele cititorilor care au împrumutat cel puţin două cărţi.
Soluţia 1 (forma relaţională):
SELECT nume
FROM cititor, imprumuta
WHERE cititor.codec=imprumuta.codec
GROUP BY nume
HAVING COUNT(*)>1;
Soluţia 2 (forma procedurală):
SELECT nume
FROM cititor
WHERE codec IN
(SELECT codec
FROM imprumuta
GROUP BY codec
HAVING COUNT(*)>1);
Exemplu:
Să se afişeze numele, prenumele, salariul lucrătorilor, codurile publicaţiilor
la care lucrează şi salariul mediu pe publicaţie pentru toţi angajaţii care au salariul
mai mare decât media salariului pe publicaţia respectivă.
SELECT s.nume, s.prenume, s.salariu,
p.nr_publicatie, a.salariu_mediu
FROM salariat s, publicatie p,
(SELECT p1.nr_publicatie,AVG(salariu) salariu_mediu
FROM publicatie p1, salariat s1
WHERE p1.cod_salariat = s1.cod_salariat
GROUP BY p1.nr_publicatie) a
WHERE p.nr_publicatie = a.nr_publicatie
AND s.cod_salariat = p.cod_salariat
AND s.salariu > a.salariu_mediu;
Exemplu:
Să se obţină numele salariaţilor care nu cunosc nici o limbă străină.
SELECT nume, prenume
FROM salariat
WHERE NOT EXISTS
(SELECT *
FROM limba
WHERE limba.cod_salariat = salariat.cod_salariat
AND limba_cun IS NOT NULL);
Exemplu:
Să se afişeze graficienii care au întârziat să predea frame-urile.
a) cu sincronizare:
SELECT nume, prenume
FROM salariat
WHERE EXISTS
(SELECT *
FROM realizeaza r
WHERE salariat.cod_salariat=r.cod_salariat
AND data_lim < SYSDATE);
b) fără sincronizare:
SELECT nume, prenume
FROM salariat
WHERE cod_salariat IN
(SELECT DISTINCT cod_salariat
FROM realizeaza
WHERE data_lim < SYSDATE);
Exemplu:
Să se determine revistele coordonate de redactori şefi care nu cunosc limba
în care sunt scrise. Se ştie că în urma inspectării vizuale a rezultatului interogării se
poate decide schimbarea redactorilor şefi ai revistelor respective, de aceea se
doreşte blocarea înregistrărilor găsite.
SELECT p.nr_publicatie
FROM salariat s, publicatie p
WHERE s.cod_salariat = p.cod_salariat
AND p.limba NOT IN
(SELECT limba_cun
FROM limba
WHERE limba.cod_salariat = s.cod_salariat)
FOR UPDATE OF p.cod_salariat;
Subinterogări

O caracteristică foarte puternică a limbajului SQL sunt subinterogările


(numite şi selecţii), care, aşa cum sugerează şi numele, se referă la o instrucţiune
SELECT care conţine o instrucţiune SELECT subordonată.
De cele mai multe ori, pentru a implementa anumite interogări, nu este
suficientă o singură cerere SELECT ci sunt necesare subcereri.
Subcererile sunt comenzi SELECT încapsulate în oricare din clauzele ,
SELECT, WHERE, HAVING, FROM, numită instrucţiune „părinte“.
Dacă subcererea urmează clauzei WHERE sau HAVING, ea poate conţine
unul dintre operatorii ALL, ANY, IN (=ANY), EXIST, NOT IN (!=ALL) care sunt
specifici cererilor care întorc mai multe linii (multiple-row subquery) sau unul
dintre operatorii de comparare (=, <, >, >=, <=, <>) care sunt specifici cererilor
care întorc o singură linie (single-row subquery).
Utilizând subcereri, se pot construi interogări complexe pe baza unor
instrucţiuni simple. Subcererile mai sunt numite instrucţiuni SELECT imbricate
sau interioare.

Subcererea returnează o valoare care este utilizată de către instrucţiunea


„părinte“. Utilizarea unei subcereri este echivalentă cu efectuarea a două cereri
secvenţiale şi utilizarea rezultatului cererii interne ca valoare de căutare în cererea
externă (principală).
Subcererile pot fi utilizate în următoarele situaţii:
pentru a furniza valori care intervin în condiţiile din clauzele WHERE,
HAVING şi START WITH ale instrucţiunilor SELECT;
pentru a defini o mulţime de linii care urmează să fie inserată în tabelul
destinaţie al unei instrucţiuni INSERT sau CREATE TABLE;
pentru a defini o mulţime de linii care urmează să fie inserate într-o
vizualizare sau vizualizare materializată, prin intermediul unei
instrucţiuni CREATE VIEW sau CREATE MATERIALIZED VIEW;
pentru a defini una sau mai multe valori care urmează să fie atribuite unor
linii existente într-o instrucţiune UPDATE;
pentru a defini un tabel asupra căruia va opera cererea externă (plasarea
subcererii în clauza FROM sau în instrucţiunile INSERT, UPDATE,
DELETE).
Subcererile trebuie incluse între paranteze şi trebuie plasate în partea dreaptă
a operatorului de comparare. Subcererea nu poate conţine clauza ORDER BY.
De obicei, subinterogările sunt folosite în clauza WHERE, ca modalitate de
limitare a rândurilor returnate în setul de rezultate al interogării externe. Aceasta
poate fi o modalitate foarte flexibilă de selectare a datelor.
O regulă esenţială de sintaxă este ca subinterogarea să fie încadrată de paranteze.
Orice operaţie efectuată cu o subinterogare poate fi făcută şi printr-o uniune.

Subinterogări necorelate

O subinterogare necorelată (noncorrelated subselect) este o subinterogare în


care interogarea internă nu face nici o referire la interogarea externă care o conţine.
Subcererile necorelate returnează o valoare care este utilizată de cererea
externă (cererea principală). Cererile care conţin subcereri necorelate sunt evaluate
în modul următor:
cererea internă este executată prima şi determină o valoare (sau o
mulţime de valori);
cererea externă se execută o singură dată, utilizând valorile returnate de
cererea internă.
În general, o cerere imbricată, necorelată are următoarea formă:
SELECT lista_select
FROM nume_tabel
WHERE expresie operator (SELECT lista_select
FROM nume_tabel);
În această sintaxă, identificatorul operator poate fi de tip:
single-row operator (>, =, >=, <, <>, <=), care poate fi utilizat dacă
subcererea returnează o singură linie;
multiple-row operator (IN, ANY, ALL), care poate fi folosit dacă
subcererea returnează mai mult de o linie.
Operatorul ANY, care este sinonim cu operatorul SOME, determină
compararea unei valori cu fiecare valoare returnată de o subcerere. Astfel, <ANY
are semnificaţia „mai mic decât maximul“; >ANY înseamnă „mai mare decât
minimul“; =ANY este echivalent cu operatorul IN. Operatorul ALL compară o
valoare cu toate valorile returnate de o subcerere. Astfel, <ALL are semnificaţia
„mai mic decât minimul“, iar >ALL este echivalent cu „mai mare decât maximul“.
Operatorul NOT poate fi utilizat în combinaţie cu IN, ANY şi ALL.
În utilizarea unei subcereri se impun anumite reguli.
Subcererea trebuie inclusă între paranteze.
Pentru claritate, subcererea se plasează în partea dreaptă a operatorului de
comparaţie.
Înainte de versiunea Oracle8i, subcererile nu puteau să conţină clauza
ORDER BY. Începând cu Oracle8i, clauza ORDER BY poate fi utilizată şi
este chiar obligatorie în subcerere pentru a efectua analiza top-n (cererea
care efectuează analiza top-n returnează cele mai mari sau cele mai mici
n valori ale unei coloane).
Operatorul folosit trebuie să fie conform cu tipul cererii. Cererea va
genera o eroare dacă este utilizat un operator single-row în faţa unei
subcereri care returnează mai mult de o linie. De asemenea, dacă
subcererea nu returnează nici o linie, apare o eroare.
Server-ul Oracle nu impune nici o limită asupra numărului de subcereri.
Limita acestora depinde de dimensiunea buffer-ului pe care îl utilizează cererea.

Exemple:

• Afişaţi toate limbile în care nu există nici un film în inventarul magazinului de


produse video.

SELECT LIMBA_COD, LIMBA_NUME


FROM LIMBA
WHERE LIMBA_COD NOT IN
(SELECT DISTINCT LIMBA_COD
FROM FILM_LIMBA)
ORDER BY LIMBA_COD

LIMBA_COD LIMBA_NUME
Ja Japoneza
Ko Coreana
ni Olandeza
ru Rusa
zh Chineza

Interogarea internă returnează o listă cu codurile de limbă asociate filmelor în


tabelul FILM_LIMBA. Cuvântul cheie DISTINCT elimină rândurile duplicate din
setul de rezultate .
Interogarea internă rulată independent, pentru a vă ajuta să înţelegeţi cum
funcţionează:
SELECT DISTINCT LIMBA_COD FROM FILM_LIMBA;
LIMBA_COD
-------------------------------------------
de (Germana)
en (Engleza)
es (Spaniola)
fr (Franceza)

• Proprietarul magazinului vrea să vadă efectul recentei creşteri de preţuri şi are


nevoie de o listă a tranzacţiilor (TRANZACTIE_ID) în care clientul a plătit mai
mult decât taxa medie (INCHIRIAT_TAXA) pentru un film. Iată cum arată
interogarea:

SELECT DISTINCT TRANZACTIE_ID


FROM FILM_INCHIRIAT
WHERE INCHIRIAT_TAXA>
(SELECT AVG(INCHIRIAT_TAXA) FROM FILM_INCHIRIAT)

Interogarea internă calculează media taxelor de închiriere, iar interogarea externă


găseşte apoi toate rândurile din tabelul FILM_INCHIRIAT pentru care valoarea
INCHIRIAT_TAXA depăşeşte media.
Cuvântul cheie DISTINCT elimină tranzacţiile duplicate.

• Rezultatele interogării anterioare ar fi mai utile pentru proprietarul magazinului


dacă ar include şi data tranzacţiei. O modalitate de a realiza acest lucru este şi
adăugăm o uniune cu tabelul CLIENT_TRANZACTIE în interogarea externă.
Totuşi, deoarece tocmai aţi învăţat despre subinterogari, să facem acelaşi lucru
folosind încă o subinterogare. Iată cum arată interogarea:

SELECT TRANZACTIE_ID, TRANZACTIE_DATA AS TRANZ_DATA


FROM CLIENT_TRANZACTIE
WHERE TRANZACTIE_ID IN
(SELECT DISTINCT TRANZACTIE_ID FROM FILM_INCH,
WHERE INCH_TAXA > (SELECT AVG ( INCHIRIAT_TAXA)
FROM FILM_INCHIRIAT)

TRANZACTIE_ID TRANZ_DATA
9 03/01/2005
10 03/01/2005
Exemplu(din galeria de arta):
a) Să se afişeze titlul, codul artistului şi valoarea operelor create de artistul
căruia îi aparţine opera având codul 180 şi care se află expuse în aceeaşi galerie cu
operele al căror cod este 100 sau 110. Se presupune că o operă are un singur autor.
SELECT titlu, cod_artist, valoare
FROM opera
WHERE cod_artist = (SELECT cod_artist
FROM opera
WHERE cod_opera = 180)
AND cod_galerie IN (SELECT cod_galerie
FROM opera
WHERE cod_opera IN (100, 110));
b) Să se determine artistul pentru care valoare medie a operelor sale de artă
este minimă.
SELECT cod_artist, AVG(valoare)
FROM opera
GROUP BY cod_artist
HAVING AVG(valoare) = (SELECT MIN(AVG(valoare))
FROM opera
GROUP BY cod_artist);
c) Pentru fiecare artist, să se afişeze titlul şi valoarea celei mai ieftine opere
de artă expuse în muzeu.
SELECT titlu, cod_artist, valoare
FROM opera
WHERE valoare IN (SELECT MIN(valoare)
FROM opera
GROUP BY cod_artist);
d) Să se afişeze operele de artă care nu sunt expuse în galeria având codul
30 şi a căror valoare este mai mică decât a unei opere din galeria 30.
SELECT cod_opera, titlu, valoare
FROM opera
WHERE valoare < ANY (SELECT valoare
FROM opera
WHERE cod_galerie = 30)
AND cod_galerie <> 30;
Dacă operatorul ANY se înlocuieşte cu operatorul ALL, cererea precedentă
returnează operele care nu sunt expuse în galeria 30 şi a căror valoare este mai
mică decât a oricărei opere din galeria respectivă.
e) Să se afişeze cele mai scumpe 3 opere de artă din muzeu.
SELECT ROWNUM "Nr.Crt", titlu, valoare
FROM (SELECT titlu, valoare
FROM opera
ORDER BY valoare DESC)
WHERE ROWNUM <= 3;
Exemplu:
Din punct de vedere logic, următoarea cerere ar trebui să returneze titlurile
operelor care nu sunt expuse în galeriile unde se află lucrările artistului având
codul 60.
SELECT titlu
FROM opera
WHERE cod_galerie NOT IN (SELECT cod_galerie
FROM opera
WHERE cod_artist = 60);
Dacă pentru una dintre opere valoarea coloanei cod_galerie este null,
întreaga cerere nu va returna nici o linie, chiar dacă există înregistrări cu
proprietatea cerută. Justificarea este că toate condiţiile în care unul dintre operanzi
este null au, de asemenea, valoarea null. Prin urmare, ori de câte ori este posibil ca
în rezultatul subcererii să apară valori null, nu trebuie folosit operatorul NOT IN.
Operatorul NOT IN este echivalent cu <>ALL. Dacă se utilizează operatorul IN, nu
mai este nici o problemă dacă în rezultatul subcererii apar valori null. Operatorul
IN este echivalent cu =ANY.
Exemplu:
Să se afişeze titlurile operelor care sunt expuse în galeriile unde se află
lucrările artistului având codul 60.
SELECT titlu
FROM opera
WHERE cod_galerie IN (SELECT cod_galerie
FROM opera
WHERE cod_artist = 60);
Pentru a evita obţinerea de valori null în rezultatul unei cereri care utilizează
operatorul NOT IN, se poate specifica o condiţie în subcerere:
SELECT titlu
FROM opera
WHERE cod_galerie NOT IN (SELECT cod_galerie
FROM opera
WHERE cod_artist = 60
AND cod_galerie IS NOT NULL);

Subcereri (Subinterogări) corelate


O subinterogare corelată (correlated subselect) este o subinterogare în care
interogarea internă referă valorile furnizate de interogarea externă.
Subcererile corelate sunt utilizate pentru procesarea linie cu linie a
interogărilor. O subcerere este corelată dacă face referinţă la o coloană dintr-un
tabel specificat în instrucţiunea „părinte“. O astfel de subcerere este evaluată o dată
pentru fiecare linie procesată de instrucţiunea „părinte“, care poate fi SELECT,
UPDATE sau DELETE.
Subcererile corelate permit compararea valorilor unei linii cu date
determinate pe baza acestor valori.
Cererile corelate se execută astfel:
cererea externă determină o linie candidat;
cererea internă este executată utilizând valoarea liniei candidat;
valorile rezultate din cererea internă sunt utilizate pentru calificarea sau
descalificarea liniei candidat;
paşii precedenţi se repetă până când nu mai există linii candidat.
Forma generală a unei subcereri corelate este următoarea:
SELECT nume_coloană_1[, nume_coloană_2 …]
FROM nume_tabel_1 extern
WHERE expresie operator
(SELECT nume_coloană_1 [, nume_coloană_2 …]
FROM nume_tabel_2
WHERE expresie_1 = extern.expresie_2);

Exemplu:

Proprietarul magazinului vrea să transmită prin poştă un cupon valoric


tuturor clienţilor care au plătit mai mult de 15$ pentru o singură tranzacţie de
închiriere.

SELECT DISTINCT CLIENT_CONT_ID


FROM CLIENT_TRANZACTIE A
WHERE 15 < (SELECT SUM (INCHIRIAT_TAXA)
FROM FILM_INCHIRIATB
WHERE A.TRANZACTIE _ID = B.TRANZACTIE_ID)

CLIENT_CONT_ID
2
7
9
Observaţi pseudonimele asociate numelor de tabele din interogările internă
şi externă, precurn şi folosirea acestora în clauza WHERE a interogării interne.
Acesta este elementul de identificare al unei subinterogări corelate. Interogarea
externă selectează o lista de valori CLIENT_CONT_ID distincte din tabelul
CLIENT_TRANZACTIE. Fiecare valoare găsită este transmisă interogării interne,
care este rulată pentru a calcula suma taxelor de închiriere din tranzacţia
respectivă. Dacă suma taxelor de închiriere este mai mare sau egală cu 15, atunci
clauza WHERE din interogarea externă ia valoarea logică „adevărat", iar rândul
CLIENT_ID este adăugat în setul de rezultate.

Vizualizări în linie

Foarte puţine implementări, printre care Oracle, permit folosirea unei subinterogări
în clauza FROM a unei interogări, într-o construcţie numită vizualizare în linie
(inline view). Această construcţie permite care setul de rezultate al unei interogări
să fie tratat ca şi cum ar fi un tabel sau o vizualizare predefinită. Iată un exemplu:
• Această interogare află numărul maxim de închirieri ale unui singur film;

SELECT MAX(INCHIRIAT_NUMAR) AS MAX_INCHIRIAT_NUMAR


FROM (SELECT FILM_ID, NUMAR(*) AS INCHIRIAT_NUMAR
FROM FILM_INCHIRIAT GROUP BY FILM_ID)

MAX_INCH_NUMAR
5

Interogarea internă calculează numărul de închirieri pentru fiecare valoare


FILM_ID. Interogarea externă selectează valoarea maximă INCHIRIAT_NUMAR
din interogarea internă, tratată ca şi cum ar fi o vizualizare predefinită. Nu există
nici o limită în privinţa modurilor de utilizare a vizualizărilor în linie - puteţi chiar
să le uniţi cu alte tabele sau vizualizări.
Exemplu de subcereri corelate pentru galeria de arta):

a) Să se afişeze informaţii despre operele de artă a căror valoare depăşeşte


valoarea medie a celor expuse în aceeaşi galerie.
SELECT titlu, valoare, cod_galerie
FROM opera o
WHERE valoare > (SELECT AVG(valoare)
FROM opera
WHERE cod_galerie = o.cod_galerie);
b) Să se afişeze codul, numele şi prenumele artiştilor care au cel puţin două
opere de artă expuse în muzeu.
SELECT cod_artist, nume, prenume
FROM artist a
WHERE 2 <= (SELECT COUNT(*)
FROM opera
WHERE cod_artist = a.cod_artist);
Server-ul Oracle evaluează subcererea corelată precedentă urmând
succesiunea de paşi prezentată în continuare.
1) Selectează o linie din tabelul specificat în cererea externă (aceasta va fi
linia candidat curentă).
2) Reţine valoarea coloanei referite în subcerere din această linie candidat
(în cazul subcererii de mai sus, coloana referită în subcerere este
a.cod_artist).
3) Efectuează subcererea, considerând condiţia acesteia ca facând referinţă
la valoarea liniei candidat din cererea externă (în exemplul precedent,
funcţia COUNT(*) este evaluată pe baza valorii lui a.cod_artist
determinată la pasul 2).
4) Evaluează clauza WHERE a cererii externe pe baza rezultatelor returnate
de cererea internă la pasul 3. Adică, se determină dacă linia candidat este
selectată în rezultatul cererii (în exemplul precedent, numărul de opere
ale unui artist, evaluat de subcerere, este comparat cu 2 în clauza WHERE
a cererii externe, iar dacă această condiţie este satisfăcută, linia
corespunzătoare artistului respectiv va face parte din rezultat).
5) Procedura se repetă pentru următoarele linii candidat din tabel, până când
sunt procesate toate liniile tabelului.
Operatorul EXISTS
În instrucţiunile SELECT imbricate, este permisă utilizarea oricărui operator
logic. Pentru a testa dacă valoarea recuperată de cererea externă există în mulţimea
valorilor regăsite de cererea internă corelată, se poate utiliza operatorul EXISTS.
Dacă subcererea returnează cel puţin o linie, operatorul returnează valoarea TRUE.
În caz contrar, va fi returnată valoarea FALSE.
Operatorul EXISTS asigură că nu mai este continuată căutarea în cererea
internă după ce aceasta regăseşte o linie.
Exemplu:
a) Să se determine codul, numele şi prenumele artiştilor care au cel puţin o
operă de artă expusă în muzeu.
SELECT cod_artist, nume, prenume
FROM artist a
WHERE EXISTS (SELECT 'x'
FROM opera
WHERE cod_artist = a.cod_artist);
Întrucât nu este necesar ca instrucţiunea SELECT interioară să returneze o
anumită valoare, se poate selecta o constantă. De altfel, din punct de vedere al
performanţei, selectarea unei constante asigură mai multă rapiditate decât
selectarea unei coloane.
Ca alternativă a lui EXISTS, poate fi utilizat operatorul IN. Exemplul
precedent poate fi rezolvat prin instrucţiunea următoare:
SELECT cod_artist, nume, prenume
FROM artist
WHERE cod_artist IN (SELECT cod_artist
FROM opera);
b) Să se determine operele care nu sunt menţionate în nici o sursă
bibliografică.
SELECT cod_opera, titlu
FROM opera o
WHERE NOT EXISTS (SELECT 'x'
FROM mentionata_in
WHERE cod_opera = o.cod_opera);
Acest exemplu poate fi rezolvat şi printr-o subcerere necorelată, utilizând
operatorul NOT IN:
SELECT cod_opera, titlu
FROM opera
WHERE cod_opera NOT IN (SELECT cod_opera
FROM ment_in
WHERE cod_opera IS NOT NULL);

Instrucţiuni LMD corelate


Subcererile corelate pot fi utilizate pentru actualizarea sau ştergerea de
înregistrări dintr-un tabel pe baza liniilor altui tabel. Forma generală a unei
instrucţiuni corelate UPDATE, respectiv DELETE, este următoarea:
UPDATE nume_tabel_1 alias_1
SET nume_coloană = (SELECT expresie
FROM nume_tabel_2 alias_2
WHERE alias_1.nume_coloană =
alias_2.nume_coloană);
DELETE FROM nume_tabel_1 alias_1
WHERE expresie operator
(SELECT expresie
FROM nume_tabel_2 alias_2
WHERE alias_1.nume_coloană =
alias_2.nume_coloană);
Exemplu:
Se presupune că valorile operelor sunt mărite cu 20% din costul ultimei
poliţe de asigurare încheiate. Să se actualizeze corespunzător valoarea operelor
care beneficiază de cel puţin o poliţă de asigurare.
UPDATE opera
SET valoare = (SELECT opera.valoare +
polita_asig.valoare*0.20
FROM polita_asig
WHERE cod_opera = opera.cod_opera
AND semnat_contract =
(SELECT MAX(semnat_contract)
FROM polita_asig
WHERE cod_opera = opera.cod_opera))
WHERE opera.cod_opera IN (SELECT DISTINCT cod_opera
FROM polita_asig);
Exemplu:
Pentru fiecare autor care are mai mult de 10 creaţii expuse în muzeu, să se
şteargă ultima operă creată de acesta.
DELETE FROM opera o1
WHERE cod_artist =
(SELECT cod_artist
FROM opera o2
WHERE cod_artist = o1.cod_artist
AND data_crearii =
(SELECT MAX(data_crearii)
FROM opera
WHERE cod_artist = o2.cod_artist)
AND 10 >
(SELECT COUNT(*)
FROM opera
WHERE cod_artist = o2.cod_artist));

Clauza WITH
Cu ajutorul clauzei WITH se poate defini un bloc de cerere înainte ca acesta
să fie utilizat într-o interogare. Clauza permite reutilizarea aceluiaşi bloc de cerere
într-o instrucţiune SELECT complexă. Acest lucru este util atunci când o cerere
face referinţă de mai multe ori la acelaşi bloc de cerere, care conţine operaţii join şi
funcţii agregat. Folosind clauza WITH, server-ul Oracle regăseşte rezultatele unui
bloc de cerere şi le stochează în spaţiul tabel temporar al utilizatorului, ceea ce
poate determina îmbunătăţirea performanţelor.
Exemplu:
Utilizând clauza WITH, să se scrie o cerere care afişează numele artiştilor şi
valoarea totală a operelor acestora. Se vor considera artiştii a căror valoare totală a
operelor este mai mare decât media valorilor totale ale operelor tuturor artiştilor.
WITH
val_artist AS (SELECT nume, SUM(valoare) AS total
FROM opera o, artist a
WHERE o.cod_artist = a.cod_artist
GROUP BY nume),
val_medie AS (SELECT SUM(total)/COUNT(*) AS medie
FROM val_artist)
SELECT *
FROM val_artist
WHERE total > (SELECT medie
FROM val_medie)
ORDER BY nume;
Intern, clauza WITH este tratată ca o vizualizare inline (subcerere în clauza
FROM) sau ca un tabel temporar. Optimizorul alege decizia adecvată pe baza
costului sau beneficiului stocării temporare a rezultatelor clauzei WITH.
Observaţii:
Clauza WITH poate fi folosită numai pentru instrucţiuni SELECT.
Un nume de cerere este vizibil tuturor blocurilor din clauza WITH
definite ulterior (inclusiv subcererilor acestora). De asemenea, un nume
de cerere este vizibil cererii principale şi subcererilor acesteia.
Când un nume de cerere coincide cu numele unui tabel, numele blocului
de cerere are precedenţă asupra numelui tabelului.
Clauza WITH poate conţine mai mult decât o singură cerere. În acest caz,
cererile sunt separate prin virgule.
Subcereri scalare
Subcererile scalare în SQL returnează valoarea unei singure coloane
corespunzătoare unei linii. Dacă subcererea returnează 0 linii, valoarea subcererii
scalare este null. Dacă subcererea returnează mai mult de o linie, server-ul
generează o eroare.
Subcererile scalare erau acceptate în Oracle8i doar în anumite cazuri, cum ar
fi clauzele FROM şi WHERE ale instrucţiunii SELECT sau clauza VALUES a
instrucţiunii INSERT. Utilitatea subcererilor scalare a fost extinsă în Oracle9i.
Astfel, ele pot apărea în:
condiţiile şi expresiile care fac parte din DECODE sau CASE;
toate clauzele instrucţiunii SELECT, cu excepţia lui GROUP BY;
în partea stângă a operatorului, în clauzele SET şi WHERE ale
instrucţiunii UPDATE.
Subcererile scalare nu sunt permise în următoarele situaţii:
ca valori implicite pentru coloane sau ca expresii hash pentru grupări;
în clauza RETURNING a instrucţiunilor LMD;
în clauza GROUP BY, constrângerile de tip CHECK, condiţiile WHEN;
în instrucţiunile care nu sunt legate de cereri, cum ar fi CREATE
PROFILE.
Exemplu:
Să se afişeze codul, titlul operelor şi numele artistului doar dacă acesta este
Brâncuşi. În caz contrar, se va afişa şirul „alt artist“.
SELECT cod_opera, titlu,
(CASE WHEN cod_artist =
(SELECT cod_artist
FROM artist
WHERE nume = 'Brancusi')
THEN 'Brancusi'
ELSE 'Alt artist' END) artist
FROM opera;

2.4.4. Funcţii grup şi clauza GROUP BY

Clauza GROUP BY este utilizată pentru a diviza liniile unui tabel în grupuri.
Pentru a returna informaţia corespunzătoare fiecărui astfel de grup, pot fi utilizate
funcţiile agregat. Ele pot apărea în clauzele SELECT, ORDER BY şi HAVING.
Server-ul Oracle aplică aceste funcţii fiecărui grup de linii şi returnează un singur
rezultat pentru fiecare mulţime.
Dintre funcţiile grup definite în sistemul Oracle, se pot enumera: AVG,
SUM, MAX, MIN, COUNT, STDDEV, VARIANCE, DENSE_RANK, RANK, FIRST,
LAST, GROUP_ID, GROUPING, GROUPING_ID etc. Tipurile de date ale
argumentelor funcţiilor grup pot fi CHAR, VARCHAR2, NUMBER sau DATE.
Funcţiile AVG, SUM, STDDEV şi VARIANCE operează numai asupra valorilor
numerice. Funcţiile MAX şi MIN pot opera asupra valorilor numerice, caracter sau
de tip dată calendaristică.
Toate funcţiile grup, cu excepţia lui COUNT(*), ignoră valorile null.
COUNT(expresie) returnează numărul de linii pentru care expresia dată nu are
valoarea null. Funcţia COUNT returnează un număr mai mare sau egal cu zero şi
nu întoarce niciodată valoarea null.
Când este utilizată clauza GROUP BY, server-ul sortează implicit mulţimea
rezultată în ordinea crescătoare a valorilor coloanelor după care se realizează
gruparea.
În clauza GROUP BY a unei cereri se pot utiliza operatorii ROLLUP şi
CUBE. Aceştia sunt disponibili începând cu versiunea Oracle8i.

Operatorul ROLLUP
Operatorul ROLLUP produce o mulţime care conţine liniile obţinute în urma
grupării obişnuite şi linii pentru subtotaluri. Acest operator furnizează valori
agregat şi superagregat corespunzătoare expresiilor din clauza GROUP BY.
Operatorul ROLLUP poate fi folosit pentru extragerea de statistici şi informaţii
totalizatoare din mulţimile rezultate. Acest operator poate fi util la generarea de
rapoarte, diagrame şi grafice.
Operatorul ROLLUP creează grupări prin deplasarea într-o singură direcţie,
de la dreapta la stânga, de-a lungul listei de coloane specificate în clauza GROUP
BY. Apoi, se aplică funcţia agregat acestor grupări. Dacă sunt specificate n expresii
în operatorul ROLLUP, numărul de grupări generate va fi n + 1. Liniile care se
bazează pe valoarea primelor n expresii se numesc linii obişnuite, iar celelalte se
numesc linii superagregat.
Dacă în clauza GROUP BY sunt specificate n coloane, pentru a produce
subtotaluri fără operatorul ROLLUP ar fi necesare n + 1 instrucţiuni SELECT
conectate prin UNION ALL. Aceasta ar face execuţia cererii ineficientă deoarece
fiecare instrucţiune SELECT determină accesarea tabelului. Operatorul ROLLUP
determină rezultatele efectuând un singur acces la tabel şi este util atunci când sunt
implicate multe coloane în producerea subtotalurilor.
Exemplu:
Să se afişeze codurile de galerii mai mici decât 50, iar pentru fiecare dintre
acestea şi pentru fiecare autor care are opere expuse în galerie, să se listeze
valoarea totală a lucrărilor sale. De asemenea, se cere valoarea totală a operelor
expuse în fiecare galerie. Rezultatul va conţine şi valoarea totală a operelor din
galeriile având codul mai mic decât 50, indiferent de codul autorului.
SELECT cod_galerie, cod_artist, SUM(valoare)
FROM opera
WHERE cod_galerie < 50
GROUP BY ROLLUP(cod_galerie, cod_artist);
Instrucţiunea precedentă va avea un rezultat de forma:
COD_GALERIE COD_ARTIST SUM(VALOARE)
10 50 14000
10 60 10000
10 24000
40 50 8080
40 8080
32080

În rezultatul prezentat anterior se pot distinge 3 tipuri de linii.


1) Prima linie reprezintă suma operelor artistului care are codul 50, expuse
în galeria având codul 10. În mod similar se interpretează a doua şi a
patra linie din rezultat.
2) Linia a treia şi a cincea din rezultat conţin valoarea totală a operelor din
galeria al cărei cod este 10, respectiv 40. Aceste linii se disting prin faptul
că valoarea coloanei cod_artist este null.
3) Ultima linie conţine suma valorilor tuturor operelor din galeriile al căror
cod este 10 sau 40. Valoarea afişată este obţinută prin însumarea valorilor
de pe a treia, respectiv a cincea linie. Întrucât această linie corespunde
totalului general, ea conţine valoarea null pe toate coloanele, cu excepţia
câmpului SUM(valoare).
Operatorul CUBE
Operatorul CUBE grupează liniile selectate pe baza valorilor tuturor
combinaţiilor posibile ale expresiilor specificate şi returnează câte o linie
totalizatoare pentru fiecare grup. Acest operator este folosit pentru a produce
mulţimi de rezultate care sunt utilizate în rapoarte. În vreme ce ROLLUP produce
subtotalurile doar pentru o parte dintre combinaţiile posibile, operatorul CUBE
produce subtotaluri pentru toate combinaţiile posibile de grupări specificate în
clauza GROUP BY, precum şi un total general.
Dacă există n coloane sau expresii în clauza GROUP BY, vor exista 2n
combinaţii posibile superagregat. Din punct de vedere matematic, aceste
combinaţii formează un cub n-dimensional, de aici provenind numele operatorului.
Pentru producerea de subtotaluri fără ajutorul operatorului CUBE ar fi necesare 2n
instrucţiuni SELECT conectate prin UNION ALL.
Exemplu:
Să se afişeze valoarea totală a operelor de artă ale unui autor, expuse în
cadrul fiecărei galerii având codul mai mic decât 50. De asemenea, să se afişeze
valoarea totală a operelor din fiecare galerie având codul mai mic decât 50,
valoarea totală a operelor fiecărui autor indiferent de galerie şi valoarea totală a
operelor din galeriile având codul mai mic decât 50.
SELECT cod_galerie, cod_artist, SUM(valoare)
FROM opera
WHERE cod_galerie < 50
GROUP BY CUBE(cod_galerie, cod_artist);
Instrucţiunea precedentă va genera un rezultat de forma următoare:
COD_GALERIE COD_ARTIST SUM(VALOARE)
10 50 14000
10 60 10000
10 24000
40 50 8080
40 8080
50 22080
60 10000
32080

În plus faţă de rezultatul corespunzător operaţiei ROLLUP, operatorul CUBE


a produs linii care reprezintă suma valorilor operelor pentru fiecare artist care a
expus în galerii având codul mai mic decât 50. Aceste linii se disting prin faptul că
valoarea coloanei cod_galerie este null.

Funcţia GROUPING
Funcţia GROUPING poate fi utilizată alături de operatorii CUBE şi
ROLLUP pentru a arăta modul cum a fost obţinută o valoare totalizatoare. Această
funcţie acceptă un singur argument, care trebuie să fie una dintre expresiile
specificate în clauza GROUP BY.
O valoare null a expresiei din argumentul funcţiei GROUPING poate
proveni din tabelul de bază (valoare null stocată) sau poate fi o valoare null creată
de operaţia ROLLUP sau CUBE ca rezultat al unei funcţii grup asupra expresiei
respective.
Funcţia GROUPING returnează valoarea 0 sau 1. Valoarea 0 returnată de
funcţia GROUPING pe baza unei expresii poate indica fie că expresia a fost
utilizată pentru calculul valorii agregat, fie că valoarea null a expresiei este o
valoare null stocată. Valoarea 1 returnată de funcţia GROUPING pe baza unei
expresii poate indica fie că expresia nu a fost utilizată pentru calculul valorii
agregat, fie că valoarea null a expresiei este creată de ROLLUP sau CUBE ca
rezultat al grupării.
Valorile returnate de funcţia GROUPING sunt utile pentru:
determinarea nivelului de agregare al unui subtotal dat, adică a grupului
sau grupurilor pe care se bazează subtotalul respectiv;
identificarea provenienţei unei valori null a unei expresii calculate, dintr-
una din liniile mulţimii rezultat.
Exemplu:
SELECT cod_galerie, cod_artist, SUM(valoare),
GROUPING(cod_galerie), GROUPING(cod_artist)
FROM opera
WHERE cod_galerie < 50
GROUP BY ROLLUP(cod_galerie, cod_artist);
SUM GROUPING GROUPING
COD_GALERIE COD_ARTIST
(VALOARE) (COD_GALERIE) (COD_ARTIST)
10 50 14000 0 0
10 60 10000 0 0
10 24000 0 1
40 50 8080 0 0
40 8080 0 1
32080 1 1
Pe prima linie din acest rezultat, valoarea totalizatoare reprezintă suma
valorilor operelor artistului având codul 50, în cadrul galeriei 10. Pentru a calcula
această valoare au fost luate în considerare coloanele cod_galerie şi cod_artist.
Prin urmare, expresiile GROUPING(cod_galerie) şi GROUPING(cod_artist) au
valoarea 0 pentru prima linie din rezultat.
Pe linia a treia se află valoarea totală a operelor din galeria având codul 10.
Această valoare a fost calculată luând în considerare doar coloana cod_galerie,
astfel încât GROUPING (cod_galerie) şi GROUPING(cod_artist) au valorile 0,
respectiv 1.
Pe ultima linie din rezultat se află valoarea totală a operelor din galeriile
având codul mai mic decât 50. Nici una dintre coloanele cod_galerie şi cod_artist
nu au intervenit în calculul acestui total, prin urmare valorile corespunzătoare
expresiilor GROUPING(cod_galerie) şi GROUPING(cod_artist) sunt 0.
Clauza GROUPING SETS
GROUPING SETS reprezintă o extensie a clauzei GROUP BY care permite
specificarea unor grupări multiple de date. Utilizarea acestei opţiuni facilitează
analiza datelor în mai multe dimensiuni.
Această extensie, apărută în sistemul Oracle9i, permite scrierea unei singure
instrucţiuni SELECT pentru a specifica grupări diferite (care pot conţine operatorii
ROLLUP şi CUBE), în loc de mai multe instrucţiuni SELECT combinate prin
operatorul UNION ALL. De altfel, reuniunea rezultatelor mai multor cereri este
ineficientă întrucât necesită mai multe parcurgeri ale aceloraşi date.
Operatorii ROLLUP şi CUBE pot fi consideraţi cazuri particulare de mulţimi
de grupări. Au loc următoarele echivalenţe:
CUBE(a, b, c) GROUPING SETS
((a, b, c), (a, b), (a, c), (b, c), (a),
(b), (c), ())
ROLLUP(a, b, GROUPING SETS
c) ((a, b, c), (a, b), (a), ())
Exemplu:
Considerând galeriile al căror cod este mai mic decât 50, să se calculeze
media valorilor operelor:
pentru fiecare galerie şi, în cadrul acesteia, pentru fiecare artist;
pentru fiecare artist şi, în cadrul acestuia, pentru anii de achiziţie
corespunzători.
SELECT cod_galerie, cod_artist,
TO_CHAR(data_achizitiei, 'yyyy') "an achizitie",
AVG(valoare) "Valoare medie"
FROM opera
WHERE cod_galerie < 50
GROUP BY GROUPING SETS
((cod_galerie, cod_artist),
(cod_artist, TO_CHAR(data_achizitiei, 'yyyy')));
Mulţimea rezultat este constituită din valorile medii pentru fiecare dintre
cele două grupuri şi are forma următoare:
COD_GALERIE COD_ARTIST an a Valoare medie
10 50 3500
10 60 2500
40 50 2020
50 2000 2380
50 2002 2300
60 2001 2000
60 2003 3000

Exemplul precedent poate fi rezolvat şi prin următoarea instrucţiune


compusă:
SELECT cod_galerie, cod_artist, NULL "an achizitie",
AVG(valoare) "Valoare medie"
FROM opera
GROUP BY cod_galerie, cod_artist
UNION ALL
SELECT NULL, cod_artist,
TO_CHAR(data_achizitiei, 'yyyy'), AVG(valoare)
FROM opera
GROUP BY cod_artist, TO_CHAR(data_achizitiei, 'yyyy');
În absenţa unui optimizor care analizează blocurile de cerere şi generează
planul de execuţie, cererea precedentă va parcurge de două ori tabelul de bază
(opera), ceea ce poate fi ineficient. Din acest motiv, este recomandată utilizarea
extensiei GROUPING SETS.

Coloane compuse
O coloană compusă este o colecţie de coloane care sunt tratate unitar în
timpul calculelor asupra grupurilor. Pentru a specifica o coloană compusă, aceasta
se include între paranteze. În operaţia ROLLUP(a, (b, c), d), coloanele b şi c
formează o coloană compusă şi sunt tratate unitar.
În general, coloanele compuse sunt utile pentru operaţiile ROLLUP, CUBE
şi GROUPING SETS. De exemplu, în CUBE sau ROLLUP coloanele compuse pot
determina eliminarea agregării de pe anumite niveluri.
Clauza GROUP BY ROLLUP(a, (b, c)) este echivalentă cu următoarea
instrucţiune compusă (în care se precizează doar forma clauzelor GROUP BY):
GROUP BY a, b, c UNION ALL
GROUP BY a UNION ALL
GROUP BY ( )
Astfel, (b, c) sunt tratate unitar şi operaţia ROLLUP nu va fi efectuată asupra
grupurilor în care coloanele b şi c nu apar simultan. Acest lucru este similar
situaţiei în care este definit un alias x pentru (b, c), iar specificaţia clauzei GROUP
BY este GROUP BY ROLLUP(a, x).
În instrucţiunea precedentă, GROUP BY () reprezintă instrucţiunea SELECT
cu valori null pentru coloanele a şi x. Această clauză este folosită pentru generarea
totalurilor generale:
SELECT null, null, coloană_agregat
FROM nume_tabel
GROUP BY ();
Următorul tabel prezintă câteva specificaţii care utilizează operatorii
ROLLUP, CUBE, GROUPING SETS, împreună cu instrucţiunile compuse
echivalente acestora:
GROUP BY ROLLUP(a, b, c) GROUP BY a, b, c UNION
ALL
GROUP BY a, b UNION
ALL
GROUP BY a
GROUP BY CUBE( (a, b), c) GROUP BY a, b, c UNION
ALL
GROUP BY a, b UNION
ALL
GROUP BY c UNION ALL
GROUP BY()
GROUP BY GROUPING SETS(a, b, GROUP BY a UNION ALL
c) GROUP BY b UNION ALL
GROUP BY c
GROUP BY GROUPING SETS GROUP BY a UNION ALL
(a, b, (b, c) ) GROUP BY b UNION ALL
GROUP BY b, c
GROUP BY GROUPING SETS( (a, b, GROUP BY a, b, c
c) )
GROUP BY GROUPING SETS(a, GROUP BY a UNION ALL
(b), ()) GROUP BY b UNION ALL
GROUP BY ()
GROUP BY GROUPING SETS (a, GROUP BY a UNION ALL
ROLLUP(b, c)) GROUP BY ROLLUP(b, c)

Exemplu:
Să se afişeze următoarele informaţii:
valoarea medie a operelor de artă din fiecare galerie;
valoarea medie a operelor de artă pentru fiecare galerie, iar în cadrul
acesteia pentru fiecare artist şi fiecare an de achiziţie;
media generală a tuturor valorilor operelor de artă.
SELECT cod_galerie, cod_artist,
TO_CHAR(data_achizitiei, 'yyyy') "an achizitie",
AVG(valoare) "Valoare medie"
FROM opera
GROUP BY ROLLUP
(cod_galerie,
(cod_artist, TO_CHAR(data_achizitiei, 'yyyy')));
Exemplul precedent poate fi rezolvat utilizând cererea compusă prezentată
mai jos. Folosirea coloanelor compuse este recomandată pentru asigurarea unei
execuţii eficiente.
SELECT cod_galerie, cod_artist,
TO_CHAR(data_achizitiei, 'yyyy'),
AVG(valoare) "Valoare medie"
FROM opera
GROUP BY cod_galerie, cod_artist,
TO_CHAR(data_achizitiei, 'yyyy')
UNION ALL
SELECT cod_galerie, TO_NUMBER(null), TO_CHAR(null),
AVG(valoare) "Valoare medie"
FROM opera
GROUP BY cod_galerie
UNION ALL
SELECT TO_NUMBER(null), TO_NUMBER(null), TO_CHAR(null),
AVG(valoare) "Valoare medie"
FROM opera
GROUP BY ();

Concatenarea grupărilor
Concatenarea grupărilor reprezintă o modalitate concisă de a genera
combinaţii de grupări. Acestea se specifică prin enumerarea mulţimilor de grupări
(grouping sets) şi a operaţiilor ROLLUP, CUBE separate prin virgulă. De exemplu,
expresia GROUP BY GROUPING SETS(a, b), GROUPING SETS(c, d) defineşte
grupările (a, c), (a, d), (b, c), (b, d).
Concatenarea mulţimilor de grupări este utilă atât pentru uşurinţa dezvoltării
cererilor, cât şi pentru aplicaţii. Codul SQL generat de aplicaţiile OLAP implică
deseori concatenarea mulţimilor de grupări, în care fiecare astfel de mulţime
defineşte grupările necesare pentru o dimensiune.
Exemplu:
Să se determine media valorilor operelor luând în considerare următoarele
grupări: (cod_galerie, cod_artist, an_achizitie), (cod_galerie, cod_artist),
(cod_galerie, an_achizitie), (cod_galerie).
SELECT cod_galerie, cod_artist,
TO_CHAR(data_achizitiei, 'yyyy') an_achizitie,
AVG(valoare)
FROM opera
GROUP BY cod_galerie, ROLLUP(cod_artist),
CUBE(TO_CHAR(data_achizitiei, 'yyyy'));

Funcţii analitice
Funcţiile analitice calculează o valoare agregat pe baza unui grup de
înregistrări. Ele diferă de funcţiile agregat prin faptul că, pentru fiecare grup, pot fi
returnate mai multe linii rezultat.
Aceste funcţii reprezintă ultimul set de operaţii efectuat la procesarea unei
interogări, înaintea clauzei ORDER BY. Din acest motiv, o funcţie analitică poate
apărea numai în lista SELECT sau în clauza ORDER BY.
Exemplu:
Pentru fiecare operă de artă, să se afle numărul de creaţii ale căror valori
sunt cu cel mult 1000 mai mici şi cu cel mult 2000 mai mari decât valoarea operei
respective.
SELECT titlu, valoare,
COUNT(*) OVER (ORDER BY valoare
RANGE BETWEEN 1000 PRECEDING
AND 2000 FOLLOWING) AS nr_dom
FROM opera;
Cuvântul cheie OVER indică faptul că funcţia operează pe mulţimea de
rezultate a cererii, adică după evaluarea celorlalte clauze. Opţiunea RANGE
defineşte, pentru fiecare linie, o „fereastră“ (o mulţime de linii). Funcţia analitică
va fi aplicată tuturor liniilor din această mulţime.

2.4.5. Interogări ierarhice

Interogările ierarhice permit regăsirea datelor pe baza unei relaţii ierarhice


care există între liniile tabelului. O bază de date relaţională nu stochează
înregistrările în mod ierarhic. Dacă există o relaţie ierarhică între liniile unui tabel,
un proces de parcurgere a unui arbore (tree walking) permite construirea ierarhiei.
O cerere ierarhică este o metodă de raportare, în ordine, a ramurilor arborelui.
În tabelul opera, se poate imagina o structură arborescentă pe baza valorilor
echivalente ale anilor corespunzători coloanelor data_crearii şi data_achizitiei.
Relaţia „părinte-copil“ a unei structuri arborescente permite controlul
direcţiei în care este parcursă ierarhia şi stabilirea rădăcinii ierarhiei.
Clauzele instrucţiunii SELECT care intervin în formularea unei cereri
ierarhice sunt START WITH şi CONNECT BY. Acestea au fost prezentate împreună
cu instrucţiunea SELECT, la începutul acestui capitol.
Pseudocoloana LEVEL poate fi utilă într-o cerere ierarhică. Aceasta
determină lungimea drumului de la rădăcină la un nod.
Operatorul PRIOR face referinţă la linia „părinte“. Plasarea acestui operator
determină direcţia interogării, dinspre „părinte“ spre „copil“ (top-down) sau invers
(bottom-up). Traversarea top-down, respectiv bottom-up a arborelui se realizează
prin specificări de forma următoare:
CONNECT BY PRIOR cheie_parinte = cheie_copil;
CONNECT BY PRIOR cheie_copil = cheie_parinte;
Operatorul PRIOR poate fi plasat în faţa oricărui membru al condiţiei
specificate în clauza CONNECT BY.
Liniile „părinte“ ale interogării sunt identificate prin clauza START WITH.
Pentru a găsi liniile „copil“, server-ul evaluează expresia din dreptul operatorului
PRIOR pentru linia „părinte“, şi cealaltă expresie pentru fiecare linie a tabelului.
Înregistrările pentru care condiţia este adevărată vor fi liniile „copil“. Spre
deosebire de START WITH, în clauza CONNECT BY nu pot fi utilizate subcereri.
Exemplu:
a) Să se afişeze codul, titlul, data creării şi data achiziţiei operelor, astfel
încât fiecare operă să fie urmată de cele achiziţionate în anul creării sale. Prima
linie afişată va fi cea corespunzătoare operei având codul 110.
SELECT cod_opera, titlu, data_crearii, data_achizitiei
FROM opera
START WITH cod_opera = 110
CONNECT BY PRIOR TO_CHAR(data_crearii, 'yyyy') =
TO_CHAR(data_achizitiei, 'yyyy');
b) Se cer aceleaşi informaţii ca la punctul a), cu deosebirea că prima linie
afişată va fi cea corespunzătoare operei având valoarea maximă.
SELECT 'In anul in care a fost creata "'|| titlu ||
' " s-a achizitionat "' ||
PRIOR titlu || '"' "traversare bottom-up "
FROM opera
START WITH valoare = (SELECT MAX(valoare)
FROM opera)
CONNECT BY PRIOR TO_CHAR(data_achizitiei, 'yyyy') =
TO_CHAR(data_crearii, 'yyyy');
c) Să se afişeze codul, titlul, data creării şi data achiziţiei operelor, astfel
încât fiecare operă să fie urmată de cele achiziţionate în anul creării sale. Se vor
considera doar operele a căror valoare este mai mare decât 7000. Prima linie afişată
va fi cea corespunzătoare operei create cel mai recent.
SELECT cod_opera, titlu, data_crearii, data_achizitiei,
valoare
FROM opera
START WITH data_crearii = (SELECT MAX(data_crearii)
FROM opera)
CONNECT BY PRIOR TO_CHAR(data_crearii, 'yyyy') =
TO_CHAR(data_achizitiei, 'yyyy')
AND valoare > 7000;
În clauza CONNECT BY, coloana data_crearii este evaluată pentru linia
„părinte“, iar coloanele data_achizitiei şi valoare sunt evaluate pentru linia
„copil“.
d) Să se afişeze ierarhia sub forma unui raport, folosindu-se indentări.
Fiecare linie a tabelului va fi considerată drept rădăcină.
SELECT LEVEL,
LPAD(titlu, LENGTH(titlu) + (LEVEL * 2) - 2, '_')
succesiune
FROM opera
CONNECT BY PRIOR TO_CHAR(data_crearii, 'yyyy') =
TO_CHAR(data_achizitiei, 'yyyy');
Exemplu:
a) Să se afişeze codul, titlul, data creării şi data achiziţiei operelor de artă
expuse în muzeu, astfel încât fiecare operă să fie urmată de cele achiziţionate în
anul creării acesteia. Prima linie afişată va fi cea corespunzătoare operei pictorului
Nicolae Grigorescu, achiziţionată cel mai recent. Rezultatul nu va conţine operele
create în anul 1970, dar va conţine operele achiziţionate în acest an.
WITH opera_ng AS
(SELECT cod_opera, data_achizitiei
FROM opera
WHERE cod_artist = (SELECT cod_artist
FROM artist
WHERE INITCAP(nume) = 'Grigorescu'
AND INITCAP(prenume) = 'Nicolae'))
SELECT cod_opera, titlu, data_crearii, data_achizitiei
FROM opera
WHERE TO_CHAR(data_crearii, 'yyyy') != 1970
START WITH (cod_opera, data_achizitiei) IN
(SELECT cod_opera, data_achizitiei
FROM opera_ng
WHERE data_achizitiei =
(SELECT MAX(data_achizitiei)
FROM opera_ng))
CONNECT BY PRIOR TO_CHAR(data_crearii, 'yyyy') =
TO_CHAR(data_achizitiei, 'yyyy');
b) Să se afişeze informaţiile solicitate la punctul a), cu deosebirea că prima
linie listată este cea al cărei cod este 110. Se vor elimina din rezultat liniile
corespunzătoare operelor create sau achiziţonate în anul 1970.
SELECT cod_opera, titlu, data_crearii, data_achizitiei
FROM opera
START WITH cod_opera = 110
CONNECT BY PRIOR TO_CHAR(data_crearii, 'yyyy') =
TO_CHAR(data_achizitiei, 'yyyy')
AND TO_CHAR(data_crearii, 'yyyy') != 1970;

Curs6_IP

Subcereri
De cele mai multe ori, pentru a implementa anumite interogări, nu este
suficientă o singură cerere SELECT ci sunt necesare subcereri. Subcererile sunt
comenzi SELECT încapsulate în oricare din clauzele SELECT, WHERE, HAVING,
FROM.
Dacă subcererea urmează clauzei WHERE sau HAVING, ea poate conţine
unul dintre operatorii ALL, ANY, IN (=ANY), EXIST, NOT IN (!=ALL) care sunt
specifici cererilor care întorc mai multe linii (multiple-row subquery) sau unul
dintre operatorii de comparare (=, <, >, >=, <=, <>) care sunt specifici cererilor
care întorc o singură linie (single-row subquery).
Subcererile trebuie incluse între paranteze şi trebuie plasate în partea dreaptă
a operatorului de comparare. Subcererea nu poate conţine clauza ORDER BY.
Exemplu:
Să se obţină numele şi salariul angajaţilor, având salariul minim.
SELECT ename, sal
FROM emp
WHERE sal=(SELECT MIN(sal)
FROM emp);
Exemplu:
Să se obţină job-ul pentru care salariul mediu este minim. Sa se afiseze si
salariul mediu.
SELECT job, AVG(sal)
FROM emp
GROUP BY job
HAVING AVG(sal)=(SELECT MIN(AVG(sal))
FROM emp
GROUP BY job);
Operatorul ANY presupune că este adevărată condiţia dacă comparaţia este
adevărată pentru cel puţin una din valorile returnate. Sunt evidente relaţiile:
< ANY  mai mic ca maximul;
> ANY  mai mare ca minimul;
= ANY  IN.
Pentru operatorul ALL se presupune că este adevărată condiţia, dacă
comparaţia este adevărată pentru toate elementele listei returnate. Pentru operatorul
ALL sunt evidente relaţiile:
< ALL  mai mic ca minimul;
> ALL  mai mare ca maximul;
! = ALL  NOT IN.
Exemplu:
WHERE codec > ALL („C1‟, „C2‟)  este superior tuturor elementelor din listă;
WHERE codec > ANY („C1‟, „C2‟)  este superior cel puţin unui element din
listă.
Exemplu:
Să se obţină salariaţii al căror salariu este mai mare ca salariile medii din
toate departamentele.

SELECT ename, job


FROM emp
WHERE sal > ALL(SELECT AVG(sal)
FROM emp
GROUP BY deptno);
Există subcereri care au ca rezultat mai multe coloane (multiple-column
subquery). Aceste interogări au următoarea sintaxă generală:
SELECT col,col,…
FROM tabel
WHERE (col,col,…) IN (SELECT col,col,…
FROM tabel
WHERE condiţie);
Exemplu:
Să se obţină numele, numărul departamentului, salariul şi comisionul tuturor
funcţionarilor ale căror salarii şi comisioane coincid cu salariile şi comisioanele
unor salariaţi din departamentul 7.
SELECT ename, deptno, sal, com
FROM emp
WHERE (sal,NVL(com,-1)) IN
(SELECT sal,NVL(com,-1)
FROM emp
WHERE deptno = 7);
Rezultatul acestei interogări este diferit de rezultatul următoarei interogări:
SELECT ename, deptno, sal, com
FROM emp
WHERE sal IN (SELECT sal
FROM emp
WHERE deptno=7)
AND NVL(com,-1) IN (SELECT NVL(com,-1)
FROM emp
WHERE deptno=7);

Dacă una din valorile returnate de subcerere este valoarea null atunci cererea
nu întoarce nici o linie. Prin urmare, dacă valoarea null poate să facă parte din
rezultatul subcererii nu trebuie utilizat operatorul NOT IN. Problema nu mai apare
dacă se utilizează operatorul IN.

Exemplu:
Să se obţină salariaţii care nu au subordonaţi.
SELECT e.ename
FROM emp e
WHERE e.empno NOT IN (SELECT m.mgr
FROM emp m);
În acest caz, instrucţiunea SQL nu întoarce nici o linie deoarece una din
valorile furnizate de subcerere este valoarea null.
Exemplu:
Să se obţină numele salariaţilor, salariile, codul departamentului în care
lucrează şi salariul mediu pe departament pentru toţi angajaţii care au salariul mai
mare ca media salariilor din departamentul în care lucrează (folosirea subcererii în
clauza FROM).
SELECT a.ename,a.sal,a.deptno,b.salavg
FROM emp a,(SELECT deptno,avg(sal) salavg
FROM emp
GROUP BY deptno) b
WHERE a.deptno=b.deptno
AND a.sal>b.salavg
Exemplu:
Să se obţină lista celor mai scumpe cărţi.
SELECT titlu
FROM carte
WHERE pret = (SELECT MAX(pret)
FROM carte);
Exemplu:
Să se obţină lista scriitorilor care au în bibliotecă un număr de exemplare
mai mare decât numărul mediu al cărţilor din bibliotecă.
SELECT DISTINCT autor
FROM carte
WHERE nrex > (SELECT AVG(nrex)
FROM carte);
Exemplu:
Să se obţină informaţii despre cărţile al căror preţ depăşeşte media preţurilor
cărţilor ce aparţin aceluiaşi domeniu
SELECT *
FROM carte c
WHERE pret > (SELECT AVG(pret)
FROM carte
WHERE coded = c.coded);
Exemplu:
Să se obţină lista cititorilor care au împrumutat cel puţin o carte.
SELECT nume
FROM cititor
WHERE codec IN (SELECT DISTINCT codec
FROM imprumuta);
Exemplu:
Să se obţină codurile cititorilor care nu au împrumutat niciodată cărţi.
SELECT codec
FROM cititor
WHERE codec NOT IN
(SELECT DISTINCT codec
FROM imprumuta);
Exemplu:
Să se obţină lista cititorilor care sunt în întârziere cu predarea cărţilor.
SELECT nume
FROM cititor
WHERE codec IN (SELECT DISTINCT codec
FROM imprumuta
WHERE dataef IS NULL
AND dares<SYSDATE);
Exemplu:
Să se obţină numele cititorilor care au împrumutat cel puţin o carte scrisă de
ZOLA.
SELECT nume
FROM cititor
WHERE codec IN
(SELECT DISTINCT codec
FROM imprumuta
WHERE codel IN
(SELECT codel
FROM carte
WHERE autor=‟ZOLA‟));
Exemplu:
Să se obţină numele cititorilor care nu au împrumutat nici o carte scrisă de
ZOLA.
SELECT nume
FROM cititor
WHERE codec NOT IN
(SELECT DISTINCT codec
FROM imprumuta
WHERE codel IN
(SELECT codel
FROM carte
WHERE autor=‟ZOLA‟));
Operatorul IN poate fi înlocuit cu = ANY (un element este în listă dacă şi
numai dacă este egal cu un element al listei), iar operatorul NOT IN poate fi
înlocuit prin !=ALL.
Exemplu:
Să se obţină codurile cititorilor care au împrumutat o carte de algebră.
SELECT DISTINCT codec
FROM imprumuta
WHERE codel IN
(SELECT codel
FROM carte
WHERE coded=
(SELECT coded
FROM domeniu
WHERE intdom=‟ALGEBRA‟));
Exemplu:
Să se obţină cititorii care au împrumutat numai cărţi scrise de „ZOLA‟.
SELECT nume
FROM cititor
WHERE codec NOT IN
(SELECT DISTINCT codec
FROM imprumuta
WHERE codel NOT IN
(SELECT codel
FROM carte
WHERE autor=‟ZOLA‟));

Exemplu:
Să se obţină numele cititorilor care au împrumutat cel puţin o carte de
informatică (procedural).
SELECT nume
FROM cititor
WHERE codec IN
(SELECT DISTINCT codec
FROM imprumuta
WHERE codel IN
(SELECT codel
FROM carte
WHERE coded=
(SELECT coded
FROM domeniu
WHERE intdom= ‟INFORMATICA‟)));
Exemplu:
Să se obţină numele cititorilor şi titlurile cărţilor de informatică împrumutate
de aceşti cititori (relational).
SELECT nume, titlu
FROM cititor, carte, imprumuta, domeniu
WHERE imprumuta.codel = carte.codel
AND carte.coded = domeniu.coded
AND imprumuta.codec = cititor.codec
AND intdom = ‟INFORMATICA‟;
Subcererile pot fi executate corelat (cu sincronizare) sau încuibărit (fără
sincronizare).
Subcererile fără sincronizare sunt caracterizate de faptul că se execută
cererea cea mai interioară care întoarce un rezultat ce este transmis cererii de nivel
superior, care întoarce un rezultat s.a.m.d.
Subcererile cu sincronizare sunt caracterizate de faptul că evaluarea
subcererii face referinţă la o coloană a cererii principale, iar evaluarea cererii
interioare se face pentru fiecare linie a cererii (principale) care o conţine.
Exemplu:
Să se obţină, utilizând sincronizarea subcererii cu cererea principală, titlurile
cărţilor care au toate exemplarele împrumutate (se selectează un titlu din carte şi
pentru acest titlu se numără câte exemplare sunt împrumutate).
SELECT titlu
FROM carte
WHERE nrex=(SELECT COUNT(*)
FROM imprumuta
WHERE codel = carte.codel
AND dataef IS NULL);
Exemplu:
Să se obţină codurile cititorilor şi codul ultimei cărţi împrumutate.
SELECT codec, codel
FROM imprumuta i
WHERE dataim>=ALL (SELECT dataim
FROM imprumuta
WHERE codec=i.codec);
Pentru această interogare, clauza WHERE putea fi scrisă şi sub forma:
WHERE dataim=(SELECT MAX(dataim)
FROM imprumuta
WHERE codec=i.codec);
Exemplu:
Să se obţină lista codurilor cărţilor împrumutate şi codul primului cititor care
a împrumutat aceste cărti.
SELECT codel,codec
FROM imprumuta i
WHERE dataim<=ALL (SELECT dataim
FROM imprumuta
WHERE i.codel=codel);
Exemplu:
Să se obţină codurile cărţilor din care cel puţin un exemplar este împrumutat.
SELECT codel
FROM carte
WHERE EXISTS
(SELECT codel
FROM imprumuta
WHERE codel = carte.codel
AND dataef IS NULL);
Operatorul WHERE EXISTS (subcerere) presupune că predicatul este
adevărat dacă subcererea întoarce cel puţin un tuplu, iar WHERE NOT EXISTS
(subcerere) presupune că predicatul este adevărat dacă subcererea nu întoarce nici
un tuplu.  EXISTS şi NOT EXISTS cer sincronizarea subcererii.
Exemplu:
Să se obţină titlurile cărţilor care sunt momentan împrumutate.
Soluţia 1 (cu sincronizare):
SELECT titlu
FROM carte
WHERE EXISTS
(SELECT *
FROM imprumuta
WHERE codel = carte.codel
AND dataef IS NULL);
Soluţia 2 (fără sincronizare):
SELECT titlu
FROM carte
WHERE codel IN
(SELECT DISTINCT codel
FROM imprumuta
WHERE dataef IS NULL);
Exemplu:
Să se obţină codurile cărţilor care nu au fost împrumutate niciodată.
Soluţia 1 (cu sincronizare)
SELECT codel
FROM carte
WHERE NOT EXISTS
(SELECT codel
FROM imprumuta
WHERE codel = carte.codel);
Soluţia 2 (fără sincronizare)
SELECT codel
FROM carte
WHERE codel NOT IN
(SELECT DISTINCT codel
FROM imprumuta);
Exemplu:
Să se obţină lista salariaţilor având salariul minim în departamentul în care
lucrează.
SELECT ename,sal
FROM emp e
WHERE sal=(SELECT MIN(sal)
FROM emp
WHERE deptno=e.deptno);
Exemplu:
Să se obţină numele primilor trei salariaţi având retribuţia maximă (ideea
rezolvării este de a verifica dacă numărul salariaţilor care au leafa mai mare decât
leafa salariatului considerat, este mai mic decât 3).
SELECT ename
FROM emp a
WHERE 3>(SELECT COUNT(*)
FROM emp
WHERE sal > a.sal);
Exemplu:
Să se obţină numele cititorilor care au împrumutat cel puţin aceleaşi cărţi ca
şi cititorul având codul C19 (ideea problemei este de a selecta cititorii pentru care
este vidă lista cărţilor împrumutatede C19 mai puţin lista cărţilor împrumutate de
acei cititori).
SELECT nume
FROM cititor
WHERE NOT EXISTS
(SELECT codel
FROM imprumuta
WHERE codec=‟C19‟
MINUS
SELECT codel
FROM imprumuta
WHERE codec= cititor.codec);
Dacă problema era modificată în sensul că „cel puţin”este înlocuit prin „cel
mult” atunci trebuiau inversate interogările legate prin MINUS.

Exemplu:
Să se obţină codurile cititorilor care au împrumutat aceleaşi cărţi ca şi
cititorul având un cod specificat.
Rezolvarea problemei se bazează pe ideea: A = B  A B şi B A  (A-
B) = şi (B-A) =  A-B şi B-A nu furnizează nici un tuplu rezultat.
SELECT codec
FROM imprumuta i
WHERE NOT EXISTS
(SELECT codel
FROM imprumuta
WHERE codec=i.codec
MINUS
SELECT codel
FROM imprumuta
WHERE codec=‟&ccc‟)
AND NOT EXISTS
(SELECT codel
FROM imprumuta
WHERE codec=‟&ccc‟
MINUS
SELECT codel
FROM imprumuta
WHERE codec=i.codec)
AND codec!=‟&ccc‟);
Ultimul operator (AND), asigură să nu apară în rezultat cititorul specificat.
În cazul formei relaţionale de rezolvare a cererii, drumul de acces la
informaţie este în sarcina SGBD-lui şi prin urmare nu mai apar cereri imbricate.
Exemplu:
Să se obţină numele cititorilor care au împrumutat cel puţin o carte.
Soluţia 1 (forma relaţională):
SELECT DISTINCT nume
FROM cititor,imprumuta
WHERE cititor.codec=imprumuta.codec;
Soluţia 2 (forma procedurală):
SELECT nume
FROM cititor
WHERE codec IN
(SELECT DISTINCT codec
FROM imprumuta);
Exemplu:
Să se obţină numele cititorilor care au împrumutat cel puţin două cărţi.
Soluţia 1 (forma relaţională):
SELECT nume
FROM cititor, imprumuta
WHERE cititor.codec=imprumuta.codec
GROUP BY nume
HAVING COUNT(*)>1;
Soluţia 2 (forma procedurală):
SELECT nume
FROM cititor
WHERE codec IN
(SELECT codec
FROM imprumuta
GROUP BY codec
HAVING COUNT(*)>1);
Exemplu:
Să se afişeze numele, prenumele, salariul lucrătorilor, codurile publicaţiilor
la care lucrează şi salariul mediu pe publicaţie pentru toţi angajaţii care au salariul
mai mare decât media salariului pe publicaţia respectivă.
SELECT s.nume, s.prenume, s.salariu,
p.nr_publicatie, a.salariu_mediu
FROM salariat s, publicatie p,
(SELECT p1.nr_publicatie,AVG(salariu) salariu_mediu
FROM publicatie p1, salariat s1
WHERE p1.cod_salariat = s1.cod_salariat
GROUP BY p1.nr_publicatie) a
WHERE p.nr_publicatie = a.nr_publicatie
AND s.cod_salariat = p.cod_salariat
AND s.salariu > a.salariu_mediu;
Exemplu:
Să se obţină numele salariaţilor care nu cunosc nici o limbă străină.
SELECT nume, prenume
FROM salariat
WHERE NOT EXISTS
(SELECT *
FROM limba
WHERE limba.cod_salariat = salariat.cod_salariat
AND limba_cun IS NOT NULL);
Exemplu:
Să se afişeze graficienii care au întârziat să predea frame-urile.
a) cu sincronizare:
SELECT nume, prenume
FROM salariat
WHERE EXISTS
(SELECT *
FROM realizeaza r
WHERE salariat.cod_salariat=r.cod_salariat
AND data_lim < SYSDATE);
b) fără sincronizare:
SELECT nume, prenume
FROM salariat
WHERE cod_salariat IN
(SELECT DISTINCT cod_salariat
FROM realizeaza
WHERE data_lim < SYSDATE);
Exemplu:
Să se determine revistele coordonate de redactori şefi care nu cunosc limba
în care sunt scrise. Se ştie că în urma inspectării vizuale a rezultatului interogării se
poate decide schimbarea redactorilor şefi ai revistelor respective, de aceea se
doreşte blocarea înregistrărilor găsite.
SELECT p.nr_publicatie
FROM salariat s, publicatie p
WHERE s.cod_salariat = p.cod_salariat
AND p.limba NOT IN
(SELECT limba_cun
FROM limba
WHERE limba.cod_salariat = s.cod_salariat)
FOR UPDATE OF p.cod_salariat;

Clauza WITH
Cu ajutorul clauzei WITH se poate defini un bloc de cerere înainte ca acesta
să fie utilizat într-o interogare. Clauza permite reutilizarea aceluiaşi bloc de cerere
într-o instrucţiune SELECT complexă.
Utilizând clauza WITH, să se scrie o cerere care afişează numele artiştilor şi
valoarea totală a operelor acestora. Se vor considera artiştii a căror valoare totală a
operelor este mai mare decât media valorilor operelor tuturor artiştilor.
WITH
val_artist AS (SELECT nume, SUM(valoare) AS total
FROM opera o, artist a
WHERE o.cod_artist = a.cod_artist
GROUP BY nume),
val_medie AS (SELECT SUM(total)/COUNT(*) AS medie
FROM val_artist)
SELECT *
FROM val_artist
WHERE total > (SELECT medie
FROM val_medie)
ORDER BY nume;
Subcereri scalare
Subcererile scalare în SQL returnează valoarea unei singure coloane
corespunzătoare unei linii. Dacă subcererea returnează 0 linii, valoarea subcererii
scalare este null. Dacă subcererea returnează mai mult de o linie, server-ul
generează o eroare.
Subcererile scalare erau acceptate în Oracle8i doar în anumite cazuri, cum ar
fi clauzele FROM şi WHERE ale instrucţiunii SELECT sau clauza VALUES a
instrucţiunii INSERT. Utilitatea subcererilor scalare a fost extinsă în Oracle9i.
Astfel, ele pot apărea în:
condiţiile şi expresiile care fac parte din DECODE sau CASE;
toate clauzele instrucţiunii SELECT, cu excepţia lui GROUP BY;
în partea stângă a operatorului, în clauzele SET şi WHERE ale
instrucţiunii UPDATE.
Exemplu:
Să se afişeze codul, titlul operelor şi numele artistului doar dacă acesta este
Brâncuşi. În caz contrar, se va afişa şirul „alt artist“.
SELECT cod_opera, titlu,
(CASE WHEN cod_artist =
(SELECT cod_artist
FROM artist
WHERE nume = 'Brancusi')
THEN 'Brancusi'
ELSE 'Alt artist' END) artist
FROM opera;

Operatorul ROLLUP
Operatorul ROLLUP produce o mulţime care conţine liniile obţinute în urma
grupării obişnuite şi linii pentru subtotaluri. Acest operator furnizează valori
agregat şi superagregat corespunzătoare expresiilor din clauza GROUP BY.
Operatorul ROLLUP creează grupări prin deplasarea într-o singură direcţie,
de la dreapta la stânga, de-a lungul listei de coloane specificate în clauza GROUP
BY. Apoi, se aplică funcţia agregat acestor grupări. Dacă sunt specificate n expresii
în operatorul ROLLUP, numărul de grupări generate va fi n + 1. Liniile care se
bazează pe valoarea primelor n expresii se numesc linii obişnuite, iar celelalte se
numesc linii superagregat.
Daca in clauza GROUP BY sunt specificate n coloane, atunci pentru a
produce subtotaluri in n dimensiuni ar fi necesare n+1 operatii SELECT legate prin
UNION ALL. Aceasta ar fi total ineficient, deoarece fiecare SELECT ar implica o
parcurgere a tabelului. Operatorul ROLLUP are nevoie de o singura parcurgere a
tabelului.
Exemplu:
Să se afişeze codurile de galerii mai mici decât 50, iar pentru fiecare dintre
acestea şi pentru fiecare autor care are opere expuse în galerie, să se listeze
valoarea totală a lucrărilor sale. De asemenea, se cere valoarea totală a operelor
expuse în fiecare galerie. Rezultatul va conţine şi valoarea totală a operelor din
galeriile având codul mai mic decât 50, indiferent de codul autorului.
SELECT cod_galerie, cod_artist, SUM(valoare)
FROM opera
WHERE cod_galerie < 50
GROUP BY ROLLUP(cod_galerie, cod_artist);
Instrucţiunea precedentă va avea un rezultat de forma:
COD_GALERIE COD_ARTIST SUM(VALOARE)
10 50 14000
10 60 10000
10 24000
40 50 8080
40 8080
32080

Operatorul CUBE
Operatorul CUBE grupează liniile selectate pe baza valorilor tuturor
combinaţiilor posibile ale expresiilor specificate şi returnează câte o linie
totalizatoare pentru fiecare grup. El produce subtotaluri pentru toate combinaţiile
posibile de grupări specificate în GROUP BY, precum şi un total general.
Daca exista n coloane sau expresii in clauza GROUP BY, vor exista 2 n
combinatii posibile superagregat. Matematic, aceste combinatii formeaza un cub
n-dimensional.
Pentru producerea de subtotaluri fara ajutorul operatorului CUBE ar fi
necesare 2 n instructiuni SELECT legate prin UNION ALL.
Exemplu:
Să se afişeze valoarea totală a operelor de artă ale unui autor, expuse în
cadrul fiecărei galerii având codul mai mic decât 50. De asemenea, să se afişeze
valoarea totală a operelor din fiecare galerie având codul mai mic decât 50,
valoarea totală a operelor fiecărui autor indiferent de galerie şi valoarea totală a
operelor din galeriile având codul mai mic decât 50.
SELECT cod_galerie, cod_artist, SUM(valoare)
FROM opera
WHERE cod_galerie < 50
GROUP BY CUBE(cod_galerie, cod_artist);

COD_GALERIE COD_ARTIST SUM(VALOARE)


10 50 14000
10 60 10000
10 24000
40 50 8080
40 8080
50 22080
60 10000
32080

Funcţia GROUPING
Aceasta funcţie este utilă pentru:
determinarea nivelului de agregare al unui subtotal dat, adică a grupului
sau grupurilor pe care se bazează subtotalul respectiv;
identificarea provenienţei unei valori null a unei expresii calculate, dintr-
una din liniile mulţimii rezultat.
Functia returnează valoarea 0 sau 1. Valoarea 0 poate indica fie că expresia a
fost utilizată pentru calculul valorii agregat, fie că valoarea null a expresiei este o
valoare null stocată.
Valoarea 1 poate indica fie că expresia nu a fost utilizată pentru calculul
valorii agregat, fie că valoarea null a expresiei este o valoare creată de ROLLUP
sau CUBE ca rezultat al grupării.
Exemplu:
SELECT cod_galerie, cod_artist, SUM(valoare),
GROUPING(cod_galerie), GROUPING(cod_artist)
FROM opera
WHERE cod_galerie < 50
GROUP BY ROLLUP(cod_galerie, cod_artist);

SUM GROUPING GROUPING


COD_GALERIE COD_ARTIST
(VALOARE) (COD_GALERIE) (COD_ARTIST)
10 50 14000 0 0
10 60 10000 0 0
10 24000 0 1
40 50 8080 0 0
40 8080 0 1
32080 1 1

Pe prima linie din acest rezultat, valoarea totalizatoare reprezintă suma


valorilor operelor artistului având codul 50, în cadrul galeriei 10. Pentru a calcula
această valoare au fost luate în considerare coloanele cod_galerie şi cod_artist.
Prin urmare, expresiile GROUPING(cod_galerie) şi GROUPING(cod_artist) au
valoarea 0 pentru prima linie din rezultat.
Pe linia a treia se află valoarea totală a operelor din galeria având codul 10.
Această valoare a fost calculată luând în considerare doar coloana cod_galerie,
astfel încât GROUPING (cod_galerie) şi GROUPING(cod_artist) au valorile 0,
respectiv 1.
Pe ultima linie din rezultat se află valoarea totală a operelor din galeriile
având codul mai mic decât 50. Nici una dintre coloanele cod_galerie şi cod_artist
nu au intervenit în calculul acestui total, prin urmare valorile corespunzătoare
expresiilor GROUPING(cod_galerie) şi GROUPING(cod_artist) sunt 0.

Clauza GROUPING SETS

GROUPING SETS reprezintă o extensie a clauzei GROUP BY care permite


specificarea unor grupări multiple de date.
Această extensie, apărută în sistemul Oracle9i, permite scrierea unei singure
instrucţiuni SELECT pentru a specifica grupări diferite (care pot conţine operatorii
ROLLUP şi CUBE), în loc de mai multe instrucţiuni SELECT combinate prin
operatorul UNION ALL. De altfel, reuniunea rezultatelor mai multor cereri este
ineficientă întrucât necesită mai multe parcurgeri ale aceloraşi date.
Operatorii ROLLUP şi CUBE pot fi consideraţi cazuri particulare de mulţimi
de grupări. Au loc următoarele echivalenţe:

CUBE(a, b, c) GROUPING SETS


((a, b, c), (a, b), (a, c), (b, c), (a), (b), (c),
())
ROLLUP(a, b, GROUPING SETS
c) ((a, b, c), (a, b), (a), ())

Exemplu:
Considerând galeriile al căror cod este mai mic decât 50, să se calculeze
media valorilor operelor:
pentru fiecare galerie şi, în cadrul acesteia, pentru fiecare artist;
pentru fiecare artist şi, în cadrul acestuia, pentru anii de achiziţie
corespunzători.
SELECT cod_galerie, cod_artist,
TO_CHAR(data_achizitiei, 'yyyy') "an achizitie",
AVG(valoare) "Valoare medie"
FROM opera WHERE cod_galerie < 50
GROUP BY GROUPING SETS
((cod_galerie, cod_artist),
(cod_artist, TO_CHAR(data_achizitiei, 'yyyy')));
Mulţimea rezultat este constituită din valorile medii pentru fiecare dintre
cele două grupuri ((cod_galerie, cod_artist) si (cod_artist, an_achizitie)) şi are
forma următoare:
COD_GALERIE COD_ARTIST An achizitie Valoare medie
10 50 3500
10 60 2500
40 50 2020
50 2000 2380
50 2002 2300
60 2001 2000
60 2003 3000

Exemplul precedent poate fi rezolvat şi prin următoarea instrucţiune


compusă:
SELECT cod_galerie, cod_artist, NULL "An achizitie",
AVG(valoare) "Valoare medie"
FROM opera
GROUP BY cod_galerie, cod_artist
UNION ALL
SELECT NULL, cod_artist,
TO_CHAR(data_achizitiei, 'yyyy'), AVG(valoare)
FROM opera
GROUP BY cod_artist, TO_CHAR(data_achizitiei, 'yyyy');
În absenţa unui optimizor care analizează blocurile de cerere şi generează
planul de execuţie, cererea precedentă va parcurge de două ori tabelul de bază
(opera), ceea ce poate fi ineficient. Din acest motiv, este recomandată utilizarea
extensiei GROUPING SETS.
Limbajul de manipulare a datelor – DML

În aceast curs se prezintă instrucţiunile DML (Data Manipulation


Language), o parte a limbajului SQL folosită pentru intreţinerea datelor stocate în
tabele relaţionale ale bazei de date.
Limbajul DML este format din trei comenzi SQL:

INSERT Adaugă noi rânduri într-un table al bazei de date.


UPDATE Actualizeaza rândurile existente intr-un table al bazei de date.
DELETE Sterge rânduri dintr-un tabel al bazei de date

Instrucţiunile DML individuale afectează datele dintr-un singur tabel. Este


posibil ca într-o instrucţiune DML să referiţi şi o vizualizare care conţine date din
mai multe tabele (adică o vizualizare care conţine o uniune de tabele), dar, în acest
caz, instrucţiunea DML poate referi numai coloane dintr-un singur tabel al
vizualizării. Cu alte cuvinte, atunci cand o instrucţiune DML foloseşte o
vizualizare, toate coloanele vizualizării referite în instrucţiunea DML trebuie să
corespundă unor coloane dintr-un singur tabel fizic al bazei de date.
Sistemul SGBD nu va efectua în baza de date nici o modificare care încalcă
una din restricţii.
La formarea instructiunilor DML, trebuie să se ţină seama de urmatoarele
aspecte referitoare la restricţiile tabelului modificat:

Restricţii de tip cheie primară

Atunci când inseraţi un nou rând într-un tabel, cheia primară a noului rând
trebuie sa fie unică în întregul tabel.Cand modificati valoarea unei chei primare
(ceea ce se intampla rareori), noua valoare trebuie să fie unică în întregul tabel.

Restricţii de unicitate

Ca şi în cazul cheilor primare, coloanele pe care a fost definită o restricţie de


unicitate trebuie sa aibă valori unice în întregul tabel.

Restricţii NOT NULL

O valoare nula (null) este o modalitate specială prin care sistemul SGBD
tratează valoarea unei coloane pentru a indica faptul ca valoarea coloanei
respective nu este cunoscută. O valoare nula nu este acelasi lucru un un spatiu
liber, un sir vid sau valoarea zero – este o valoare speciala care nu este egala cu
nimic altceva.
În cazul instrucţiunilor INSERT, trebuie specificate valori pentru toate
coloanele cu restricţii NOT NULL.
În cazul instrucţiunilor UPDATE nu se pot inlocui valorile unei coloane cu
valori nule dacă pe coloana respectivă este definită p restricţie NOT NULL.
Dacă instrucţiunea DML referă o vizualizare , nu se poate sa o folosim intr-
o instrucţiune INSERT dacă una dintre coloanele tabelului cu o restricţie NOT
NULL(obligatorii) lipseşte din definirea vizualizării.

Restricţii referenţiale

Nu se poate insera sau actualiza valoarea unei chei externe decât dacă există
deja rândul părinte corespondent care conţine valoarea cheii în coloana cheii
primare. In sens invers, nu se poate şterge un rând părinte dacă există rânduri
subordonate care referă valoarea din rândul părinte, decât dacă restricţia a fost
definită cu opţiunea ON DELETE CASCADE. In general inserările în tabele
trebuie făcute ierarhic (mai intai randurile parinte, apoi randurile copii), iar
ştergerile trebuie făcute în ordine inversă (copiii inaintea părinţilor).

Restrictii de verificare (CHECK) O instructiune INSERT sau UPDATE


nu poate stoca într-o coloana o valoare care încalcă o restricţie CHECK definită
pentru coloana respectivă.

Instrucţiunea INSERT

Instrucţiunea INSERT este folosită pentru inserarea noilor rânduri de date în


tabele sau tabele de bază al unei vizualizări. Instrucţiunea are două forme de bază:
una în care valorile coloanelor sunt specificate chiar în instrucţiune şi alta în care
valorile sunt selectate dintr-un tabel sau o vizualizare, folosind o subinterogare.

Inserarea unui singur rand de date folosind clauza Values

Instrucţiunea INSERT care foloseşte o clauză VALUES poate crea un


singur rând la fiecare rulare, deoarece valorile pentru rândul de date respective sunt
specificate chiar în instrucţiune.
Sintaxa generală a instrucţiunii este următoarea:

INSERT INTO nume_tabel_sau_vizualizare


[(lista_de_coloane)]
VALUES (lista_de_valori);
Sau

INSERT INTO nume_tabel / nume_view [(col1[, col2[,…]])]


VALUES (expresia1[, expresia2[,…]]) / subcerere;
expresia1, expresia2, reprezintă expresii a căror evaluare este atribuită
coloanelor precizate (se inserează o linie);
subcerere, reprezintă o interogare (se inserează una sau mai multe
linii).

Clauza VALUES specifică valorile ce vor fi introduse în tabel sau


vizualizare. Pentru a insera mai multe linii prin aceeaşi instrucţiune INSERT, în
locul acestei clauze se va preciza o subcerere.

Exemple pentru baza de date FILM


Diagrama ERD a bazei de date FILM(prezentare parţială)

FILM
FILM_ID <pk>
MPAA_RATING FILM_COD_GEN <fk1> FILM_GEN
MPAA_COD_RATING <pk> MPAA_COD_RATING <fk2> FILM_COD_GEN <pk>
MPAA_DESCRIERE_RATING FILM_NUME FILM_DESCRIERE_GEN
RETAIL_PRET_VHS
RETAIL_PRET_DVD
AN_PRODUS

FILM_COPII
FILM_ID <pk, fk>>
NUMAR_COPIE <pk>
DATA_CUMPARARE
DATA_VANZARE
FORMAT_MEDIA
Se poate remarcă următoarele:

Lista de coloane este opţională, dar dacă este inclusă trebuie să fie
încadrată în paranteze rotunde.
Dacă lista de coloane este omisă, trebuie specificată o valoare pentru
fiecare coloană din tabel, în ordinea în care sunt definite coloanele în tabel. Este
bine ca întotdeauna să includeţi lista de coloane, deoarece omiterea acesteia face ca
instrucţiunea INSERT să fie dependentă de definiţia tabelului. Dacă o coloană este
modificată sau în tabel este adăugată o nouă coloană, chiar şi opţională, probabil
instrucţiunea INSERT va eşua la următoarea rulare.
Dacă lista de coloane este specificată, lista de valori trebuie să conţin
o valoare pentru fiecare coloană din listă, în aceeaşi ordine. Cu alte cuvinte, între
lista de coloane şi lista de valori trbuie să existe o corespondenţa unu-la-unu. Orice
coloana care lipseşte din listă va primi o valoare nulă, presupunund că valorile nule
sunt acceptate în coloana respectivă.
În clauza VALUES, valorile de tip caracter şi dată calendaristică
trebuie incluse între apostrofuri. Nu se recomandă includerea între apostrofuri a
valorilor numerice, întrucât aceasta ar determina conversii implicite la tipul
NUMBER.
Pentru introducerea de valori speciale în tabel, pot fi utilizate funcţii.
Adăugarea unei linii care va conţine valori null se poate realiza în
mod:
- implicit, prin omiterea numelui coloanei din lista de coloane;
- explicit, prin specificarea în lista de valori a cuvântului cheie null
sau a şirului vid în cazul şirurilor de caractere sau datelor
calendaristice.

Exemplul următor conţine două instrucţiuni INSERT, una care creează un


nou rând în tabelul FILM, cu o listă opţională de coloane, din care este omisă
coloana RETAIL_PRET_VHS, şi alta care creează un rând în tabelul FILM_COPII
pentru acelaşi tip, dar fără lista opţională de coloane.

INSERT INTO FILM


(FILM_ID, FILM_COD_GEN, MPAA_RATING_COD, FILM_NUME,
PRET_INCHIRIAT_DVD, AN_PRODUCERE)
VALUES (21,‟Drama‟,‟PG-13‟,‟Ray‟, 29.95, ‟2004‟);

INSERT INTO FILM_COPII


VALUES (21, 1, ‟2005-04-01‟, NULL, ‟V‟);
Exemplu baza galeria de arta

GALERIE 1 inclusa_in M(1)


cod_galerie# SALA
cod_sala#
cod_galerie#

1
cuprinsa_in SECURITATE
cod_opera#
sistem#
M(1) 1 protejata_prin M(0)

1 creata_de M(1)
ARTIST OPERA
cod_artist# cod_opera# 1 asigurata_de M(0)
POLITA_ASIG
M(1) cod_polita#
M(1) M(1)
mentionata_in
studiaza

M(0)
M(0)
SURSA_BIBLIO
cod_sursa# SPECIALIST
tip cod_specialist#

ARTICOL figureaza_in

CARTE M(0)

EXPOZITIE M(1) organizata_de M(1) ORGANIZATOR


M(1) cod_expo# cod_organizator#
editata_de

M(1)

AUTOR
cod_autor#
Să se adauge prin metoda explicită, respectiv prin metoda implicită, două
înregistrări în tabelul artist, precizând numai codul, numele şi prenumele artistului.

ARTIST(cod_artist#, nume, prenume, an_nastere, an_moarte,


nationalitate, observatii);

INSERT INTO artist


(cod_artist, nume, prenume)
VALUES (50, 'Grigorescu', 'Nicolae');

INSERT INTO artist


VALUES (70, 'Andreescu', 'Ion', NULL, NULL, NULL, NULL);
în galeria creată anterior şi care a fost achiziţionată la 20 ianuarie 2009.

Exemplu:
Următoarea instrucţiune va genera eroarea „ORA-01400: cannot insert
NULL into …“, întrucât se încearcă inserarea unei linii în tabelul opera fără a
preciza valoarea cheii primare.
INSERT INTO opera
(titlu, data_achizitiei)
VALUES ('Flori de camp', SYSDATE);

Exemplu BD CARTE
Să se insereze în tabelul carte toate cărţile din tabelul carte_info,
presupunând că tabelul carte_info a fost deja creat. De asemenea, să se introducă o
nouă carte căreia i se cunoaşte codul (c34), titlul (algebra) şi preţul (500).

INSERT INTO carte


(codel, titlu, autor, nrex, pret, coded)
VALUES (‟c34‟,‟algebra‟, null, null, 50, null);

Exemplu:
INSERT INTO carte
(codel, nrex)
VALUES ('c25', 25);
inserare prin parametrizare
INSERT INTO domeniu
VALUES ('&cod', '&dendom'); inserare prin parametrizare

Inserări masive folosind instrucţiunea SELECT internă

Aşa cum se observă, este nevoie de foarte mult cod pentru a insera în tabel
un singur rând de date folosind o instrucţiune INSERT cu clauza VALUES.
O altă soluţie, care poate fi folosită pentru a insera rânduri multiple într-un
tabel , este forma care foloseşte o instrucţiune SELECT internă. Această formă este
utilă şi pentru stabilirea următoarei valori disponibile pentru o cheie primară cu
valori secvenţiale. De asemenea , poate fi folosită atunci când creaţi un tabel
temporar pentru testare şi vreţi să-l populaţi cu toate datele dintr-un alt tabel.

Sintaxa generală a instrucţiunii este

INSERT INTO nume_tabel_sau_vizualizare


[(lista_de_coloane)]
SELECT instructiune_select;

Se remarcă următoarele:

Lista de coloane este opţională, dar dacă este inclusă trebuie să fie încadrată
în paranteze.
Dacă lista de coloane este omisă, instrucţiune SELECT internă trebuie să
furnizeze o valoare pentru fiecare coloană din tabel, în ordinea în care sunt definite
coloanele în tabel. Este bine ca întotdeauna să includeţi lista de coloane, deoarece
omiterea acesteia face ca instrucţiunea INSERT să fie dependentă de definiţia
tabelului. Dacă o coloană este modificată sau în tabel este adăugată o nouă
coloană, chiar şi opţională, probabil instrucţiunea INSERT va eşua la următoarea
rulare.
Dacă lista de coloane este specificată, instrucţiune SELECT internă să
furnizeze o valoare pentru fiecare coloană din lista de valori, în aceeaşi ordine. Cu
alte cuvinte, între lista de coloane şi setul de rezultate al instrucţiunii SELECT
trebuie să existe o corespondenţa unu-la-unu. Orice coloană care lipseşte din listă
va primi o valoare nulă, presupunund că valorile nule sunt acceptate în coloana
respectivă.
Cuvântul cheie NULL poate fi folosit în instrucţiunea SELECT pentru
specificarea unei valori nule pentru o coloană.
Ca exemplu, să presupunem că toate filmele sunt acum disponibile şi în
limba franceză. Tabelul FILM_LIMBA conţine rânduri pentru limba franceză
pentru o parte din filme, aşa că acum vrem să le adăugăm numai pe cele care
lipsesc. Instrucţiunea INSERT care va rezolva această problemă este:

INSERT INTO FILM_LIMBA


(FILM_ID, COD_LIMBA)
SELECT FILM_ID, ‟fr‟
FROM FILM
WHERE FILM_ID NOT IN
( SELECT FILM_ID FROM FILM_LIMBA
WHERE COD_LIMBA =‟fr‟ );

INSERT INTO carte


SELECT *
FROM carte_info;

Exemplu:
Presupunând că tabelul salariat a fost completat cu datele tuturor
salariaţilor editurii, să se completeze tabelele grafician, tehnoredactor şi
redactor_sef, în concordanţă cu datele conţinute în tabelul salariat (nu pot exista
graficieni, tehnoredactori sau redactori şefi care să nu fie salariaţi!).
INSERT INTO grafician (cod_salariat)
SELECT cod_salariat
FROM salariat
WHERE job = ‟grafician‟;

INSERT INTO tehnoredactor (cod_salariat)


SELECT cod_salariat
FROM salariat
WHERE job = ‟tehnoredactor‟;

INSERT INTO redactor_sef (cod_salariat)


SELECT cod_salariat
FROM salariat
WHERE job = ‟redactor_sef‟;
NU Inserări multitabel
O inserare multitabel presupune introducerea de linii calculate pe baza
rezultatelor unei subcereri, în unul sau mai multe tabele. Acest tip de inserare,
introdus de Oracle9i, este util în mediul data warehouse. Astfel, datele extrase
dintr-un sistem sursă, pot fi transformate utilizând instrucţiuni INSERT multitabel,
spre a fi încărcate în obiectele bazei de date.
Pentru o astfel de inserare, în versiunile anterioare lui Oracle9i erau
necesare n operaţii independente INSERT INTO…SELECT…, unde n reprezintă
numărul tabelelor destinaţie. Aceasta presupunea n procesări ale aceleiaşi surse de
date şi, prin urmare, creşterea de n ori a timpului necesar procesului.
Sintaxa clauzei inserare_multi_tabel este următoarea:
{ALL INTO…[VALUES…] [INTO…[VALUES…] …]
| inserare_condiţionată} subcerere
Clauza inserare_condiţionată are forma următoare:
[ALL | FIRST]
WHEN condiţie THEN INTO…[VALUES…]
[INTO…[VALUES…] …]
[WHEN condiţie THEN INTO…[VALUES…]
[INTO…[VALUES…] …] …]
[ELSE INTO…[VALUES…]
[INTO…[VALUES…] …] …]
Pentru a efectua o inserare multitabel necondiţionată, sistemul va executa
câte o instrucţiune INSERT…INTO pentru fiecare linie returnată de subcerere.
Utilizând clauza inserare_condiţionată, decizia inserării unei linii depinde
de condiţia specificată prin intermediul opţiunii WHEN. Expresiile prezente în
aceste condiţii trebuie să facă referinţă la coloane returnate de subcerere. O
instrucţiune de inserare multitabel poate conţine maxim 127 clauze WHEN.
Specificarea opţiunii ALL determină evaluarea tuturor condiţiilor din
clauzele WHEN. Pentru cele a căror valoare este TRUE, se inserează înregistrarea
specificată în opţiunea INTO corespunzătoare.
Opţiunea FIRST determină inserarea corespunzătoare primei clauze WHEN a
cărei condiţie este evaluată TRUE. Toate celelalte clauze WHEN sunt ignorate.
Dacă nici o condiţie din clauzele WHEN nu este TRUE, atunci sistemul
execută clauza INTO corespunzătoare opţiunii ELSE, iar dacă aceasta nu există, nu
efectuează nici o acţiune.
Inserările multitabel pot fi efectuate numai asupra tabelelor, nu şi asupra
vizualizărilor sau vizualizărilor materializate. De asemenea, acest tip de inserare nu
se poate efectua asupra tabelelor distante. Subcererea dintr-o instrucţiune
corespunzătoare unei inserări multitabel nu poate utiliza o secvenţă.
Exemplu:
Se presupune că licitaţiile pentru achiziţionarea operelor de artă au loc
numai în zilele de miercuri. Fie tabelul opera_intrare (data_inceput, sapt_1,
sapt_2, sapt_3, sapt_4), în care data_inceput reprezintă data primei zile de
miercuri din lună, iar sapt_i furnizează valoarea operelor achiziţionate în
săptămâna respectivă. Considerând că în fiecare săptămână se achiziţionează o
singură lucrare, să se insereze liniile corespunzătoare în tabelul opera.
INSERT ALL
INTO opera (cod_opera, valoare, data_achizitiei)
VALUES (secv_cod_opera.NEXT_VALUE, sapt_1, data_inceput)
INTO opera (cod_opera, valoare, data_achizitiei)
VALUES (secv_cod_opera.NEXT_VALUE, sapt_2,
data_inceput + 7)
INTO opera (cod_opera, valoare, data_achizitiei)
VALUES (secv_cod_opera.NEXT_VALUE, sapt_3,
data_inceput + 14)
INTO opera (cod_opera, valoare, data_achizitiei)
VALUES (secv_cod_opera.NEXT_VALUE, sapt_4,
data_inceput + 21)
SELECT data_inceput, sapt_1, sapt_2, sapt_3, sapt_4
FROM opera_intrare;
Exemplu:
Se consideră trei tabele care conţin informaţii referitoare la galerii, în funcţie
de numărul operelor găzduite de către acestea. Tabelele se numesc galerie_mica,
galerie_medie, galerie_mare după cum numărul de opere este mai mic decât 30,
cuprins între 31 şi 100, respectiv mai mare decât 101. Se presupune că structura
fiecăruia dintre tabele este alcătuită din coloanele cod_galerie, nume,
număr_opere. Să se insereze înregistrări în aceste tabele.
INSERT ALL
WHEN nr_opere <= 30 THEN
INTO galerie_mica
WHEN nr_opere > 30 AND nr_opere <= 100 THEN
INTO galerie_medie
WHEN nr_opere > 100 THEN
INTO galerie_mare
SELECT g.cod_galerie, nume_galerie, nr_opere
FROM galerie g, (SELECT cod_galerie, count(*) nr_opere
FROM opera
GROUP BY cod_galerie) x
WHERE g.cod_galerie = x.cod_galerie;
Acelaşi rezultat se obţine prin utilizarea clauzei ELSE, astfel:
INSERT ALL
WHEN nr_opere <= 30 THEN
INTO galerie_mica
WHEN nr_opere > 30 AND nr_opere <= 100 THEN
INTO galerie_medie
ELSE
INTO galerie_mare
SELECT g.cod_galerie, nume_galerie, nr_opere
FROM galerie g, (SELECT cod_galerie, count(*) nr_opere
FROM opera
GROUP BY cod_galerie) x
WHERE g.cod_galerie = x.cod_galerie;
Exemplu:
Se consideră un tabel, galerie_g, având aceeaşi structură ca şi cele din
exemplul precedent. În acesta vor fi reţinute galeriile al căror nume începe cu litera
„G“. Se presupune că, dacă o galerie se încadrează în acest tabel, ea nu mai trebuie
să apară şi în cele referitoare la numărul de opere găzduite. Să se insereze
înregistrări în tabelele galerie_g, galerie_mica, galerie_medie, galerie_mare.
INSERT FIRST
WHEN UPPER(nume_galerie) LIKE 'G%' THEN
INTO galerie_g
WHEN nr_opere <= 30 THEN
INTO galerie_mica
WHEN nr_opere > 30 AND nr_opere <= 100 THEN
INTO galerie_medie
WHEN nr_opere > 100 THEN
INTO galerie_mare
SELECT g.cod_galerie, nume_galerie, nr_opere
FROM galerie g, (SELECT cod_galerie, count(*) nr_opere
FROM opera
GROUP BY cod_galerie) x
WHERE g.cod_galerie = x.cod_galerie;
Comanda UPDATE

Instrucţiunea UPDATE este folosită pentru actualizarea datelor din


coloanele unui tabel (sau ale unei vizualizări).
Valorile câmpurilor care trebuie modificate pot fi furnizate explicit sau pot fi
obţinute în urma unei cereri SQL.

Sintaxa generală a instrucţiunii UPDATE:

UPDATE nume_tabel_sau_vizualizare
SET nume_coloana = expresie
[,nume_coloana = expresie...]
[ WHERE conditie];

Sau mai general, expresia poate fi o cerere

UPDATE nume_tabel_sau_vizualizare
SET (column1[,column2[,…]]) = (subquery) / column = expr /
(query)
[WHERE condition]
Observaţii:
Pentru a se putea executa instrucţiunea UPDATE, utilizatorul
care o lansează în execuţie trebuie să aibă acest privilegiu.
Dacă nu este specificată clauza WHERE se vor modifica toate
liniile.
Cererea trebuie să furnizeze un număr de valori corespunzător
numărului de coloane din paranteza care precede caracterul de egalitate.

Se remarcă următoarele:
Clauza SET conţine o listă cu una sau mai multe coloane,
împreună cu o expresie care specifică noua valoare pentru fiecare coloană.
Aceasta este o listă de perechi nume-valoare, separate prin virgule, cu un
operator de egalitate între fiecare nume şi valoare.
Expresia poate fi o constantă, un alt nume de coloană sau orice
altă expresie pe care SQL o poate transforma într-o singură valoare, care
poate fi apoi atribuită coloanei respective.
Clauza WHERE conţine o expresie care limitează rândurile
actualizate. Dacă această clauză este omisă, motorul SQL va încerca să
actualizeze toate rândurile din tabel sau din vizualizare.

Exemple:
Un film a fost adăugat cu un preţ incorect. Instrucţiunea
următoare va actualiza două coloane din acelaşI rând a tabelului MOVIE.

UPDATE FILM
SET RETAIL_PRET_VHS = 29.95 ,
RETAIL_PRET_DVD = 34.95
WHERE FILM_ID = 21

Conducerea firmei de produse video a decis să crească salariul


tuturor funcţionarilor cu 10 procente. Această instrucţiune va actualiza o
singură coloană de pe mai multe rânduri, rotujind rezultatul la 2 zecimale cu
funcţia ROUND.

UPDATE ANGAJAT
SET ANGAJAT_PLATA_ORA = ROUND
(ANGAJAT_PLATA_ORA * 1.1, 2)
WHERE ANGAJAT_JOB_CATEGORY =‟C‟ ;

Exemple BD CARTE

Preţul cărţilor scrise de Lucian Blaga să fie modificat, astfel încât să fie egal
cu preţul celei mai scumpe cărţi de informatică din bibliotecă.
UPDATE carte
SET pret = (SELECT MAX(pret)
FROM carte
WHERE coded = ‟I‟)
WHERE autor = ‟Lucian Blaga‟;
Exemplu:
Să se modifice preţul cărţilor din bibliotecă, care se găsesc într-un număr de
exemplare mai mic decât media numărului de exemplare pe bibliotecă. Noua
valoare a preţului să fie egală cu suma preţurilor cărţilor scrise de Zola.
UPDATE carte
SET pret = (SELECT SUM(pret)
FROM carte
WHERE autor = ‟Zola‟)
WHERE nrex < (SELECT AVG(nrex)
FROM carte);

Exemplu:
Să se reducă cu 10% salariile redactorilor şefi care nu sunt asociaţi
nici unei publicaţii.
UPDATE salariat
SET salariu = 0,9*salariu
WHERE cod_salariat IN
(SELECT cod_salariat
FROM redactor_sef
WHERE cod_salariat NOT IN
(SELECT cod_salariat
FROM publicatie));
Exemplu:
Să se mărească cu 5% salariile redactorilor şefi ce coordoneaza publicaţiile
care au cel mai mare număr de frame-uri.
UPDATE salariat
SET salariu = 1,05*salariu
WHERE cod_salariat IN
(SELECT cod_salariat
FROM publicatie
WHERE nr_publicatie IN
(SELECT nr_publicatie
FROM frame
GROUP BY nr_publicatie
HAVING COUNT(*) > ALL
(SELECT COUNT(*)
FROM frame
GROUP BY nr_publicatie)));
** Oracle9i permite utilizarea valorii implicite DEFAULT in comenzile
INSERT si UPDATE. Unei coloane i se atribuie valoarea implicită definită la
crearea sau modificarea structurii tabelului dacă nu se precizează nici o valoare sau
dacă se precizează cuvântul cheie DEFAULT în comenzile INSERT sau UPDATE.
Dacă nu este definită nici o valoare implicită pentru coloana respectivă, sistemul îi
atribuie valoarea null.
Exemplu:
UPDATE carte
SET pret = DEFAULT
WHERE codel = 77;

Exemplu BD GALERIE ARTA


a) Să se transfere în galeria 10 opera având codul 110.
UPDATE opera
SET cod_galerie = 10
WHERE cod_opera = 110;

b) Să se modifice informaţiile referitoare la opera având codul 120,


considerând că se află expusă în aceeaşi galerie şi a fost achiziţionată la aceeaşi
dată ca şi opera al cărei cod este 110.
UPDATE opera
SET (cod_galerie, data_achizitiei) =
(SELECT cod_galerie, data_achizitiei
FROM opera
WHERE cod_opera = 110)
WHERE cod_opera = 120;

c) Să se modifice copie_opera pe baza valorilor din tabelul opera. Se


consideră că operele care au acelaşi autor ca şi opera având codul 100 sunt expuse
în galeria ce conţine lucrarea al cărei cod este 110.
UPDATE copie_opera
SET cod_galerie = (SELECT cod_galerie
FROM opera
WHERE cod_opera = 110)
WHERE cod_autor = (SELECT cod_autor
FROM opera
WHERE cod_opera = 100);
Cazurile în care instrucţiunea UPDATE nu poate fi executată sunt similare
celor în care eşuează instrucţiunea INSERT. Acestea au fost menţionate anterior.
Exemplu:
UPDATE opera
SET cod_galerie = 47
WHERE cod_galerie = 40;
Deoarece galeria având codul 47 nu există în tabelul „părinte“ (galerie),
instrucţiunea precedentă va genera eroarea „ORA-02291: integrity constraint
(STUDENT.SYS_C002773) violated - parent key not found“.

Exemplu:
Să se transfere în galeria având codul 50 toate operele din galeria 60, care
sunt create de Nicolae Grigorescu. Să se mărească cu 10% valoarea acestor opere.
UPDATE opera o
SET cod_galerie = 50,
valoare = valoare * 1.10
WHERE (SELECT INITCAP(nume) ||' '||INITCAP(prenume)
FROM artist
WHERE cod_artist = o.cod_artist)= 'Nicolae Grigorescu'
AND o.cod_galerie = 60;

Exemplu:
Să se actualizeze operele al căror autor este Ştefan Luchian astfel: codul
galeriei devine codul galeriei în care este expusă cea mai scumpă operă a artistului,
valoarea fiecărei opere va fi mărită cu 10% din media valorilor operelor din
galerie, iar data achiziţiei va fi considerată data celei mai recente achiziţii din
galerie.
UPDATE opera o
SET cod_galerie = (SELECT cod_galerie
FROM artist a, opera b
WHERE a.cod_artist = b.cod_artist
AND INITCAP(nume) = 'Luchian '
AND INITCAP(prenume) = 'Stefan'
AND valoare =
(SELECT MAX(valoare)
FROM opera
WHERE cod_artist =
b.cod_artist)),
(valoare, data_achizitiei) =
(SELECT o.valoare + AVG(o2.valoare)*0.10,
MAX(o2.data_achizitiei)
FROM opera o2
WHERE o.cod_opera = o2.cod_opera)
WHERE cod_artist = (SELECT cod_artist
FROM artist
WHERE INITCAP(nume) = 'Luchian '
AND INITCAP(prenume) = 'Stefan');

Oracle9i introduce o nouă funcţionalitate, reprezentată de posibilitatea


utilizării valorilor implicite (DEFAULT) în instrucţiunile INSERT şi UPDATE.
Unei coloane i se atribuie valoarea implicită definită la crearea sau modificarea
structurii tabelului dacă:
nu se precizează nici o valoare;
se precizează cuvântul cheie DEFAULT în comenzile INSERT
sau UPDATE.
Dacă nu a fost definită nici o valoare implicită pentru coloana respectivă,
sistemul îi atribuie valoarea null. Cuvântul cheie DEFAULT nu poate fi specificat
la actualizarea vizualizărilor.
Exemplu:
Să se creeze tabelul test, având o coloană căreia i se specifică o valoare
implicită. Ulterior, să se modifice această valoare. Să se insereze şi să se
actualizeze câte o înregistrare din tabel, utilizând valoarea implicită.
CREATE TABLE test(
cod NUMBER PRIMARY KEY,
nume VARCHAR2(30) DEFAULT 'NECUNOSCUT');
ALTER TABLE test MODIFY (nume DEFAULT 'NEDEFINIT');
INSERT INTO test VALUES (1, DEFAULT);
UPDATE test SET nume = DEFAULT WHERE cod = 2;
Comanda (Instrucţiunea) DELETE

Instrucţiunea DELETE şterge unul sau mai multe rânduri dintr-un tabel.
Instrucţiunea poate să folosească şi o vzualizare, dar numai dacă aceasta se bazează
pe un singur tabel (ceea ce înseamnă că instrucţiunile DELETE nu pot fi folosite
pentru vizualizări care conţin uniuni). În instrucţiunile DELETE nu sunt referite
niciodată coloane, doarece instrucţiunea şterge rânduri întregi de date, inclusiv
toate valorile datelor (toate coloanele) din rândurile afectate. Dacă vreţi să ştergeţi
o singură valoare din rândurile existente, folosiţi instrucţiunea UPDATE pentru a
înlocui valorile respective cu valori nule (presupunând că valorile nule sunt
permise în acele coloane).

Sintaxa generală a instrucţiunii DELETE este

DELETE FROM nume_tabel_sau_vizualizare [AS alias]


[ WHERE conditie ];

Se remarcă următoarele:
Comanda DELETE nu şterge structura tabelului.

Clauza WHERE este opţională. Totuşi, este folosită aproape întotdeauna,


deoarece o instrucţiune DELETE fără o clauză WHERE încearcă să şteargă
toate rândurile din tabel. În clauza WHERE pot fi folosite şi subcereri.
Atunci când este inclusă, clauza WHERE specifică rândurile care urmează
să fie şterse. Orice rând pentru care condiţia WHERE este evaluată ca
adevărată este şters din tabel.
Nu se pot şterge rânduri dacă se încalcă o restricţie referenţială. În general,
rândurile subordonate trebuie şterse înaintea rândurilor părinte.
Pentru a şterge linii identificate cu ajutorul valorilor din alte tabele, se
utilizează subcereri.
Comanda nu poate fi folosită pentru ştergerea valorilor unui câmp
individual. Acest lucru se poate realiza cu ajutorul comenzii UPDATE.

Exemple BD MOVIE

Să se şteargă filmul adăugat mai devreme (cu FILM_ID = 21 ).


Se observă că trebuie să se ştergă mai întâi rândurile corespondente din
tabelele FILM_COPY şi FILM_LIMBA, deoarece acestea sunt rânduri
„copii” ale rândului din tabelul „FILM”
DELETE FROM FILM_COPY
WHERE FILM_ID = 21;

DELETE FROM FILM_LIMBA


WHERE FILM_ID = 21;

DELETE FROM FILM


WHERE FILM_ID = 21;

Să se şteargă din tabelul FILM_LIMBA toate rândurile pentru


limba spaniolă (COD_LIMBA='es' ). În multe implementări SQL se face
diferenţierea literelor mari de cele mici, caz în care valoarea codului de limbă
trebuie specificată cu litere mici pentru a se potrivi cu datele din tabel.

DELETE FROM FILM_LIMBA


WHERE COD_LIMBA =‟es‟;

Exemplu:
Să se elimine cititorii care au numele „Popa‟şi cei care au restituit astăzi cel
puţin o carte.

DELETE FROM cititor


WHERE nume=‟Popa‟
OR codec IN (SELECT codec
FROM imprumuta
WHERE data_ef=SYSDATE);

Exemplu:
Să se elimine redactorii şefi care nu au coordonat nici o publicaţie.
DELETE FROM redactor_sef
WHERE cod_salariat NOT IN
(SELECT DISTINCT cod_salariat
FROM publicatie);
Exemplu:
Să se şteargă salariul angajatului având codul 1279.
UPDATE salariat
SET salariu=null
WHERE cod_salariat = 1279;

Exemplu:
Urmatoarele doua comenzi sunt echivalente.
DELETE FROM opera
WHERE cod_opera = 777;

DELETE FROM (SELECT * FROM opera)


WHERE cod_opera = 777;

Exemplu:
Să se şteargă cartea cea mai scumpă
DELETE FROM carte
WHERE pret = (SELECT MAX(pret)
FROM carte);
Exemplu:
Pentru fiecare autor care are mai mult de 10 creaţii expuse în muzeu, să se
şteargă ultima operă creată de acesta.
DELETE FROM opera o1
WHERE cod_artist =
(SELECT cod_artist
FROM opera o2
WHERE cod_artist = o1.cod_artist
AND data_crearii =
(SELECT MAX(data_crearii)
FROM opera
WHERE cod_artist = o2.cod_artist)
AND 10 <
(SELECT COUNT(*)
FROM opera
WHERE cod_artist = o2.cod_artist));
Exemple BD GALERIE de ARTA

a) Să se suprime înregistrarea corespunzătoare operei având codul 120.


DELETE FROM opera
WHERE cod_opera = 120;

Următoarea instrucţiune are acelaşi efect, dar utilizează o subcerere:


DELETE FROM (SELECT * FROM opera)
WHERE cod_opera = 120;
b) Să se şteargă întregul conţinut al tabelului copie_opera.
(nu se foloseste caluza where)
DELETE FROM copie_opera;

c) Să se şteargă toate operele care se află expuse într-o galerie al cărei nume
conţine şirul de caractere „muzeu“.
DELETE FROM opera
WHERE cod_galerie = (SELECT cod_galerie
FROM galerie
WHERE UPPER(nume_galerie)
LIKE '%MUZEU%');
Dacă se încearcă ştergerea unei înregistrări care conţine o valoare implicată
într-o constrângere de integritate, atunci va fi returnată o eroare.
Exemplu:
DELETE FROM galerie
WHERE cod_galerie = 40;
În urma execuţiei acestei instrucţiuni sistemul generează eroarea „ORA-
02292: integrity constraint (STUDENT.SYS_C002773) violated - child record
found“, datorată calităţii de cheie externă a coloanei cod_galerie în tabelul opera.
Există opere în galeria având codul 40 şi de aceea aceasta nu poate fi suprimată.
În cazul în care constrângerea de integritate referenţială a fost definită
utilizând opţiunea ON DELETE CASCADE, atunci instrucţiunea DELETE va
şterge atât liniile indicate, cât şi liniile „copil“ din tabelele corespunzătoare.
LIMBAJUL PENTRU CONTROLUL DATELOR

Controlul unei baze de date cu ajutorul SQL-ului se refera la:


asigurarea confidentialitatii si securitatii datelor;
organizarea fizica a datelor;
realizarea unor performante;
reluarea unor actiuni in cazul unei defectiuni;
garantarea coerentei datelor in cazul prelucrarii concurente.
Sistemul de gestiune trebuie:
să pună la dispoziţia unui număr mare de utilizatori o mulţime
coerentă de date;
să garanteze coerenţa datelor în cazul manipulării simultane de
către diferiţi utilizatori.
Coerenţa este asigurată cu ajutorul conceptului de tranzacţie.
Tranzacţia este unitatea logică de lucru constând din una sau mai multe instrucţiuni
SQL, care trebuie să fie executate atomic (ori se execută toate, ori nu se execută
nici una!), asigurând astfel trecerea BD dintr-o stare coerentă în altă stare coerentă.
Dacă toate operaţiile ce constituie tranzacţia sunt executate şi devin
efective, spunem că tranzacţia este validată, iar modificările aduse de tranzacţie
devin definitive.
Dacă dintr-un motiv sau altul (neverificarea condiţiilor, accesul
imposibil) o operaţie a tranzacţiei nu a fost executată spunem că tranzacţia a fost
anulată. Modificările aduse de toate operaţiile tranzacţiei anulate sunt şi ele
anulate şi se revine la starea bazei de date de dinaintea tranzacţiei anulate.
Este posibil ca o tranzacţie să fie descompusă în subtranzacţii, astfel
încât dacă este necesar să se anuleze doar parţial unele operaţii.
 Fiecare tranzacţie se poate termina:
“normal” (commit);
“anormal” (rollback).
Controlul tranzacţiilor constă în:
definirea începutului şi sfârşitului unei tranzacţii,
validarea sau anularea acesteia,
eventuală descompunere în subtranzacţii.
Limbajul pentru controlul datelor (LCD) permite salvarea informaţiei,
realizarea fizică a modificărilor în baza de date, rezolvarea unor probleme de
concurenţă.
Limbajul conţine următoarele instrucţiuni:
COMMIT - folosită pentru permanentizarea modificărilor
executate asupra BD (modificările sunt înregistrate şi sunt vizibile tuturor
utilizatorilor);
ROLLBACK - folosită pentru refacerea stării anterioare a BD
(sunt anulate toate reactualizările efectuate de la începutul tranzacţiei);
SAVEPOINT - folosită în conjuncţie cu instrucţiunea
ROLLBACK, pentru definirea unor puncte de salvare în fluxul programului.
O tranzacţie constă:
dintr-o singură instrucţiune LDD;
dintr-o singură instrucţiune LCD;
din instrucţiuni LMD care fac schimbări consistente în date.
Tranzacţia începe:
după o comandă COMMIT,
după o comandă ROLLBACK,
după conectarea iniţială la Oracle,
când este executată prima instrucţiune SQL.
Tranzacţia se termină:
dacă sistemul cade;
dacă utilizatorul se deconectează;
dacă se dau comenzile COMMIT sau ROLLBACK ;
dacă se execută o comandă LDD.
După ce se termină o tranzacţie, prima instrucţiune SQL executabilă va
genera automat începutul unei noi tranzacţii.
 Un commit apare automat:
când este executată o comandă LDD;
când este executată o comandă LCD;
după o ieşire normală din SQL*Plus fără specificarea explicită a
comenzilor COMMIT sau ROLLBACK.
Un rollback apare automat după o ieşire “anormală“ din SQL*Plus sau o
cădere sistem.
Din momentul în care s-a executat instrucţiunea COMMIT, BD s-a
modificat (permanent) în conformitate cu instrucţiunile SQL executate în cadrul
tranzacţiei care tocmai s-a terminat. Din acest punct începe o nouă tranzacţie.
Dacă se foloseşte utilitarul SQL*Plus, există posibilitatea ca după fiecare
comandă LMD să aibă loc o permanentizare automată a datelor (un COMMIT
implicit). Acest lucru se poate realiza folosind comanda:
SET AUTO[COMMIT] {ON | OFF}
Comanda ROLLBACK permite restaurarea unei stări anterioare a BD.
ROLLBACK [TO [SAVEPOINT] savepoint];
Dacă nu se specifică nici un savepoint, toate modificările făcute în
tranzacţia curentă sunt anulate, iar dacă se specifică un anumit savepoint, atunci
doar modificările de la acel savepoint până în momentul respectiv sunt anulate.
Executarea unei instrucţiuni ROLLBACK presupune terminarea tranzacţiei curente
şi începerea unei noi tranzacţii.
Punctele de salvare pot fi considerate ca nişte etichete care referă o
submulţime a schimbărilor dintr-o tranzacţie, marcând efectiv un punct de salvare
pentru tranzacţia curentă. Punctele de salvare NU sunt obiecte ale schemei. Prin
urmare, nu sunt referite in DD.
Server-ul Oracle implementează un punct de salvare implicit pe care îl mută
automat după ultima comandă LMD executată. Dacă este creat un punct de salvare
având acelaşi nume cu unul creat anterior, cel definit anterior este şters automat.
SAVEPOINT savepoint;
Exemplu:
Comanda ROLLBACK nu va genera terminarea tranzacţiei.
COMMIT
INSERT …
SAVEPOINT a
UPDATE …
INSERT …
SAVEPOINT b
DELETE …
ROLLBACK TO a
Starea datelor înainte de COMMIT sau ROLLBACK este următoarea:
starea anterioară a datelor poate fi recuperată;
utilizatorul curent poate vizualiza rezultatele operaţiilor LMD
prin interogări asupra tabelelor;
alţi utilizatori nu pot vizualiza rezultatele comenzilor LMD
făcute de utilizatorul curent (read consistency);
înregistrările (liniile) afectate sunt blocate şi, prin urmare, alţi
utilizatori nu pot face schimbări în datele acestor înregistrări.
Execuţia unei comenzi COMMIT implică anumite modificări.
Toate schimbările (INSERT, DELETE, UPDATE) din baza de
date făcute după anterioara comandă COMMIT sau ROLLBACK sunt
definitive. Comanda se referă numai la schimbările făcute de utilizatorul
care dă comanda COMMIT.
Toate punctele de salvare vor fi şterse.
Starea anterioară a datelor este pierdută definitiv.
Toţi utilizatorii pot vizualiza rezultatele.
Blocările asupra liniilor afectate sunt eliberate; liniile pot fi
folosite de alţi utilizatori pentru a face schimbări în date.
Execuţia unei comenzi ROLLBACK implică anumite modificări.
Anulează tranzacţia în curs şi toate modificările de date făcute
după ultima comandă COMMIT.
Sunt eliberate blocările liniilor implicate.
Nu şterge un tabel creat prin CREATE TABLE. Eliminarea
tabelului se poate realiza doar prin comanda DROP TABLE.
Exemplu:
Ce efect are următoarea secvenţă de instrucţiuni?
(a) SELECT *
FROM salariat;

(b) SAVEPOINT a;

(c) DELETE FROM salariat;


INSERT INTO salariat
VALUES (18,‟Breaban‟,‟Marin‟,4,5000, ‟tehnored‟);
INSERT INTO salariat
VALUES (23,‟Popescu‟,‟Emil‟,7,40000,‟grafician‟);
SAVEPOINT b;

(d) INSERT INTO salariat


VALUES (29,‟‟,‟‟,5,3000000,‟tehnoredactor‟);
SELECT AVG(salariu)
FROM salariat;
(e) ROLLBACK TO b;
SELECT AVG(salariu)
FROM salariat;

(f) ROLLBACK TO a;
INSERT INTO salariat
VALUES (18,‟Ion‟,‟Mihai‟,5,580,‟redr_sef‟);
COMMIT;

Consistenţa la citire
Într-un sistem multi-user, sistemul Oracle furnizează read consistency la
nivel de instrucţiune SQL, adică o singură comandă SQL nu poate da rezultate care
sunt contradictorii sau inconsistente. Read consistency asigură că fiecare utilizator
“vede” datele aşa cum existau la ultimul commit, înainte să înceapă o operaţie
LMD. Prin urmare, modificările efectuate asupra unei baze de date nu sunt vizibile
decât după ce operaţia de actualizare a fost validată. Numai utilizatorul care a
executat tranzacţia poate vedea modificările făcute de el în cursul acestei tranzacţii.
Modelul multiversiune, furnizat de Oracle, asigură consistenţa la citire:
garantează că setul de date văzut de orice instrucţiune SQL este
consistent şi nu se schimbă în timpul execuţiei unei instrucţiuni (Oracle
asigură o consistenţă la citire la nivel de instrucţiune);
operaţiile de citire (SELECT) nu trebuie să vadă datele care sunt
în proces de schimbare;
operaţiile de scriere (INSERT, DELETE, UPDATE) nu trebuie
să afecteze consistenţa datelor şi să întrerupă sau să intre în conflict cu alte
operaţii de scriere concurente.
Cum se implementează modelul multiversiune? Dacă asupra bazei este
executată o comandă LMD, server-ul Oracle face o copie a datelor dinainte de
modificare şi o depune în segmentul rollback (undo).
Toţi utilizatorii (cu excepţia celor care modifică datele) vor vedea datele
cum sunt înainte de modificare (văd conţinutul segmentului undo). Dacă comanda
LMD este commit, atunci schimbările din baza de date devin vizibile oricărui
utilizator care foloseşte instrucţiunea SELECT. Când se termină tranzacţia, spaţiul
ocupat în segmentul undo de “vechea” dată este liber pentru reutilizare. Server-ul
Oracle asigură astfel o vizualizare consistentă a datelor în orice moment.
Carte

Controlul datelor (LCD)

Tranzacţia este o unitate logică de lucru, constituită dintr-o secvenţă de


comenzi care trebuie să se execute atomic pentru a menţine consistenţa datelor.
Server-ul Oracle asigură consistenţa datelor prin intermediul tranzacţiilor,
inclusiv în eventualitatea unei anomalii a unui proces sau a sistemului. Tranzacţiile
oferă mai multă flexibilitate şi control în modificarea datelor.
Controlul tranzacţiilor se realizează prin utilizarea instrucţiunilor limbajului
de control al datelor: COMMIT, ROLLBACK, SET TRANSACTION, SAVEPOINT.
Tranzacţiile pot fi de tip LMD, LDD sau LCD. Tranzacţiile LDD şi LCD
constau dintr-o singură instrucţiune LDD, respectiv LCD. Tranzacţiile LMD
constau dintr-o succesiune de instrucţiuni LMD care determină o modificare
consistentă a datelor. De exemplu, un transfer de fonduri între două conturi
bancare presupune debitarea unui cont şi creditarea celuilalt cu aceeaşi sumă.
Ambele acţiuni trebuie fie să eşueze, fie să se încheie cu succes. Creditarea nu
trebuie salvată fără să fie salvată şi operaţia de debitare.

Procesarea tranzacţiilor
Modificările făcute asupra datelor în timpul unei tranzacţii sunt temporare
până când tranzacţia este salvată. Operaţiile de prelucrare a datelor afectează iniţial
un buffer al bazei. Prin urmare, starea precedentă a datelor poate fi recuperată.
În general, o tranzacţie începe atunci când este întâlnită prima instrucţiune
LMD şi se termină la:
apariţia unei instrucţiuni LDD;
emiterea unei instrucţiuni LCD;
părăsirea mediului SQL*Plus;
defectarea staţiei de lucru sau la înregistrarea unei întreruperi
a sistemului.
Execuţia unei instrucţiuni LDD determină salvarea automată a modificărilor
survenite pe perioada tranzacţiei. Server-ul Oracle generează o operaţie COMMIT
implicită înainte şi după orice instrucţiune LDD. Aşadar, chiar dacă instrucţiunea
LDD nu este executată cu succes, instrucţiunea anterioară acesteia nu mai poate fi
anulată întrucât server-ul a efectuat deja operaţia COMMIT.
Instrucţiunile COMMIT şi ROLLBACK încheie tranzacţia curentă prin
definitivarea, respectiv anularea tuturor modificărilor aflate în aşteptare. Aceste
instrucţiuni permit:
asigurarea consistenţei datelor;
previzualizarea modificărilor asupra datelor înainte ca acestea
să devină permanente;
gruparea logică a operaţiilor.
Ieşirea din mediul SQL*Plus fără lansarea unei instrucţiuni COMMIT sau
ROLLBACK are ca efect salvarea automată a tranzacţiei curente.
Atunci când intervine o anomalie (cădere) a sistemului sau închiderea
anormală a sesiunii SQL*Plus, întreaga tranzacţie curentă este anulată automat
(ROLLBACK). Acest fapt împiedică eroarea să cauzeze modificări nedorite ale
datelor şi determină revenirea la starea din momentul ultimei operaţii COMMIT.
O ieşire normală din iSQL*Plus are loc prin apăsarea butonului Exit.
Terminarea normală a unei sesiuni SQL*Plus are loc prin execuţia comenzii EXIT.
În SQL*Plus, închiderea ferestrei este interpretată ca ieşire anormală.
Interfaţa SQL*Plus pune la dispoziţie variabila de mediu AUTOCOMMIT,
care poate avea valorile ON sau OFF. Dacă această variabilă are valoarea ON,
atunci efectul fiecărei instrucţiuni LMD se definitivează imediat ce instrucţiunea a
fost executată. Dacă variabila AUTOCOMMIT are valoarea OFF, definitivarea
unei tranzacţii va avea loc la execuţia comenzii COMMIT sau în cazurile de salvare
automată a tranzacţiilor, prezentate anterior.
După încheierea unei tranzacţii, următoarea instrucţiune SQL executabilă
marchează automat începutul unei noi tranzacţii.

Comanda COMMIT
Instrucţiunea COMMIT determină încheierea tranzacţiei curente şi
permanentizarea modificărilor care au intervenit pe parcursul acesteia.
Instrucţiunea suprimă toate punctele intermediare definite în tranzacţie şi
eliberează blocările tranzacţiei. De asemenea, instrucţiunea poate fi utilizată pentru
terminarea unei tranzacţii read-only începută printr-o comandă SET
TRANSACTION.
Sistemul lansează implicit o comandă COMMIT înainte şi după orice
instrucţiune LDD. Sintaxa corespunzătoare comenzii COMMIT este următoarea:
COMMIT [WORK] [COMMENT 'text' | FORCE 'text' [, nr_întreg] ];
Opţiunea WORK a fost introdusă din motive de conformitate cu standardul
SQL. Instrucţiunile COMMIT şi COMMIT WORK sunt echivalente.
Clauza COMMENT permite specificarea unui comentariu care va fi asociat
tranzacţiei curente. Textul care îi urmează poate ocupa maxim 255 octeţi şi va fi
stocat în vizualizarea DBA_2PC_PENDING din dicţionarul datelor.
Într-un sistem distribuit, clauza FORCE permite salvarea manuală a unei
tranzacţii distribuite in-doubt (în care operaţia COMMIT a fost întreruptă de o
cădere a sistemului sau a reţelei). Textul care îi urmează conţine identificatorul
local sau global al tranzacţiei. Pentru a afla aceşti identificatori se poate consulta,
de asemenea, vizualizarea DBA_2PC_PENDING din dicţionarul datelor.
Pentru a atribui tranzacţiei un system change number (SCN) se specifică un
număr întreg în clauza FORCE. Valoarea unui SCN este mărită ori de câte ori este
salvată o tranzacţie. Acest număr are un rol important în asigurarea consistenţei la
citire. În general, o cerere citeşte un bloc de date care are ca atribut un SCN
corespunzător ultimei modificări a blocului respectiv. Dacă acest SCN este mai
mare decât cel citit la începutul interogării, înseamnă că blocul a fost modificat
ulterior lansării cererii. Prin urmare, trebuie găsită o versiune mai veche a blocului
în segmentele de anulare.
O instrucţiune COMMIT care conţine clauza FORCE permanentizează
numai tranzacţia specificată şi nu o afectează pe cea curentă. Prezenţa acestei
clauze nu este permisă în PL/SQL.
Exemplu:
Să se insereze o înregistrare în tabelul artist şi să se permanentizeze
modificarea.
INSERT INTO artist(cod_artist, nume, prenume)
VALUES (189, 'Pallady', 'Theodor');
COMMIT;
Înainte de operaţia COMMIT, utilizatorul curent poate vizualiza rezultatele
comenzilor LMD prin interogarea tabelelor. Efectele acestor operaţii nu sunt
vizibile celorlalţi utilizatori. Server-ul Oracle asigură consistenţa la citire, astfel
încât fiecare utilizator vizualizează datele în starea corespunzătoare ultimei operaţii
COMMIT efectuate asupra lor. Liniile afectate de tranzacţia curentă sunt blocate,
nefiind posibilă modificarea lor de către ceilalţi utilizatori.
Dacă mai mulţi utilizatori modifică simultan acelaşi tabel, fiecare dintre
aceştia poate consulta numai propriile modificări. Pe măsură ce operaţia COMMIT
este executată de către utilizatori, actualizările efectuate de aceştia devin vizibile.
În urma execuţiei instrucţiunii COMMIT, modificările asupra datelor sunt
scrise în baza de date, iar starea precedentă a datelor este pierdută definitiv. În
acest fel, rezultatele tranzacţiei pot fi vizualizate de către toţi utilizatorii. Blocările
asupra liniilor afectate sunt eliberate, astfel că înregistrările devin disponibile
celorlalţi utilizatori pentru a efectua noi actualizări. După operaţia COMMIT, toate
punctele intermediare (SAVEPOINT) ale tranzacţiei respective sunt şterse.

Comanda ROLLBACK
Atunci când o linie este modificată, valorile anterioare ale coloanelor
actualizate sunt salvate într-un segment de reluare. Dacă tranzacţia este anulată,
server-ul Oracle va rescrie valorile din acest segment în linia tabelului.
Pentru a renunţa la modificările efectuate se utilizează instrucţiunea
ROLLBACK. În urma execuţiei acesteia, se încheie tranzacţia, se anulează
modificările asupra datelor, se restaurează starea lor precedentă şi se eliberează
blocările asupra liniilor.
O parte a tranzacţiei poate fi anulată automat printr-o operaţie ROLLBACK
implicită dacă a fost detectată o eroare în timpul execuţiei unei instrucţiuni. Dacă o
singură instrucţiune LMD eşuează în timpul execuţiei unei tranzacţii, efectul său
este anulat de un ROLLBACK la nivel de instrucţiune, dar schimbările efectuate de
instrucţiunile LMD precedente nu sunt anulate. Acestea din urmă pot fi salvate sau
anulate explicit de către utilizator.
Sintaxa instrucţiunii ROLLBACK este următoarea:
ROLLBACK [WORK]
[TO [SAVEPOINT] pct_intermediar | FORCE 'text'];
Semnificaţiile opţiunilor WORK şi FORCE sunt similare celor prezentate în
cadrul instrucţiunii COMMIT.
În clauza TO SAVEPOINT se poate specifica punctul intermediar până la
care se doreşte anularea tranzacţiei. În absenţa acestei clauze, întreaga tranzacţie
este anulată. O tranzacţie in-doubt nu poate fi anulată manual până la un punct
intermediar.
Dacă a fost definit un punct intermediar prin instrucţiunea SAVEPOINT
nume, instrucţiunea ROLLBACK TO SAVEPOINT nume determină întoarcerea
tranzacţiei curente la punctul intermediar specificat.
În felul acesta se revine într-o stare anterioară a tranzacţiei şi se anulează
modificările care au survenit după definirea punctului intermediar. De asemenea,
sunt şterse punctele intermediare ulterioare acestuia şi sunt eliberate toate blocările
asupra tabelelor sau liniilor, efectuate după punctul intermediar respectiv.

Comanda SAVEPOINT
Instrucţiunea SAVEPOINT marchează un punct intermediar în procesarea
tranzacţiei. În acest mod este posibilă împărţirea tranzacţiei în subtranzacţii.
Această instrucţiune nu face parte din standardul ANSI al limbajului SQL.
Punctele intermediare definite în procesarea unei tranzacţii nu sunt obiecte
ale schemei şi nu pot fi referite în dicţionarul datelor. Nu există nici o modalitate
de a lista punctele intermediare definite. Dacă este creat un al doilea punct
intermediar având acelaşi nume cu un punct intermediar precedent, acesta din urmă
este şters.
Instrucţiunea SAVEPOINT are sintaxa:
SAVEPOINT nume_pct_intermediar;

Exemplu:
Să se mărească prin 20%, respectiv 50% valoarea operelor care au codurile
100, respectiv 150. Să se verifice că valoarea totală a operelor din galerie nu
depăşeşte 7 000 000, iar apoi să se reactualizeze valoarea operei având codul 150,
mărind-o cu 40%.
UPDATE opera
SET valoare = valoare * 1.2
WHERE cod_opera = 100;
SAVEPOINT val_100;
UPDATE opera
SET valoare = valoare * 1.5
WHERE cod_opera = 150;
SAVEPOINT val_150;
SELECT SUM(valoare)
FROM opera;
ROLLBACK TO SAVEPOINT val_100;
UPDATE opera
SET valoare = valoare * 1.4
WHERE cod_opera = 150;
COMMIT;
Consistenţa la citire
Utilizatorii pot accesa baza de date prin operaţii de citire (instrucţiuni
SELECT) sau prin operaţii de scriere (instrucţiuni INSERT, UPDATE, DELETE).
Consistenţa la citire este necesară pentru a asigura că:
datele vizualizate de către utilizatorii care scriu şi citesc din
baza de date sunt consistente;
utilizatorii care citesc din baza de date nu pot vizualiza starea
datelor care sunt în curs de modificare;
utilizatorii care scriu în baza de date sunt asiguraţi că
modificările asupra acesteia se realizează în mod consistent;
modificările pe care le efectuează un utilizator nu intră în
conflict cu cele ale altui utilizator.
Scopul consistenţei la citire este ca fiecare utilizator să vizualizeze datele în
starea existentă la ultima operaţie COMMIT.
Consistenţa la citire se implementează automat, prin păstrarea unei copii
parţiale a bazei de date în segmentele de reluare. Atunci când se efectuează o
operaţie INSERT, UPDATE sau DELETE, server-ul Oracle reţine o copie a datelor
în starea dinaintea modificării şi o scrie într-un segment de reluare.
Pentru toţi utilizatorii care citesc din baza de date, cu excepţia celui care a
iniţiat modificarea, datele sunt vizibile în starea dinaintea începerii reactualizării.
Aceşti utilizatori vizualizează starea datelor din segmentul de reluare. Astfel, se
garantează că utilizatorii citesc date consistente care nu sunt în curs de schimbare.
După ce se efectuează operaţia COMMIT asupra tranzacţiei, modificările
făcute în baza de date devin vizibile tuturor. Server-ul Oracle creează vizualizări
consistente la citire pentru interogările care au început înainte ca tranzacţia să fie
salvată. Apoi, spaţiul ocupat de datele vechi în segmentul de reluare va fi eliberat
pentru a fi refolosit.
Dacă se efectuează operaţia ROLLBACK asupra tranzacţiei, modificările
sunt anulate. Astfel, versiunea datelor salvate în segmentul de reluare este rescrisă
în tabel, iar baza de date revine în starea de dinaintea începerii tranzacţiei.

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