29.11.2014 Views

Capitolul II Structurarea bazelor de date

Capitolul II Structurarea bazelor de date

Capitolul II Structurarea bazelor de date

SHOW MORE
SHOW LESS

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

32<br />

<strong>Capitolul</strong> <strong>II</strong><br />

<strong>Structurarea</strong> <strong>bazelor</strong> <strong>de</strong> <strong>date</strong><br />

Scurt istoric<br />

În anii '60, A.F. Codd, cercetător la I.B.M., a studiat posibilitatea<br />

ameliorării modului <strong>de</strong> stocare a <strong>date</strong>lor în fişiere <strong>de</strong>oarece existenŃa informaŃiilor<br />

redundante predispunea la erori greu <strong>de</strong> <strong>de</strong>pistat. În 1970 a publicat un articol,<br />

"A Relational Mo<strong>de</strong>l of Data for Large Shared Databanks" care a schimbat<br />

complet concepŃiile privind structura <strong>bazelor</strong> <strong>de</strong> <strong>date</strong>. Un programator, Larry<br />

Ellison, sesizând importanŃa practică a teoriei lui Codd, a realizat un produs<br />

software, Oracle, şi o firmă pentru promovarea acestuia, Oracle Corporation. L.<br />

Ellison a <strong>de</strong>venit astfel unul dintre cei mai bogaŃi oameni <strong>de</strong> pe planetă.<br />

Anomalii rezolvate <strong>de</strong> mo<strong>de</strong>lul relaŃional<br />

Să presupunem că într-o bibliotecă, bibliotecara păstrează evi<strong>de</strong>nŃa<br />

cărŃilor cu ajutorul calculatorului, într-un fişier pentru cărŃi având următoarea<br />

structură:<br />

NrInv Autor Titlu Editura Locul Anul<br />

apariŃiei<br />

Având în ve<strong>de</strong>re posibilităŃile unui calculator legate <strong>de</strong> parcurgerea<br />

fişierelor, s-ar părea că vor putea fi realizate uşor o mulŃime <strong>de</strong> rapoarte. În<br />

timpul exploatării pe calculator a fişierului s-au <strong>de</strong>pistat însă probleme cauzate<br />

<strong>de</strong> modul <strong>de</strong> structurare a informaŃiilor.<br />

1. Anomalia la actualizarea <strong>date</strong>lor:<br />

Conducerea bibliotecii a impus ca numele autorului să fie scris cu<br />

majuscule. Pentru autorii mai puŃin prolifici nu e nici o problemă, dar unii se<br />

regăsesc în fişier <strong>de</strong> zeci sau chiar sute <strong>de</strong> ori. Modificarea în sute <strong>de</strong> locuri a<br />

aceluiaşi nume poate conduce la erori greu <strong>de</strong> <strong>de</strong>pistat. Această anomalie poartă<br />

numele <strong>de</strong> anomalia la actualizare. Pentru eliminarea ei, mo<strong>de</strong>lul relaŃional<br />

propune structurarea informaŃiilor în două tabele: un tabel cu numele autorilor şi<br />

un tabel cu cărŃi:<br />

CodAutor Autor<br />

NrInv CodAutor Titlu Editura Locul Anul apariŃieie


33<br />

În momentul înregistrării unei cărŃi, dacă autorul exista <strong>de</strong>ja în tabelul <strong>de</strong><br />

autori, i se notează codul care apoi este folosit la înregistrarea cărŃii. Dacă<br />

autorul nu există în fişierul <strong>de</strong> autori, el va fi adăugat, în momentul adăugării<br />

atribuindu-se un cod. În acest mod, modificarea numelui autorilor se realizează<br />

simplu, numele fiecărui autor apărând o singură dată.<br />

2. Anomalia la ştergerea <strong>date</strong>lor:<br />

Această anomalie poate apărea dacă se cere ştergerea din fişierul <strong>de</strong> cărŃi<br />

a înregistrării corespunzând unei cărŃi pierdute. Odată cu titlul cărŃii se şterge şi<br />

editura care a publicat-o. Ulterior, dacă se doreşte realizarea unui raport privind<br />

editurile cu care biblioteca are relaŃii, în raport nu va mai figura editura care a<br />

realizat cartea suprimată. Acestă anomalie poartă numele <strong>de</strong> anomalia la<br />

ştergerea <strong>date</strong>lor.<br />

3. Anomalia la adăugarea <strong>date</strong>lor:<br />

Dacă se doreşte înregistrarea în baza <strong>de</strong> <strong>date</strong> a bibliotecii a <strong>date</strong>lor unei<br />

noi edituri, în mo<strong>de</strong>lul elaborat acest lucru nu este posibil fără adăugarea unei<br />

prime cărŃi achiziŃionate <strong>de</strong> la aceasta. Dacă nu s-a cumpărat nici o carte, baza<br />

noastră prezintă o anomalie la adăugarea <strong>date</strong>lor.<br />

Normalizarea<br />

Mo<strong>de</strong>lul relaŃional elaborat <strong>de</strong> Codd propune soluŃii pentru eliminarea<br />

acestor anomalii. Procesul <strong>de</strong> structurare a bazei <strong>de</strong> <strong>date</strong> în ve<strong>de</strong>rea eliminării<br />

anomaliilor sesizate poartă numele <strong>de</strong> normalizare. Normalizarea constă în<br />

aducerea bazei <strong>de</strong> <strong>date</strong> într-una dintre formele normale, cele mai importante<br />

fiind cele 3 forme prezentate în continuare.<br />

1. Prima formă normală<br />

Prima formă normală cere ca tabelele în care sunt păstrate informaŃiile să<br />

satisfacă următoarelor cerinŃe:<br />

a. Fiecare coloană trebuie să păstreze o informaŃie elementară (care nu se<br />

mai poate <strong>de</strong>scompune). În exemplul prezentat, dacă o carte are mai<br />

mulŃi autori coloana CodAutor ar trebui să conŃină mai multe coduri,<br />

<strong>de</strong>ci acest mod <strong>de</strong> structurare nu respectă această cerinŃă.<br />

b. Fiecare coloană trebuie să aibă un nume unic;<br />

c. Tabelul nu poate avea două linii conŃinând informaŃii i<strong>de</strong>ntice. Fiecare<br />

tabel din componenŃa unei baze <strong>de</strong> <strong>date</strong> normalizate conŃine o cheie<br />

primară. O cheie primară este un câmp care are valori distincte<br />

pentru toate liniile tabelului. Uneori, mai rar, cheia primară este<br />

obŃinută prin alăturarea valorilor dintr-un ansamblu <strong>de</strong> mai multe<br />

câmpuri. Pot exista în baza <strong>de</strong> <strong>date</strong> tabele care nu au o cheie primară.<br />

Tabelele pentru care s-a <strong>de</strong>finit o cheie primară respectă, <strong>de</strong> regulă,<br />

cerinŃa enunŃată.


34<br />

d. Într-un tabel nu se admit grupuri <strong>de</strong> informaŃii care se repetă. În<br />

exemplul dat Editura şi Locul formează un grup care probabil se repetă<br />

pentru toate cărŃile provenind <strong>de</strong> la aceeaşi editură.<br />

2. A doua formă normală<br />

A doua formă normală se referă la tabelele care au o cheie compusă din<br />

valorile mai multor câmpuri. Astfel, în exemplul dat dacă <strong>date</strong>le editurii sunt<br />

păstrate într-un tabel separat având structura:<br />

NumeEd Oras Adresa NumeScurt Telefon<br />

atunci adăugarea unui nou sediu pentru o editură va face ca valoarea din coloana<br />

"NumeScurt" să apară repetat, <strong>de</strong>oarece ea nu <strong>de</strong>pin<strong>de</strong> <strong>de</strong> sediul editurii ci <strong>de</strong><br />

numele acesteia. Pentru a satisface cerinŃele celei <strong>de</strong>-a doua forme normale,<br />

coloanele unui tabel trebuie să <strong>de</strong>pindă direct <strong>de</strong> toate câmpurile care formează o<br />

cheie primară compusă.<br />

3. A treia formă normală<br />

A treia formă normală rezolvă anomalia care apare în cazul în care într-un<br />

tabel există una sau mai multe coloane ale căror valori nu <strong>de</strong>pind direct <strong>de</strong><br />

valoarea cheii primare. În exemplul dat, să presupunem că în tabelul în care<br />

sunt înregistrate cărŃile există o coloană care conŃine numele furnizorului (firma<br />

prin care s-a achiziŃionat cartea). Cu siguranŃă că prin acelaşi furnizor s-au<br />

achiziŃionat şi alte cărŃi, <strong>de</strong>ci numele acestuia va apărea pe mai multe linii<br />

<strong>de</strong>oarece furnizorul nu <strong>de</strong>pin<strong>de</strong> direct <strong>de</strong> carte. Coloanele unui tabel care<br />

satisface a treia formă normală conŃin informaŃii care <strong>de</strong>pind direct <strong>de</strong> cheia<br />

primară.<br />

RelaŃii între tabelele unei baze <strong>de</strong> <strong>date</strong><br />

Pentru a satisface cerinŃele impuse <strong>de</strong> cele 3 forme normale prezentate,<br />

informaŃiile sunt <strong>de</strong> regulă păstrate într-un ansamblu <strong>de</strong> tabele între care există<br />

relaŃii <strong>de</strong> diferite tipuri.<br />

1. RelaŃii 1 la mai mulŃi (1 la n, one to many)<br />

Dacă în exemplul consi<strong>de</strong>rat <strong>date</strong>le privind o editură sunt păstrate într-un<br />

fişier iar cărŃile sunt înregistrate în alt fişier, între cele două tabele se stabileşte o<br />

<strong>de</strong>pen<strong>de</strong>nŃă <strong>de</strong> tip "unul la mai mulŃi".


35<br />

cod editură<br />

Edituri<br />

CodE<br />

Nume Adresa Telefon<br />

editura<br />

cod autor<br />

NrInv CodA Titlu CodE Anul Carti<br />

carte<br />

Acest tip <strong>de</strong> relaŃie este cel mai frecvent întâlnit şi stă la baza mo<strong>de</strong>lului<br />

relaŃional elaborat <strong>de</strong> Codd.<br />

Cheile primare din cele două tabele sunt CodE pentru Edituri şi NrInv<br />

pentru CărŃi. În tabelul <strong>de</strong> cărŃi, CodE şi CodA (cod autor) sunt chei străine. O<br />

cheie străină dintr-un tabel A permite regăsirea unei linii dintr-un tabel asociat,<br />

B. În tabelul asociat, B, cheia străină din tabelul A este <strong>de</strong> regulă cheie primară.<br />

În cazul dat, cheia străină CodA permite regăsirea în tabelul <strong>de</strong> autori a numelui<br />

acestuia iar cheia străină CodE permite găsirea numelui editurii care a publicat<br />

cartea.<br />

2. RelaŃii 1 la 1 (one to one)<br />

O relaŃie <strong>de</strong> tipul 1 la 1 apare în cazul în care unei linii dintr-un tabel îi<br />

corespun<strong>de</strong> o singură linie în tabelul cu care acesta este în legătură. În cazul în<br />

care fiecărei înregistrări dintr-un tabel îi corespun<strong>de</strong> o înregistrare în al doilea<br />

tabel nu este necesară înregistrarea informaŃiilor în două tabele separate.<br />

3. RelaŃii mai mulŃi la mai mulŃi (m la n, many to many)<br />

O relaŃie <strong>de</strong> acest tip apare în exemplul dat între tabela <strong>de</strong> autori şi cea <strong>de</strong><br />

cărŃi. Astfel un scriitor poate fi autor la mai multe cărŃi iar o carte poate avea<br />

mai mulŃi autori (CodA_2 respectiv NrInv_3 <strong>de</strong> exemplu).<br />

În astfel <strong>de</strong> situaŃii se va proceda la crearea unui tabel suplimentar, <strong>de</strong><br />

legătură, care va transforma relaŃia evi<strong>de</strong>nŃiată (many to many) în relaŃii one to<br />

many. Fiecare articol din tabelul <strong>de</strong> legătură va conŃine o pereche <strong>de</strong> chei<br />

străine, una fiind cheie primară în primul tabel şi una în al doilea tabel:


36<br />

Autori<br />

∞<br />

∞<br />

CărŃi<br />

CodA_1<br />

NrInv_1<br />

CodA_2<br />

NrInv_2<br />

CodA_3<br />

NrInv_3<br />

CodA_4<br />

NrInv_4<br />

CodA_5<br />

NrInv_5<br />

CodA_6<br />

NrInv_6<br />

CodA_7<br />

NrInv_7<br />

NrInv_8<br />

NrInv_9<br />

CodA_1<br />

Autori<br />

1 ∞ Tab. <strong>de</strong> legătură ∞ 1<br />

CodA_2 NrInv_1<br />

NrInv _1<br />

CărŃi<br />

CodA_2<br />

CodA_2<br />

NrInv _3<br />

NrInv _2<br />

CodA_3<br />

CodA_3<br />

NrInv _3<br />

NrInv _3<br />

CodA_4<br />

CodA_6<br />

NrInv _3<br />

NrInv _4<br />

CodA_5<br />

CodA_2<br />

NrInv _8<br />

NrInv _5<br />

CodA_6<br />

NrInv _6<br />

CodA_7<br />

NrInv _7<br />

NrInv _8<br />

NrInv _9


37<br />

<strong>Capitolul</strong> <strong>II</strong>I<br />

Limbajul SQL<br />

În 1992 ANSI (American National Standards Institute) a <strong>de</strong>finitivat<br />

varianta standard a unui limbaj <strong>de</strong>stinat sistemelor <strong>de</strong> gestiune a <strong>bazelor</strong> <strong>de</strong> <strong>date</strong><br />

<strong>de</strong>numit Structured Query Language, prescurtat SQL (pronunŃaŃi "es-q-el").<br />

Frazele SQL permit crearea, actualizarea, interogarea şi distrugerea <strong>bazelor</strong> <strong>de</strong><br />

<strong>date</strong> relaŃionale. Deşi toate S.G.B.D. folosesc SQL, a<strong>de</strong>sea ele implementează şi<br />

funcŃii care nu există în standard.<br />

Comenzile <strong>de</strong> bază ale limbajului SQL care sunt Create, Alter, Select,<br />

Insert, Up<strong>date</strong>, Delete şi Drop sunt suportate <strong>de</strong> toate sistemele <strong>de</strong> gestiune<br />

<strong>de</strong> baze <strong>de</strong> <strong>date</strong> şi permit realizarea tuturor activităŃilor majore legate <strong>de</strong> crearea<br />

şi exploatarea <strong>bazelor</strong> <strong>de</strong> <strong>date</strong> relaŃionale. Cuvintele cheie ale limbajului SQL pot<br />

fi scrise atât cu litere mici cât şi cu majuscule.<br />

Odată instalat, serverul Oracle XE oferă două interfeŃe pentru introducerea<br />

comenzilor SQL:<br />

a. Introducerea comenzilor SQL folosind interpretorul <strong>de</strong> comenzi<br />

SQL *Plus executabil într-o fereastră <strong>de</strong> tip Command Prompt<br />

Lansarea în execuŃie a interpretorului se realizează accesând Run SQL<br />

Command Line din grupul <strong>de</strong> comenzi Oracle Database 10g Express Edition:<br />

După lansarea în execuŃie a interpertorului este necesară conectarea la<br />

serverul Oracle XE printr-o comandă connect, ca în exemplul următor, după care<br />

pot fi introduse comenzi. Comenzile SQL pot fi introduse pe mai multe linii,<br />

marcarea sfârşitului introducerii unei comenzi realizându-se printr-un caracter '/'.


38<br />

b. Introducerea comenzilor SQL folosind interfaŃa grafică:<br />

După conectare se selectează SQL Commands / Enter Command.


39<br />

Comenzile introduse în fereastra SQL Commands pot fi terminate prin ';'<br />

ca în MySQL <strong>de</strong> exemplu sau se poate chiar omite caracterul terminal. Astfel<br />

pentru suprimarea tabelului cafea se poate scrie:<br />

drop table cafea;<br />

sau pur şi simplu<br />

drop table cafea<br />

efectul fiind acelaşi.<br />

Comenzile SQL pot fi memorate individual apăsând butonul Save:<br />

clic):<br />

Comenzile memorate pot fi reexecutate prin selectare cu mouse-ul (dublu


40<br />

Tipuri <strong>de</strong> <strong>date</strong> suportate <strong>de</strong> Oracle<br />

<strong>date</strong>:<br />

a. Şiruri <strong>de</strong> caractere<br />

Pentru păstrarea şirurilor <strong>de</strong> caractere, Oracle <strong>de</strong>fineşte patru tipuri <strong>de</strong><br />

- VARCHAR2 - pentru şiruri <strong>de</strong> caractere <strong>de</strong> lungime variabilă,<br />

- NVARCHAR2 pentru şiruri <strong>de</strong> caractere <strong>de</strong> lungime variabilă în<br />

format UNICODE (16 biŃi / caracter),<br />

- CHAR - pentru şiruri <strong>de</strong> caractere având lungime fixă,<br />

- NCHAR - pentru şiruri <strong>de</strong> caractere având lungime fixă, în format<br />

UNICODE.<br />

Indiferent <strong>de</strong> tip, la <strong>de</strong>clararea unui câmp trebuie precizată lungimea:<br />

nume varchar2(50)<br />

Pentru VARCHAR2 lungimea specificată este cea maximă admisă în timp<br />

ce pentru CHAR ea va fi efectiv utilizată, şirurile <strong>de</strong> lungime mai mică fiind<br />

completate la dreapta cu spaŃii. Rezultă că VARCHAR2 este mai eficient, în<br />

exemplele prezentate în continuare acest tip fiind utilizat sistematic.<br />

b. Date numerice<br />

Datele numerice pot fi <strong>de</strong>clarate în Oracle folosind unul dintre tipurile<br />

următoare:<br />

- NUMBER - pentru numere zecimale,<br />

- BINARY_FLOAT - pentru numere reale (memorate fără conversie<br />

în baza 10)<br />

- BINARY_DOUBLE- pentru numere reale în dublă precizie<br />

(memorate fără conversie).<br />

Cel mai frecvent se foloseşte tipul NUMBER. Pentru <strong>de</strong>clararea unei <strong>date</strong><br />

<strong>de</strong> tip NUMBER se poate scrie:<br />

inaltime number(3)


41<br />

sau,<br />

inaltime number(3,0)<br />

Pentru numere care au o parte întreagă şi una zecimală se scrie:<br />

pret NUMBER(7,2)<br />

însemnând reprezentarea câmpului pret folosind 7 poziŃii zecimale, ultimele două<br />

fiind folosite pentru partea reală.<br />

Exemple:<br />

Număr DeclaraŃie Valoare memorată<br />

123.89 NUMBER 123.89<br />

123.89 NUMBER(3) 124<br />

123.89 NUMBER(6,2) 123.89<br />

123.89 NUMBER(6,1) 123.9<br />

123.89 NUMBER(3) eroare (<strong>de</strong>păşire)<br />

123.89 NUMBER(4,2) eroare (<strong>de</strong>păşire)<br />

BINARY_FLOAT şi BINARY_DOUBLE sunt tipuri recoman<strong>date</strong> în cazul în<br />

care <strong>date</strong>le astfel reprezentate sunt folosite la calcule mai complicate.<br />

c. Tipuri pentru timp şi dată calendaristică<br />

Pentru <strong>de</strong>clararea câmpurilor care vor păstra data calendaristică sau<br />

timpul, Oracle foloseşte tipurile DATE şi TIMESTAMP.<br />

Formatele implicite <strong>de</strong> introducere a <strong>date</strong>i şi a timpului rezultă din tabelul<br />

următor.<br />

Valoare Tip dată Val. memorată<br />

12-MAR-2007<br />

DATE<br />

2007-02-01 01:02:04.1234 TIMESTAMP<br />

d. Tipuri pentru memorarea imaginilor<br />

Pentru <strong>de</strong>clararea câmpurilor <strong>de</strong>stinate păstrării în baza <strong>de</strong> <strong>date</strong> a<br />

imaginilor, Oracle foloseşte tipurile CLOB sau BLOB.


42<br />

Crearea tabelelor în Oracle XE<br />

Comanda CREATE TABLE<br />

Comanda CREATE TABLE serveşte la crearea unui nou tabel şi la<br />

<strong>de</strong>scrierea câmpurilor acestuia. Ea are formatul general:<br />

CREATE TABLE nume<br />

(nume_câmp tip_câmp [(marime [,precizie])]<br />

[NULL | NOT NULL]<br />

[PRIMARY KEY | UNIQUE]<br />

[,nume_câmp tip_câmp [(marime [,precizie])]<br />

[NULL | NOT NULL]<br />

)<br />

Exemplu:<br />

CREATE TABLE regiune<br />

)<br />

(ID_regiune CHAR(2) NOT NULL PRIMARY KEY,<br />

nume VARCHAR2(40)<br />

Crearea tabelelor va fi realizată mai uşor folosind interfaŃa serverului<br />

Oracle XE, aşa cum s-a procedat în primele cursuri. În cazul în care în momentul<br />

creării unui tabel se impun restricŃii asupra câmpurilor, se <strong>de</strong>clară chei străine<br />

sau se <strong>de</strong>clară o cheie primară, fraza SQL corespunzătoare va conŃine un număr<br />

<strong>de</strong> restricŃii introduse folosind cuvântul rezervat "constraints".<br />

Exemplu:<br />

CREATE TABLE "DEMO_ORDERS"<br />

( "ORDER_ID" NUMBER NOT NULL ENABLE,<br />

"CUSTOMER_ID" NUMBER NOT NULL ENABLE,


43<br />

"ORDER_TOTAL" NUMBER(8,2),<br />

"ORDER_TIMESTAMP" DATE,<br />

"USER_ID" NUMBER,<br />

CONSTRAINT "DEMO_ORDER_PK" PRIMARY KEY ("ORDER_ID") ENABLE,<br />

CONSTRAINT "DEMO_ORDER_TOTAL_MIN" CHECK (or<strong>de</strong>r_total >= 0) ENABLE,<br />

CONSTRAINT "DEMO_ORDERS_CUSTOMER_ID_FK" FOREIGN KEY ("CUSTOMER_ID")<br />

REFERENCES "DEMO_CUSTOMERS" ("CUSTOMER_ID") ENABLE,<br />

CONSTRAINT "DEMO_ORDERS_USER_ID_FK" FOREIGN KEY ("USER_ID")<br />

REFERENCES "DEMO_USERS" ("USER_ID") ENABLE<br />

)<br />

/<br />

Obs. În fraza SQL afişată <strong>de</strong>numirile câmpurilor, constrângerilor sau<br />

<strong>de</strong>numirea tabelului apar între ghilimele. Această scriere permite folosirea <strong>de</strong><br />

<strong>de</strong>numiri conŃinând spaŃii (<strong>de</strong> evitat!). Dacă <strong>de</strong>numirile nu pot da naştere la<br />

confuzii, ghilimelele pot fi omise.<br />

Cele patru constrângeri <strong>de</strong>clarate se referă la cheia primară, limitarea unei<br />

valori şi <strong>de</strong>clară două câmpuri ca fiind chei străine, precizând şi tabelele legate.<br />

În primul exemplu cheia primară a fost <strong>de</strong>clarată adăugând <strong>de</strong>scrierii câmpului<br />

ID_regiune cuvintele PRIMARY KEY.<br />

Din aceste exemple se observă diversitatea modatităŃilor <strong>de</strong> scriere a unei<br />

comenzi SQL. Pentru a limita volumul <strong>de</strong> cunoştinŃe legate <strong>de</strong> sintaxa limbajului,<br />

în cele ce urmează comenzile vor fi realizate şi testate folosind interfaŃa<br />

aplicaŃiei. Aşa cum s-a văzut <strong>de</strong>ja, interfaŃa permite şi afişarea comenzilor<br />

create. Deoarece în timpul realizării unei baze <strong>de</strong> <strong>date</strong> se pot produce inci<strong>de</strong>nte<br />

mergând până la distrugerea serverului Oracle XE, este bine să fie păstrate întrun<br />

fişier având extensia .sql un număr cât mai mare <strong>de</strong> fraze a căroir executare<br />

să permită refacerea tabelelor şi repopularea lor cu <strong>date</strong>.<br />

Comanda DROP TABLE<br />

este:<br />

Comanda DROP TABLE permite suprimarea unui tabel. Sintaxa comenzii<br />

DROP TABLE Nume_tabel<br />

Pentru a da comanda folosind interfaŃa grafică se selectează succesiv<br />

Object Browser / Browse / Tables, se selectează apoi tabelul şi se apasă butonul<br />

Drop:


44<br />

Comanda SELECT<br />

Comanda SELECT creează o mulŃime <strong>de</strong> selecŃie. Aceasta poate conŃine<br />

un articol, mai multe articole sau niciunul. Articolele din mulŃimea <strong>de</strong> selecŃie<br />

conŃin numai câmpurile indicate <strong>de</strong> programator. Din acest punct <strong>de</strong> ve<strong>de</strong>re se<br />

poate consi<strong>de</strong>ra că SELECT crează un subtabel conŃinând numai informaŃiile<br />

specificate. Câmpurile înregistrărilor mulŃimii <strong>de</strong> selecŃie pot proveni dintr-un<br />

tabel sau din mai multe tabele legate.<br />

Comanda SELECT are formatul general:<br />

SELECT [DISTINCT] coloana1 [,coloana2]<br />

FROM tabel_1[,tabel_2, ...]<br />

[WHERE condiŃii]<br />

[GROUP BY listă-coloane]<br />

[HAVING conditii]<br />

[ORDER BY listă-coloane [ASC | DESC] ]<br />

Dintre cele 5 clauze ale comenzii SELECT numai clauza FROM este<br />

obligatorie. Fiecare dintre clauze are la rândul ei reguli şi parametri pentru<br />

construcŃie, făcând din SELECT cea mai complexă comandă a limbajului SQL. În<br />

frazele SELECT şirurile <strong>de</strong> caractere se pun între caractere ' (apostrof).<br />

Pentru construirea unei comenzi SELECT se poate folosi asistentul Query<br />

Buil<strong>de</strong>r.


45<br />

AplicaŃia va afişa trei panouri:<br />

- în stânga un panou conŃinând tabelele cuprinse în schema curentă :<br />

- în centru un panou conŃinând tabelele selectate:<br />

clic<br />

clic<br />

Notă: JOB_ID din Jobs = JOB_ID din Employees. Pentru impunerea<br />

legăturii se va selecta succesiv cu mouse-ul JOB_ID din Employees şi din Jobs.<br />

- în partea <strong>de</strong> jos un panou cuprinzând câmpurile selectate şi alte<br />

specificaŃii:


46<br />

Selectarea dintr-un singur tabel<br />

Exemple fundamentale:<br />

SELECT Nume, Prenume FROM cititor<br />

SELECT * FROM cititor<br />

SELECT * FROM cititor WHERE nume = 'Popescu'<br />

SELECT nume, prenume, adresa FROM cititor WHERE nume LIKE 'Po%'<br />

SELECT Nume, Prenume FROM cititor ORDER BY Nume<br />

Numele coloanelor scrise după SELECT precizează câmpurile mulŃimii <strong>de</strong><br />

selecŃie. Dacă se doreşte ca mulŃimea <strong>de</strong> selecŃie să aibă aceeaşi structură cu<br />

tabelul, în locul listei <strong>de</strong> coloane se pune *.<br />

Clauza WHERE permite limitarea mulŃimii <strong>de</strong> selecŃie prin introducerea<br />

unei condiŃii care specifică înregistrările căutate. În cazul selectării din mai multe<br />

tabele, această clauză poate fi folosită şi pentru a introduce legăturile dintre<br />

tabele. La scrierea condiŃiei se pot folosi operatorii logici AND, OR sau NOT<br />

precum şi operatorii relaŃionali:<br />

= Egal<br />

> Mai mare<br />

< Mai mic<br />

>= Mai mare sau egal<br />


47<br />

IN('Ioan','Vasile','Grigore')<br />

IN specifică o mulŃime căreia trebuie să-i aparŃină câmpul specificat<br />

(prenume).<br />

SELECT * FROM cititor WHERE nume = 'Popescu' AND data_nasterii<br />

BETWEEN '12-MAY-1968' AND '29-MAY-1980'<br />

Clauza BETWEEN permite <strong>de</strong>finirea unui interval căruia trebuie să-i<br />

aparŃină câmpul specificat (data_nasterii).<br />

Clauza ORDER BY serveşte la impunerea ordinii <strong>de</strong> afişare a înregistrărilor mulŃimii <strong>de</strong><br />

selecŃie. Ordonarea poate fi realizată după valorile unuia sau a mai multor câmpuri, crescător (ASC)<br />

sau <strong>de</strong>screscător (DESC). În cazul în care se folosesc mai multe câmpuri, acestea sunt separate prin<br />

virgulă.<br />

ASC<br />

SELECT * FROM Cititor ORDER BY Nume,Prenume,ID_cititor<br />

SELECT * FROM Angajati ORDER BY salar DESC, Nume ASC, Prenume<br />

Clauza DISTINCT permite realizarea unei mulŃimi <strong>de</strong> selecŃie care<br />

conŃine înregistrări distincte, care diferă prin cel puŃin o valoare a unui câmp. De<br />

exemplu :<br />

SELECT DISTINCT Localitate FROM cititor<br />

Ultima frază va provoca afişarea numelor localităŃilor în care domiciliază<br />

cititorii. Fără clauza DISTINCT, numele oraşului Cluj-Napoca ar fi fost repetat <strong>de</strong><br />

mai multe ori.<br />

câmp.<br />

Clauza GROUP BY permite gruparea înregistrărilor după valoarea unui<br />

Exemplul 1:<br />

SELECT Localitate, COUNT(*) as Nr_Cititori FROM Cititor GROUP BY<br />

Localitate<br />

În cazul în care se realizează o grupare, fiecare dintre liniile mulŃimii <strong>de</strong><br />

selecŃie se referă la un grup <strong>de</strong> înregistrări şi nu la înregistrări simple. În<br />

exemplul prece<strong>de</strong>nt, GROUP BY Localitate precizează câmpul după care se<br />

realizează gruparea. Înafara valorii câmpului după care se face gruparea, în<br />

astfel <strong>de</strong> situaŃii liniile mulŃimii <strong>de</strong> selecŃie pot conŃine rezultatul aplicării unor<br />

funcŃii matematice asupra articolelor care formează grupul (suma valorilor dintrun<br />

câmp, media valorilor, valoarea maximă sau minimă, numărul <strong>de</strong> articole care<br />

formează grupul etc). Pentru câmpurile care vor conŃine rezultatul aplicării unor


48<br />

funcŃii se recomandă folosirea clausei AS nume pentru atribuirea unui nume<br />

relevant coloanei respective. În exemplul dat s-a afişat rezultatul funcŃiei<br />

COUNT(*), care numără înregistrările din grup. FuncŃiile care pot fi apelate<br />

pentru câmpuri numerice sunt prezentate în tabelul <strong>de</strong> mai jos.<br />

MIN<br />

MAX<br />

SUM<br />

AVG<br />

COUNT<br />

COUNT DISTINCT<br />

Exemplul 2:<br />

returnează cea mai mică valoare dintr-o<br />

coloană (câmp numeric)<br />

returnează cea mai mare valoare dintr-o<br />

coloană (câmp numeric)<br />

returnează suma valorilor numerice<br />

dintr-o coloană (câmp numeric)<br />

returnează media valorilor dintr-o coloană<br />

(câmp numeric)<br />

returnează numărul <strong>de</strong> valori dintr-o<br />

coloană<br />

returnează numărul <strong>de</strong> valori distincte<br />

dintr-o coloană<br />

SELECT Sectie, MAX(salar) as Sal_Max FROM Angajati<br />

GROUP BY Sectie<br />

Se pot însă aplica aceleaşi funcŃii şi întregului fişier, fără gruparea<br />

articolelor, caz în care mulŃimea <strong>de</strong> selecŃie va conŃine o singură înregistrare:<br />

SELECT AVG(salar) FROM Angajati<br />

SELECT AVG(salar) FROM Angajati WHERE functie='Zidar'<br />

SELECT COUNT(*) FROM Cititor<br />

Clauza HAVING serveşte la precizarea unui filtru care se aplică grupurilor <strong>de</strong> articole,<br />

dacă este prezentă clauza GROUP BY.<br />

500<br />

Exemplu:<br />

SELECT Sectie, AVG(Salar) FROM Angajati GROUP BY Sectie HAVING AVG(Salar) ><br />

Dacă în fraza SELECT lipseşte clauza GROUP BY, folosirea clauzei HAVING nu se<br />

justifică, ea având acelaşi efect ca şi clauza WHERE.<br />

O situaŃie aparte prezintă comenzile SELECT care nu realizează o mulŃime<br />

<strong>de</strong> selecŃie ci un calcul matematic. În acest caz from nume_tabel va fi înlocuit<br />

prin from dual, ca în exemplul următor:


49<br />

Cuvântul rezervat dual astfel folosit permite respectarea sintaxei comenzii<br />

SELECT.<br />

Selectarea din mai multe tabele<br />

Principial o bază <strong>de</strong> <strong>date</strong> relaŃională presupune repartizarea <strong>date</strong>lor în mai<br />

multe tabele. Aşa cum s-a văzut <strong>de</strong>ja, acest mod <strong>de</strong> stocare permite eliminarea<br />

informaŃiilor redondante. Pentru a găsi articolele dintr-un tabel legate <strong>de</strong> o<br />

înregistrare din alt tabel trebuie însă indicată în frazele SELECT condiŃia <strong>de</strong><br />

legătură dintre cele două tabele.<br />

Exemple:<br />

SELECT Edituri.Nume, Carti.Titlu, Carti.Anul FROM Edituri, Carti WHERE<br />

Nume='Minerva' AND Edituri.CodE=Carti.CodE<br />

A doua condiŃie conŃinută în clauza WHERE este cea care leagă tabelele<br />

Edituri şi Carti.<br />

Limbajul SQL permite înlocuirea unei mulŃimi care contribuie la selecŃie<br />

printr-o altă frază SELECT, ca în exemplul următor.<br />

SELECT Edituri.Nume, Carti.Titlu, Carti.Anul FROM Edituri, Carti WHERE<br />

Nume='Minerva' AND Edituri.CodE=Carti.CodE AND Titlu.Data IN (SELECT<br />

Data FROM Carti WHERE Data BETWEEN '12-MAY-1975' AND '29-MAY-1980')<br />

Odată cu standardizarea limbajului SQL, pentru introducerea legăturilor<br />

stabilite între tabele prin <strong>de</strong>finirea <strong>de</strong> chei primare şi străine s-a <strong>de</strong>finit şi o altă<br />

modalitate, respectiv clauza JOIN. Folosind JOIN, exemplul anterior poate fi scris<br />

astfel:<br />

SELECT Edituri.Nume, Carti.Titlu, Carti.Anul<br />

FROM Edituri INNER JOIN Carti ON Edituri.CodE=Carti.CodE<br />

WHERE Nume='Minerva'


50<br />

Clauza JOIN este însă şi soluŃie într-o altă situaŃie, respectiv când într-un<br />

tabel se acceptă pentru o cheie străină valori nule. Un exemplu simplu este cel<br />

al tabelelor Angajati şi SoŃi prezentate în continuare.<br />

Dintre angajaŃii din primul tabel doi sunt căsătoriŃi, în cazul lor ID_SOT<br />

are valori nenule.<br />

Dacă se doreşte realizarea unei mulŃimi <strong>de</strong> selecŃie care să cuprindă<br />

angajaŃii, iar pentru cei căsătoriŃi numele şi prenumele soŃului/soŃiei, fraza<br />

SELECT ar putea fi următoarea:<br />

select Angajati.Nume, Angajati.Prenume,Soti.Nume_prenume<br />

from Angajati, Soti where Angajati.ID_SOT=SOTI.ID_SOT<br />

Rezultat:<br />

Rezultatul nu este cel dorit <strong>de</strong>oarece prin condiŃia pusă sunt excluşi din<br />

mulŃimea <strong>de</strong> selecŃie angajaŃii necăsătoriŃi.<br />

SoluŃia este oferită <strong>de</strong> clauza LEFT OUTER JOIN:<br />

select Angajati.Nume, Angajati.Prenume,Soti.Nume_prenume<br />

from Angajati left outer join Soti on Angajati.ID_SOT=SOTI.ID_SOT


51<br />

Rezultatul va cuprin<strong>de</strong> toate liniile din primul tabel iar pentru liniile din<br />

primul tabel care au corespon<strong>de</strong>nt în al doilea tabel, va inclu<strong>de</strong> şi informaŃiile<br />

corespunzătoare din al doilea tabel.<br />

Similar se poate folosi clauza RIGHT OUTER JOIN pentru inclu<strong>de</strong>rea<br />

tuturor înregistrărilor din al doilea tabel şi selectarea din primul doar a celor care<br />

satisfac relaŃia <strong>de</strong> legătură.<br />

Utilizarea parametrilor<br />

SQL permite ca la scrierea comenzii SELECT să se folosească parametrii.<br />

Valorile acestora sunt cerute într-o fereastră separată, în momentul executării<br />

interogării.<br />

Exemplu :<br />

sql>select * from edituri where cod_edit > :co<strong>de</strong>d;


52<br />

Comanda INSERT<br />

Comanda INSERT adaugă un rând într-un tabel existent.<br />

Exemplu:<br />

INSERT INTO Edituri(CodE,Nume,Adresa,Telefon) VALUES(121,<br />

'Albatros','B-dul Tomis Nr. 32 Constanta','0745654765')<br />

Lista <strong>de</strong> câmpuri <strong>de</strong> după numele tabelei poate fi omisă dacă toate<br />

câmpurile primesc valori iar acestea sunt scrise în ordinea <strong>de</strong>finită la creare (în<br />

care ele apar în capul <strong>de</strong> tabel). Dacă un câmp nu primeşte valoare el va primi<br />

implicit valoarea NULL, dacă la creare, prin modul <strong>de</strong> <strong>de</strong>clarare a câmpului,<br />

introducerea unei astfel <strong>de</strong> valori este autorizată.<br />

Comanda DELETE<br />

Comanda DELETE suprimă una sau mai multe înregistrări dintr-un fişier.<br />

Ca şi în cazul comenzii SELECT, pentru <strong>de</strong>finirea unui set <strong>de</strong> înregistrări care vor<br />

fi şterse se utilizează clauza WHERE.<br />

Exemple:<br />

DELETE FROM Autori WHERE CodAut=7<br />

DELETE FROM Edituri<br />

Ultima comandă suprimă toate înregistrările din tabelul Edituri.<br />

Comanda UPDATE<br />

Comanda UPDATE permite modificarea unei înregistrări sau a unui set <strong>de</strong><br />

înregistrări. Pentru precizarea setului <strong>de</strong> înregistrări afectate se foloseşte clauza<br />

WHERE.<br />

Exemplu:<br />

UPDATE Edituri SET Adresa='str. 1 Mai Nr. 12', Telefon='0745343435'<br />

WHERE Nume='Dacia'<br />

UPDATE Angajati SET Salar=Salar*1.2 WHERE Salar


18<br />

RelaŃii între tabele. Comenzi SQL<br />

Laborator nr. 2<br />

1. PorniŃi aplicaŃia – Start -> Programs -> Oracle Database 10g Express Edition -> Go To<br />

Database<br />

Home Page sau scrieŃi adresa http://127.0.0.1:8080/apex/ în browser-ul dv.<br />

2. ConectaŃi-vă la serverul Oracle Database XE , folosind contul creat la laboratorul nr. 1,<br />

respectiv numele <strong>de</strong> utilizator biblio şi parola biblio.<br />

3. Refacerea tabelelor create la laboratorul anterior (dacă e cazul) se realizează în două<br />

etape:<br />

• se refac tabelele şi<br />

• se inserează <strong>date</strong>le.<br />

Refacerea tabelelor se poate realiza folosind comenzile CREATE salvate anterior într-un<br />

fişier .txt. Comenzile pot fi introduse una câte una copiindu-le în fereastra <strong>de</strong>stinată<br />

introducerii comenzilor SQL sau toate odată, folosind posibilitatea aplicaŃiei <strong>de</strong> creare şi<br />

execuŃie a scripturilor SQL.<br />

A doua variantă fiind mai productivă va fi prezentată în continuare.<br />

Se afişează fereastra în care pot fi introduse comenzile unui script (Home / SQL / SQL Scripts<br />

/ Upload).<br />

Rezultatul este crearea unui script SQL :


19<br />

În continuare se execută scriptul (Run).<br />

4. Inserarea <strong>date</strong>lor în tabele<br />

După refacerea tabelelor bazei <strong>de</strong> <strong>date</strong> se poate trece la refacerea conŃinutului acestora<br />

folosind fişierele .txt care conŃin <strong>date</strong>le. Pentru aceasta se poate proceda astfel:<br />

• Se selectează în fereastra Home opŃiunea Utilities / Data Load/Unload / Load:<br />

• În fereastra care se afişează se selectează Load Text Data:


20<br />

• Se indică faptul că tabelul în care vor fi adăugate <strong>date</strong>le există (se selectează opŃiunea<br />

Existing table):<br />

• Se indică schema (Biblio):<br />

• Se selectează tabelul care urmează să fie repopulat cu <strong>date</strong>:<br />

• Se indică numele fişierului (Browse) şi separatorul folosit (tab, \t);<br />

• AplicaŃia afişează în continuare informaŃiile recuperate. Pentru încărcarea acestora în<br />

tabelul indicat se va apăsa butonul Load data.


21<br />

ObservaŃie: La refacerea tabelelor şi a conŃinuturilor acestora folosind metoda expusă<br />

anterior, serverul Oracle XE face toate verificările privind integritatea <strong>date</strong>lor. ImplicaŃiile<br />

acestui fapt sunt următoarele:<br />

• Salvarea comenzilor <strong>de</strong> creare a tabelelor trebuie să urmeze ordinea creerii<br />

iniŃiale a acestora. Astfel un tabel care conŃine chei străine va fi creat după<br />

crearea tabelelor <strong>de</strong> care acesta <strong>de</strong>pin<strong>de</strong>.<br />

• Restaurarea <strong>date</strong>lor trebuie să urmeze aceeaşi logică. Datele dintr-un tabel<br />

care conŃine o cheie străină vor fi încărcate după încărcarea <strong>date</strong>lor din tabelul<br />

principal, ale cărui înregistrări sunt referite prin valorile cheii străine.<br />

• Astfel, <strong>de</strong> exemplu, tabelul Edituri trebuie creat înaintea tabelului Carti.<br />

Datele din tabelul Carti nu pot fi incărcate înaintea încărcării <strong>date</strong>lor din<br />

tabelul Edituri.<br />

5. În meniul Object Browser selectaŃi Create / Table, apoi creaŃi următoarele tabele:<br />

cititori<br />

cod_cit number (4, 0)<br />

cnp number (13, 0)<br />

nume varchar2 (30)<br />

prenume varchar2 (20)<br />

localitatea varchar2 (30)<br />

ju<strong>de</strong>tul varchar2 (20)<br />

adresa varchar2 (80)<br />

telefon number (10, 0)<br />

e_mail varchar2 (50)<br />

cheie primară : cod_cit<br />

autcarti<br />

imprumut<br />

cod_carte number (4, 0) cod_carte number (4, 0)<br />

cod_autor number (4, 0) cod_cit number (4, 0)<br />

data_imprumut <strong>date</strong><br />

data_rest <strong>date</strong><br />

chei străine : cod_carte, cod_autor chei străine : cod_carte, cod_cit


22<br />

Obs.<br />

e-mail-ul poate fi null<br />

data_rest poate fi null<br />

formatul <strong>date</strong>i este ZZ-LLL-AA, <strong>de</strong> ex. 01-OCT-2006<br />

6. IntroduceŃi în aceste tabele următoarele înregistrări:<br />

- în tabelul cititori:<br />

1 || 1246845691231 || Popescu || Marin || Turda || Cluj || str. Mica, nr. 123 || 0264122112 || popescu@personal.ro<br />

2 || 2342356786431 || Maniu || Laura || Dej || Cluj || str. Zambilelor, nr. 321 || 0744123456 ||<br />

laura_maniu@yahoo.com<br />

3 || 2897654356789 || Rotaru || Călin || Sighisoara || Mureş || str. Gării, nr. 43 || 0265012021 ||<br />

calinrotaru@personal.ro<br />

- în tabelul autcarti:<br />

(1; 1), (2; 2), (3; 3), (4; 4)<br />

- în tabelul imprumut:<br />

1; 1; 10 octomrie 2001; 15 octombrie 2001<br />

1; 2; 10 februarie 2007; -<br />

etc.


23<br />

Comenzi SQL (crearea, editarea, vizualizarea, rularea şi ştergerea comenzilor SQL).<br />

7. Crearea unei comenzi SQL presupune:<br />

• <strong>de</strong>schi<strong>de</strong>rea paginii SQL-Commands<br />

• scrierea comenzii SQL<br />

Obs. Comanda SQL poate să se termine cu ';', '/' sau să nu aibă un caracter terminal.<br />

ex. :<br />

SELECT * from autori;<br />

sau<br />

SELECT * from autori<br />

/<br />

sau<br />

SELECT * from autori<br />

• rularea (Run sau Ctrl+Enter)


24<br />

• salvarea<br />

• copierea<br />

se <strong>de</strong>schi<strong>de</strong> fereastra care cuprin<strong>de</strong> comenzile salvate<br />

se selectează comanda care urmează a fi copiată<br />

se apasă Save<br />

se dă numele noii comenzi<br />

se editează (dacă e cazul) comanda nouă


25<br />

se salvează din nou<br />

se rulează<br />

8. IntroduceŃi câteva comenzi SQL, folosind şi opŃiunea <strong>de</strong> salvare a acestor comenzi:<br />

toŃi autorii în ordine alfabetica, afişând toate câmpurile tabelului<br />

select * from autori or<strong>de</strong>r by nume asc<br />

numele şi prenumele autorilor în irdine alfabetică<br />

select nume, prenume from autori or<strong>de</strong>r by nume asc<br />

titlurile cărŃilor din bibliotecă<br />

select titlu from carti<br />

titlurile cărŃilor apărute în anul 1991<br />

select titlu from carti where an_apar=1991<br />

titlurile cărŃilor apărute în anul specificat <strong>de</strong> utilizator (variabilă)<br />

select titlu from carti where an_apar=:an<br />

titlul cărŃilor şi anul <strong>de</strong> apariŃie pentru cărŃile care au codul > 2<br />

select titlu, an_apar from carti where cod_carte>2


26<br />

titlul cărŃii, anul apariŃiei şi codul cărŃii pentru cărŃile apărute înainte <strong>de</strong> 1991 şi<br />

care au codul < 2<br />

select titlu, an_apar, cod_carte from carti where an_apar2<br />

numele şi prenumele cititorilor care au nume care încep cu Po<br />

select nume, prenume from cititori where nume like 'Po%'<br />

afişarea localităŃilor <strong>de</strong> un<strong>de</strong> provin cititorii<br />

select distinct localitatea from cititori<br />

afişarea numărului <strong>de</strong> cărŃi din biblitecă<br />

select count(*) as nr from carti<br />

9. IntroduceŃi şi alte comenzi SQL pentru a afla <strong>date</strong> din celelalte tabele.


27<br />

Laborator nr. 3<br />

RelaŃii între tabele. Comenzi SQL care selectează <strong>date</strong> din mai multe tabele<br />

1. PorniŃi aplicaŃia: – Start -> Programs -> Oracle Database 10g Express Edition -> Go To<br />

Database Home Page sau scrieŃi adresa http://127.0.0.1:8080/apex/ în browser-ul dv.<br />

2. ConectaŃi-vă la serverul Oracle Database XE , folosind contul creat la laboratorul nr. 1,<br />

respectiv numele <strong>de</strong> utilizator biblio şi parola biblio.<br />

3. IntroduceŃi câteva comenzi SQL, folosind şi opŃiunea <strong>de</strong> salvare a acestor comenzi:<br />

selectarea cărŃilor şi editurilor corespunzătoare<br />

select carti.titlu as titlul_cartii, edituri.nume as editura from carti , edituri where<br />

carti.cod_edit = edituri.cod_edit<br />

selectarea tuturor cărŃilor şi vizualizarea titlurilor şi a anilor apariŃiei acestora<br />

împreună cu autorii lor:<br />

select carti.titlu as titlul_cartii, carti.an_apar as anul_aparitiei, autori.nume as<br />

autorul, carti.cod_carte, autcarti.cod_carte from autori, carti, autcarti where<br />

autcarti.cod_carte = carti.cod_carte and autcarti.cod_autor = autori.cod_autor<br />

afişaŃi titlul cărŃii (în ordine alfabetică), numele şi prenumele autorului şi<br />

editura:<br />

select carti.titlu as titlul_cartii, TRIM(autori.nume) || ' ' || TRIM(autori.prenume)<br />

as Nume_autor, edituri.nume as editura from autori, carti, autcarti, edituri<br />

where autcarti.cod_carte = carti.cod_carte and autcarti.cod_autor =<br />

autori.cod_autor and carti.cod_edit = edituri.cod_edit<br />

Obs. Concatenarea se realizează cu ajutorul caracterului ||.


28<br />

AfişaŃi titlul cărŃii, numele şi prenumele autorului, numele şi prenumele<br />

cititorului pentru cărŃile împrumutatate inainte <strong>de</strong> 01 oct 2008:<br />

select carti.titlu as titlul_cartii, TRIM(autori.nume)||' '||TRIM(autori.prenume) as<br />

Nume_autor, TRIM(cititori.nume)||' '||TRIM(cititori.prenume) as Cititorul from<br />

autori, carti, autcarti, cititori, imprumut where autcarti.cod_carte =<br />

carti.cod_carte and autcarti.cod_autor = autori.cod_autor and cititori.cod_cit =<br />

imprumut.cod_cit and imprumut.cod_carte = carti.cod_carte and<br />

data_imprumut < '10-OCT-2008'<br />

4. IntroduceŃi şi alte comenzi SQL pentru a afla <strong>date</strong> din celelalte tabele.<br />

O mică pauză…<br />

constructivă<br />

łinând cont <strong>de</strong> importanŃa înŃelegerii modului <strong>de</strong> structurare a unei baze <strong>de</strong> <strong>date</strong>, în<br />

continuare vor fi prezentate câteva studii <strong>de</strong> caz: evi<strong>de</strong>nŃa notelor elevilor, evi<strong>de</strong>nŃa câinilor <strong>de</strong><br />

rasă, gestionarea informaŃiilor legate <strong>de</strong> o bancă…sau orice altceva….<br />

1. CreaŃi un utilizator nou, scoala, cu parola scoala<br />

2. CreaŃi o bază <strong>de</strong> <strong>date</strong> pentru gestionarea materiilor pre<strong>date</strong> şi a notelor obŃinute <strong>de</strong><br />

elevi.<br />

3. Pentru acesta creaŃi următoarele tabele:<br />

ELEVI<br />

cod_elev - cheie primară (număr întreg)<br />

nume - (şir <strong>de</strong> caractere)<br />

initiala - (caracter)<br />

prenume - (caracter)<br />

data_nasterii - (data)<br />

adresa - (caracter)<br />

telefon - (caracter)


29<br />

MATER<strong>II</strong><br />

NOTE<br />

cod_materie - cheie primară (număr)<br />

nume_materie - (caracter)<br />

cod_nota - cheie primară (număr)<br />

cod_elev - cheie străină (număr)<br />

cod_materie - cheie străină (număr)<br />

data - (dată calendaristică)<br />

nota - (număr)<br />

4. Se cere:<br />

• Să se adauge 4 elevi, 3 materii, şi câte 2 note fiecărui elev la fiecare materie;<br />

ELEVI<br />

NOTE<br />

MATER<strong>II</strong>


30<br />

• Să se afişeze toŃi elevii în ordine alfabetică sub forma:<br />

nume, initiala, prenume, data_naşterii<br />

Vom folosi editorul <strong>de</strong> interogări (Query Buil<strong>de</strong>r)<br />

Fiind o interogare bazată pe un singur tabel, trebuie să parcurgem următoarele etape:<br />

• Selectăm tabelul şi alegem câmpurile care sunt parte a interogării:<br />

• Adăugăm condiŃiile <strong>de</strong> ordonare:<br />

• Salvăm interogarea (Save):


31<br />

• Executăm interogarea (Run):<br />

Fraza SQL generată poate fi afişată:<br />

select "ELEVI"."NUME" as "NUME",<br />

"ELEVI"."INITIALA" as "INITIALA",<br />

"ELEVI"."PRENUME" as "PRENUME",<br />

"ELEVI"."DATA_NASTER<strong>II</strong>" as "DATA_NASTER<strong>II</strong>"<br />

from "ELEVI" "ELEVI"<br />

or<strong>de</strong>r by ELEVI.NUME ASC, ELEVI.INITIALA ASC, ELEVI.PRENUME ASC<br />

5. Alte interogări:<br />

• Să se afişeze toŃi elevii cu toate notele la toate materiile sub forma:<br />

nume, initiala, prenume, materia, nota<br />

în ordinea <strong>de</strong>screscătoare a notelor , elevii fiind ordonaŃi alfabetic<br />

etape:<br />

Fiind o interogare bazată pe mai multe tabele, trebuie să parcurgem următoarele<br />

• Alegem tabelele necesare şi selectăm câmpurile care sunt parte a interogării:


32<br />

• Adăugăm condiŃiile <strong>de</strong> legătură şi selectăm numai câmpurile care urmează să fie<br />

afişate<br />

• Adăugăm criteriile <strong>de</strong> ordonare:<br />

• Salvăm interogarea (Save);


33<br />

• Executăm interogarea (Run)<br />

Fraza SQL generată poate fi afişată:<br />

select "ELEVI"."NUME" as "NUME",<br />

"ELEVI"."INITIALA" as "INITIALA",<br />

"ELEVI"."PRENUME" as "PRENUME",<br />

"MATER<strong>II</strong>"."NUME_MATERIE" as "NUME_MATERIE",<br />

"NOTE"."NOTA" as "NOTA"<br />

from "NOTE" "NOTE",<br />

"MATER<strong>II</strong>" "MATER<strong>II</strong>",<br />

"ELEVI" "ELEVI"<br />

where "NOTE"."COD_ELEV" =elevi.cod_elev<br />

and "NOTE"."COD_MATERIE" =materii.cod_materie<br />

or<strong>de</strong>r by NOTE.NOTA DESC, ELEVI.NUME ASC, ELEVI.INITIALA ASC, ELEVI.PRENUME<br />

ASC<br />

• Să se afişeze toŃi elevii cu toate notele la o materie (<strong>de</strong> ex. limba română) sub<br />

forma:<br />

nume, initiala, prenume, materia, nota<br />

în ordinea <strong>de</strong>screscătoare a notelor , elevii fiind ordonaŃi alfabetic.<br />

select<br />

from<br />

"ELEVI"."NUME" as "NUME",<br />

"ELEVI"."INITIALA" as "INITIALA",<br />

"ELEVI"."PRENUME" as "PRENUME",<br />

"MATER<strong>II</strong>"."NUME_MATERIE" as "NUME_MATERIE",<br />

"NOTE"."NOTA" as "NOTA"<br />

"NOTE" "NOTE",


34<br />

"MATER<strong>II</strong>" "MATER<strong>II</strong>",<br />

"ELEVI" "ELEVI"<br />

where "MATER<strong>II</strong>"."NUME_MATERIE" ='Limba romana'<br />

and "NOTE"."COD_ELEV" =elevi.cod_elev<br />

and "NOTE"."COD_MATERIE" =materii.cod_materie<br />

or<strong>de</strong>r by NOTE.NOTA DESC, ELEVI.NUME ASC, ELEVI.INITIALA ASC, ELEVI.PRENUME<br />

ASC<br />

rezultatul:<br />

• Să se afişeze toŃi elevii cu note <strong>de</strong> 10 la o materie (<strong>de</strong> ex. limba română) sub<br />

forma:<br />

nume, initiala, prenume, materia, nota<br />

elevii fiind ordonaŃi alfabetic.<br />

select "ELEVI"."NUME" as "NUME",<br />

"ELEVI"."INITIALA" as "INITIALA",<br />

"ELEVI"."PRENUME" as "PRENUME",<br />

"MATER<strong>II</strong>"."NUME_MATERIE" as "NUME_MATERIE",<br />

"NOTE"."NOTA" as "NOTA"<br />

from "NOTE" "NOTE",<br />

"MATER<strong>II</strong>" "MATER<strong>II</strong>",<br />

"ELEVI" "ELEVI"<br />

where "MATER<strong>II</strong>"."NUME_MATERIE" ='Limba romana'<br />

and "NOTE"."NOTA" =10<br />

and "NOTE"."COD_ELEV" =elevi.cod_elev<br />

and "NOTE"."COD_MATERIE" =materii.cod_materie<br />

or<strong>de</strong>r by ELEVI.NUME ASC, ELEVI.INITIALA ASC, ELEVI.PRENUME ASC<br />

rezultatul:<br />

• Să se afişeze elevii care au nota 10 , indiferent <strong>de</strong> materie.<br />

select<br />

"ELEVI"."NUME" as "NUME",<br />

"ELEVI"."INITIALA" as "INITIALA",<br />

"ELEVI"."PRENUME" as "PRENUME",


35<br />

"NOTE"."NOTA" as "NOTA",<br />

"MATER<strong>II</strong>"."NUME_MATERIE" as "NUME_MATERIE"<br />

from "MATER<strong>II</strong>" "MATER<strong>II</strong>",<br />

"NOTE" "NOTE",<br />

"ELEVI" "ELEVI"<br />

where "NOTE"."NOTA" =10<br />

and "NOTE"."COD_ELEV" =elevi.cod_elev<br />

and "NOTE"."COD_MATERIE" =materii.cod_materie<br />

or<strong>de</strong>r by ELEVI.NUME ASC, ELEVI.INITIALA ASC, ELEVI.PRENUME ASC<br />

rezultat:<br />

• Să se afişeze toate notele mai mari <strong>de</strong> 7, obŃinute la matematică dupa 01-JAN-<br />

2008 .<br />

select "ELEVI"."NUME" as "NUME",<br />

"ELEVI"."INITIALA" as "INITIALA",<br />

"ELEVI"."PRENUME" as "PRENUME",<br />

"MATER<strong>II</strong>"."NUME_MATERIE" as "NUME_MATERIE",<br />

"NOTE"."DATA" as "DATA",<br />

"NOTE"."NOTA" as "NOTA"<br />

from "NOTE" "NOTE",<br />

"MATER<strong>II</strong>" "MATER<strong>II</strong>",<br />

"ELEVI" "ELEVI"<br />

where "NOTE"."COD_ELEV"="ELEVI"."COD_ELEV"<br />

and "NOTE"."COD_MATERIE"="MATER<strong>II</strong>"."COD_MATERIE"<br />

and "MATER<strong>II</strong>"."NUME_MATERIE" ='Matematica'<br />

and "NOTE"."DATA" >'01-JAN-2008'<br />

and "NOTE"."NOTA" >7<br />

or<strong>de</strong>r by ELEVI.NUME ASC, ELEVI.INITIALA ASC, ELEVI.PRENUME ASC<br />

rezultat posibil :


36<br />

<strong>Capitolul</strong> IV<br />

Limbajul PL/SQL<br />

GeneralităŃi<br />

Limbajul SQL (Structured Query Language) este un limbaj <strong>de</strong>clarativ<br />

orientat pe obŃinerea <strong>de</strong> mulŃimi <strong>de</strong> selecŃie într-o aplicaŃie în arhitectură clientserver.<br />

EficienŃa sa este remarcabilă dar în cazul în care elementele unei mulŃimi<br />

<strong>de</strong> selecŃie trebuie accesate pe rând, nu în grup, utilizarea sa nu mai este<br />

posibilă. Pe <strong>de</strong> altă parte SQL nu oferă nici suportul necesar realizării interfeŃei<br />

unei aplicaŃii. În contrast cu SQL, limbajele procedurale pot manipula linii<br />

individuale dintr-o mulŃime <strong>de</strong> selecŃie. Ele dispun <strong>de</strong> funcŃii care permit trecerea<br />

<strong>de</strong> la o linie la alta şi ramificarea codului în funcŃie <strong>de</strong> rezultatul testării valorilor<br />

preluate din tabelele bazei <strong>de</strong> <strong>date</strong>.<br />

Limbajul PL/SQL (Procedural Language extensions to SQL) a fost<br />

<strong>de</strong>zvoltat <strong>de</strong> compania Oracle ca extensie a limbajului <strong>de</strong>clarativ SQL. PL/SQL<br />

este un limbaj <strong>de</strong> programare procedural care poate fi folosit pentru <strong>de</strong>scrierea<br />

unor prelucrări complexe sau pentru programarea unor secvenŃe <strong>de</strong> cod care<br />

trebuie executate automat la apariŃia unui eveniment (triggere).<br />

O caracteristică remarcabilă a limbajului PL/SQL este faptul că<br />

procedurile sau funcŃiile scrise vor fi memorate în baza <strong>de</strong> <strong>date</strong>. Aceleaşi<br />

prelucrări pot fi realizate <strong>de</strong> regulă şi în cadrul aplicaŃiilor client care accesează<br />

<strong>date</strong>le din bază, dar în cazul modificării unei meto<strong>de</strong> <strong>de</strong> calcul trebuie refăcute<br />

aplicaŃiile client afectate şi suportate toate costurile pe care le implică<br />

redistribuirea unor noi versiuni ale aplicaŃiilor client.<br />

Având în ve<strong>de</strong>re faptul că <strong>de</strong> multe ori aplicaŃiile din domeniul <strong>bazelor</strong> <strong>de</strong><br />

<strong>date</strong> sunt în arhitectură client-server şi aplicaŃia client accesează aplicaŃia server<br />

(Oracle XE) prin intermediul unei reŃele, utilizarea pe cât posibil a procedurilor<br />

scrise în PL/SQL poate ameliora semnificativ viteza <strong>de</strong> prelucrare. În cazul unei<br />

proceduri care ar implica transferul spre aplicaŃia client a unui volum mare <strong>de</strong><br />

<strong>date</strong> (rezultatul unei interogări <strong>de</strong> exemplu), întârzierile cauzate <strong>de</strong> reŃeaua prin<br />

care se accesează serverul <strong>de</strong> baze <strong>de</strong> <strong>date</strong> pot fi mari. Dacă prelucrarea <strong>date</strong>lor<br />

nu presupune afişarea acestora în aplicaŃia client, mult mai eficientă este soluŃia<br />

prelucrării <strong>date</strong>lor pe server, într-o procedură scrisă în PL/SQL.<br />

PL/SQL este bazat pe limbajul ADA, o parte dintre construcŃiile sale<br />

sintactice provenind din Pascal.<br />

Scrierea unui bloc anonim<br />

De regulă programarea în PL/SQL înseamnă <strong>de</strong>finirea unor proceduri sau<br />

funcŃii, în sensul pe care acestea le au în oricare dintre limbajele procedurale<br />

cunoscute. O procedură sau o funcŃie poate fi introdusă folosind fereastra SQL<br />

Plus sau folosind interfaŃa grafică, în SQL Command sau Script Editor.<br />

O succesiune <strong>de</strong> instrucŃiuni în PL/SQL care nu sunt <strong>de</strong>stinate <strong>de</strong>finirii<br />

unei funcŃii sau proceduri formează un bloc anonim care va fi executat doar o<br />

singură dată.


37<br />

Exemplu:<br />

begin<br />

end;<br />

/<br />

dbms_output.put_line('Hello World');<br />

În fereastra SQL*Plus secvenŃa <strong>de</strong> cod scrisă va fi precedată <strong>de</strong> comanda<br />

set serveroutput on<br />

Aceasta trebuie dată la începutul sesiunii <strong>de</strong> lucru şi realizează activarea<br />

afişării la consolă a rezultatului operaŃiilor <strong>de</strong> ieşire.<br />

Dacă se foloseşte interfaŃa grafică nu mai este necesară comanda<br />

set serveroutput on.


38<br />

Exemplul următor conŃine <strong>de</strong>claraŃia unei variabile, nr. Pentru a afişa<br />

valoarea acesteia se realizează conversia ei în şir <strong>de</strong> caractere folosind funcŃia<br />

to_char():<br />

Elementele limbajului PL/SQL<br />

Codul PL/SQL poate fi conŃinut în blocuri anonime sau în blocuri care<br />

conŃin subprograme memorate în baza <strong>de</strong> <strong>date</strong> (proceduri sau funcŃii).<br />

Un bloc anonim se introduce în fereastra în care se introduc comenzi<br />

SQL. El nu este memorat în mod normal în baza <strong>de</strong> <strong>date</strong> în ve<strong>de</strong>rea reutilizării<br />

ulterioare. InterfaŃa serverului Oracle XE permite totuşi memorarea unui bloc,<br />

întocmai ca şi memorarea unei comenzi SQL orecare. Cele două exemple<br />

anterioare sunt blocuri anonime.<br />

Un subprogram memorat (<strong>de</strong>numit uneori stocat) este un subprogram<br />

PL/SQL pe care serverul Oracle îl compilează şi îl memorează în baza <strong>de</strong> <strong>date</strong>.<br />

Subprogramul memorat poate fi ulterior apelat dintr-o aplicaŃie sau dintr-un alt<br />

bloc PL/SQL. Subprogramele pot fi proceduri sau funcŃii. DiferenŃa dintre cele<br />

două este faptul că o funcŃie returnează o valoare.<br />

Un pachet (engl. package) este format dintr-un un grup <strong>de</strong> subprograme<br />

şi <strong>de</strong> <strong>de</strong>claraŃii <strong>de</strong> variabile. Serverul Oracle memorează elementele conŃinute<br />

într-un pachet, acestea putând fi apelate din alte pachete sau subprograme.<br />

Sintaxa unui bloc PL/SQL<br />

Un bloc anonim PL/SQL se compune din secŃiuni şi are sintaxa<br />

următoare:


39<br />

Bloc anonim<br />

DECLARE<br />

<strong>de</strong>claratii <strong>de</strong> variabile<br />

BEGIN<br />

cod program<br />

EXCEPTION<br />

cod tratare exceptii<br />

END;<br />

Dacă blocul conŃine o procedură memorată în baza <strong>de</strong> <strong>date</strong>, sintaxa sa<br />

este următoarea:<br />

Subprogram memorat <strong>de</strong> tip procedură<br />

CREATE OR REPLACE PROCEDURE "nume"<br />

(lista_parametri)<br />

IS<br />

<strong>de</strong>claratii variabile<br />

BEGIN<br />

cod program<br />

EXCEPTION<br />

cod tratare exceptii<br />

END;<br />

SecŃiunea <strong>de</strong> <strong>de</strong>claraŃii (DECLARE în cazul blocului anonim) cuprin<strong>de</strong><br />

<strong>de</strong>claraŃii <strong>de</strong> variabile simple, variabile structurate, variabile tip cursor, funcŃii<br />

sau proceduri ajutătoare. Zona <strong>de</strong> <strong>de</strong>claraŃii este opŃională. Pentru funcŃii,<br />

proceduri şi triggere cuvântul DECLARE lipseşte, blocul <strong>de</strong> <strong>de</strong>claraŃii fiind implicit<br />

cuprins între linia <strong>de</strong> <strong>de</strong>clarare a funcŃiei sau a procedurii şi BEGIN.<br />

Blocul introdus prin EXCEPTION este opŃional şi realizează tratarea<br />

erorilor apărute în timpul execuŃiei codului programului.<br />

Caracterul ';' se foloseşte pentru a marca sfârşitul unei instrucŃiuni sau a<br />

unui bloc, dacă apare după END.<br />

Codul poate cuprin<strong>de</strong> blocuri interioare. Exemplu:<br />

DECLARE<br />

<strong>de</strong>claraŃii variable<br />

BEGIN<br />

-- cod program<br />

BEGIN<br />

codul blocului inclus<br />

EXCEPTION<br />

tratare exceptii<br />

END;<br />

-- cod program (continuare)<br />

END;


40<br />

Pentru transformarea exemplelor din următoarele subcapitole în exemple<br />

executabile, înaintea <strong>de</strong>claraŃiilor <strong>de</strong> variabile va fi introdus fie numele secŃiunii<br />

<strong>de</strong> <strong>date</strong>, DECLARE fie secvenŃa <strong>de</strong> <strong>de</strong>clarare a unei proceduri stocate (CREATE<br />

OR REPLACE PROCEDURE "nume" IS).<br />

Comentarii<br />

În PL/SQL comentariile în linie se introduc prin două caractere '-' iar<br />

comentariile pe mai multe linii sunt cuprinse între /* respectiv */, ca în limbajul<br />

C.<br />

Exemplu:<br />

Tipuri <strong>de</strong> <strong>date</strong> în PL/SQL<br />

Tipurile <strong>de</strong> <strong>date</strong> folosite în PL/SQL pot fi:<br />

4. cele folosite în SQL (VARCHAR2, NVARCHAR2, CHAR, NCHAR,<br />

NUMBER, BINARY_FLOAT, BINARY_DOUBLE, DATE, TIMESTAMP,<br />

CLOB şi BLOB),<br />

5. tipuri specifice limbajului PL/SQL : BOOLEAN, NUMBER (scris<br />

simplu, fără dimensiune) şi PLS_INTEGER (pentru variabile având<br />

valori întregi),


41<br />

6. tipuri specifice structurate: TABLE, VARRAY şi RECORD.<br />

Exemplu:<br />

-- Declaratii <strong>de</strong> variabile<br />

nume VARCHAR2(30);<br />

prenume VARCHAR2(25);<br />

marca NUMBER(6);<br />

activ BOOLEAN;<br />

salar_lunar NUMBER(6);<br />

nb_zile_lucrate NUMBER(2);<br />

salar_zilnic NUMBER(6,2);<br />

medie_zile_lucr CONSTANT NUMBER(2) := 21; -- o constanta<br />

BEGIN<br />

NULL; -- NULL indica lipsa corpului. Este permisa pt. testare.<br />

END;<br />

/<br />

Obs. Pentru a <strong>de</strong>fini constanta medie_zile_lucr s-a folosit cuvântul<br />

rezervat CONSTANT şi imediat s-a atribuit valoarea corespunzătoare.<br />

Variabilele <strong>de</strong>clarate servesc <strong>de</strong> multe ori la memorarea unor valori din<br />

tabelele bazei <strong>de</strong> <strong>date</strong>, obŃinute folosind comenzi SELECT. În astfel <strong>de</strong> cazuri<br />

este esenŃial ca tipul <strong>de</strong>clarat pentru o astfel <strong>de</strong> variabilă să coincidă cu tipul<br />

coloanei tabelului din care va primi valori. Pentru a evita erorile greu <strong>de</strong> <strong>de</strong>pistat<br />

cauzate <strong>de</strong> <strong>de</strong>clararea eronată a acestor variabile, PL/SQL oferă soluŃia simplă a<br />

preluării tipului câmpului care va furniza valori folosind %TYPE, astfel:<br />

co<strong>de</strong>d edituri.cod_edit%TYPE;<br />

Variabila co<strong>de</strong>d va fi NUMBER(5), <strong>de</strong> acelaşi tip cu câmpul cod_edit din<br />

tabelul edituri.<br />

O situaŃe asemănătoare apare în cazul variabilelor structurate (<strong>de</strong> tipul<br />

RECORD). O astfel <strong>de</strong> variabilă va avea mai multe câmpuri. Dacă variabila<br />

trebuie să preia valorile conŃinute într-o linie a unui tabel, la <strong>de</strong>clararea ei se va<br />

folosi %ROWTYPE, astfel:<br />

editura edituri%ROWTYPE;<br />

Variabila editura va fi <strong>de</strong> tip RECORD şi va avea aceleaşi câmpuri cu<br />

tabelul edituri. Accesul la câmpuri se realizează folosind operatorul '.' (punct).<br />

Exemplu: editura.cod_edit, editura.nume etc.


42<br />

Cursoare<br />

Cursoarele permit programatorului să preia <strong>date</strong> dintr-o mulŃime <strong>de</strong><br />

selecŃie, linie cu linie, în ve<strong>de</strong>rea prelucrării lor. În PL/SQL un cursor poate fi<br />

implicit sau explicit.<br />

Cursorul implicit presupune utilizarea unei mulŃimi <strong>de</strong> selecŃie având o<br />

singură linie şi este folosit pentru a atribui valori unui set <strong>de</strong> variabile.<br />

Exemplu:<br />

SELECT cont, data, valoare into cnt, dt, val from operatii where cod_op = 3;<br />

În ve<strong>de</strong>rea selectării unei singure linii se impune valoarea cheii primare.<br />

Cursorul explicit are nume şi este <strong>de</strong>clarat în secŃiunea <strong>de</strong> <strong>de</strong>claraŃii a<br />

blocului (procedurii, funcŃiei), astfel:<br />

CURSOR c1 IS SELECT ... ;<br />

Exemplu:<br />

CURSOR c1 IS SELECT nume, prenume FROM angajati WHERE functia = 'zidar';<br />

Comanda SQL SELECT va fi executată în momentul <strong>de</strong>schi<strong>de</strong>rii cursorului<br />

folosind instrucŃiunea OPEN. Liniile mulŃimii <strong>de</strong> selecŃie conŃinute în cursor vor fi<br />

prelucrate individual, accesul la linia curentă realizându-se folosind instrucŃiunea<br />

FETCH.<br />

După terminarea prelucrării <strong>date</strong>lor conŃinute într-un cursor, acesta<br />

trebuie închis folosind instrucŃiunea CLOSE.<br />

Câteva exemple privind folosirea cursoarelor vor fi înserate după<br />

prezentarea instrucŃiunilor repetitive.<br />

I<strong>de</strong>ntificatori<br />

Numele unei variabile constă dintr-un şir având maximum 30 caractere şi<br />

format dintr-o literă urmată opŃional <strong>de</strong> alte litere, cifre, $, _. Caracterele '&', '-',<br />

'/' şi ' ' (spaŃiu) nu sunt permise. PL/SQL nu este sensibil la tipul literelor -<br />

majuscule sau litere mici.<br />

Exemple:<br />

-- Declaratii <strong>de</strong> variabile<br />

numeprenume VARCHAR2(30); -- i<strong>de</strong>ntificator acceptat


43<br />

nume_prenume VARCHAR2(30); -- i<strong>de</strong>ntificator acceptat, _ permis<br />

nume$prenume VARCHAR2(30); -- i<strong>de</strong>ntificator acceptat, $ permis<br />

nume#prenume VARCHAR2(30); -- i<strong>de</strong>ntificator acceptat, # permis<br />

-- nume-prenume i<strong>de</strong>ntificator neacceptat, minus nepermis<br />

-- nume/prenume i<strong>de</strong>ntificator neacceptat, / nepermis<br />

-- nume prenume i<strong>de</strong>ntificator neacceptat, spatiu nepermis<br />

-- NUMEPRENUME i<strong>de</strong>ntif. neacceptat, acelasi cu numeprenume si<br />

NumePrenume<br />

-- NumePrenume i<strong>de</strong>ntif. neacceptat, acelasi cu numeprenume si<br />

NUMEPRENUME<br />

BEGIN<br />

NULL;<br />

END;<br />

/<br />

Operatori<br />

La scrierea codului în PL/SQL se folosesc următoarele tipuri <strong>de</strong> operatori:<br />

e. aritmetici: + - * /<br />

f. logici : '=' '>' '=' '


44<br />

END;<br />

/<br />

Literali<br />

Exemple:<br />

-- Declaratii <strong>de</strong> variabile<br />

number1 PLS_INTEGER := 32000; -- literal numeric, val întreagă<br />

number2 NUMBER(8,3);<br />

BEGIN<br />

number2 := 3.125346e3; -- literal numeric<br />

number2 := -8300.00; -- literal numeric<br />

number2 := -14; -- literal numeric<br />

END;<br />

char1 VARCHAR2(1) := 'x'; -- literal caracter<br />

char2 VARCHAR2(1);<br />

BEGIN<br />

char2 := '5'; -- literal caracter<br />

END;<br />

/<br />

-- Declaratii <strong>de</strong> variabile<br />

string1 VARCHAR2(1000);<br />

string2 VARCHAR2(32767);<br />

BEGIN<br />

string1 := '555-111-2323';<br />

-- daca un sir contine apostrof, acesta se dubleaza<br />

string2 := 'Here''s an example of two single quotation marks.';<br />

END;<br />

/<br />

-- Declaratii <strong>de</strong> variabile<br />

gata BOOLEAN := TRUE; -- BOOLEAN literal<br />

complet BOOLEAN;<br />

true_or_false BOOLEAN;<br />

BEGIN<br />

gata := FALSE; -- literal BOOLEAN


45<br />

complet := NULL; -- literal BOOLEAN (valoare ne<strong>de</strong>finita)<br />

true_or_false := (3 = 4);<br />

true_or_false := (3 < 4);<br />

END;<br />

/<br />

-- Declaratii <strong>de</strong> variabile<br />

<strong>date</strong>1 DATE := '11-AUG-2005'; -- literal DATE<br />

time1 TIMESTAMP;<br />

BEGIN<br />

time1 := '11-AUG-2005 11:01:01 PM'; -- literal TIMESTAMP<br />

END;<br />

/<br />

Atribuirea folosind SELECT ... INTO<br />

Dacă valoarea unei variabile se <strong>de</strong>termină în funcŃie <strong>de</strong> valori dintr-o linie<br />

a unui tabel al bazei <strong>de</strong> <strong>date</strong>, PL/SQL permite atribuirea valorii acesteia folosind<br />

un cursor implicit, respectiv o construcŃie<br />

SELECT expresie INTO variabilă FROM tabel WHERE<br />

condiŃie_selectare_linie<br />

Expresia folosită poate folosi variabile, literali şi valori din linia<br />

corespunzătoare din tabel.<br />

Exemplu:<br />

-- Declaratii <strong>de</strong> variabile<br />

procent_bonus CONSTANT NUMBER(2,3) := 0.05;<br />

bonus NUMBER(8,2);<br />

ang_id NUMBER(6) := 120; -- atribuie o val. pt testare<br />

BEGIN<br />

-- preia salar din tabelul angajati, calculeaza bonusul şi atribuie<br />

-- rezultatul -> variabila bonus<br />

SELECT salar * procent_bonus INTO bonus FROM angajati<br />

WHERE angajat_id = ang_id;<br />

-- listeaza codul angajat_id, bonusul si procent_bonus<br />

DBMS_OUTPUT.PUT_LINE ( 'Angajat: ' || TO_CHAR(ang_id)<br />

|| ' Bonus: ' || TO_CHAR(bonus) || ' Procent bonus: ' ||<br />

TO_CHAR(procent_bonus*100));


46<br />

END;<br />

/<br />

În aceeaşi frază SELECT pot fi atribuite valori mai multor variabile.<br />

Exemplu:<br />

SELECT Nume, Prenume, salar*procent_bonus INTO m_nume, m_prenume,<br />

m_salar<br />

FROM angajati WHERE angajat_id = ang_id;<br />

FuncŃii uzuale<br />

PL/SQL cuprin<strong>de</strong> un număr mare <strong>de</strong> funcŃii. În tabelul <strong>de</strong> mai jos sunt<br />

incluse cele mai <strong>de</strong>s folosite.<br />

FuncŃia<br />

FuncŃii pentru prelucrarea şirurilor<br />

upper(s), lower(s)<br />

ltrim(s), rtrim(s)<br />

Descriere<br />

converteşte s în majuscule/minuscule<br />

înlătura spaŃiile <strong>de</strong> la stânga / dreapta<br />

substr(s, start, lungime)<br />

length(s)<br />

FuncŃii pentru prelucrarea <strong>date</strong>i calendaristice<br />

sys<strong>date</strong><br />

to_<strong>date</strong>(data, format)<br />

to_char(data, format)<br />

FuncŃii pentru <strong>date</strong> numerice<br />

round(x)<br />

mod(n, p)<br />

abs(x)<br />

power(x,n)<br />

dbms_random.random()<br />

Conversii <strong>de</strong> tip<br />

to_char(n)<br />

to_number(s)<br />

Alte funcŃii<br />

user<br />

returnează un subşir <strong>de</strong>finit prin poz. start şi lungime<br />

returnează lungimea şirului <strong>de</strong> caractere s<br />

data din sistem<br />

returneaza o dată formatată conform formatului<br />

Ex. : to_<strong>date</strong>('31-12-2007', 'dd-mm-yyyy')<br />

Converteşte o dată calendaristică în şir, conform<br />

formatului format. Exemplu:<br />

to_<strong>date</strong>(d, 'dd-mm-yyyy')<br />

rotunjeşte x<br />

returnează restul împărŃirii întregi n/p<br />

returnează val. absolută<br />

returnează x n<br />

generează un număr aleator întreg<br />

converteşte n în şir <strong>de</strong> caractere<br />

converteşte şirul s în număr<br />

returnează numele utilizatorului serverului Oracle


47<br />

InstrucŃiuni<br />

SecvenŃele <strong>de</strong> cod scrise în PL/SQL pot conŃine comenzi SQL (CREATE,<br />

INSERT, DELETE, DROP sau ALTER).<br />

Exemplu:<br />

Insert into <strong>de</strong>ponent values (124, 'Ionescu Valer', 'Str. Crinilor Nr. 7, Craiova',<br />

'0743123989');<br />

Pe lângă comenzile SQL sau atribuirile <strong>de</strong> valori limbajul PL/SQL dispune<br />

<strong>de</strong> un set complet <strong>de</strong> instrucŃiuni necesare controlului execuŃiei programului, ca<br />

oricare limbaj procedural.<br />

InstrucŃiunea <strong>de</strong> <strong>de</strong>ci<strong>de</strong>re - IF<br />

În limbajul PL/SQL instrucŃiunea IF poate prezenta trei forme.<br />

a. IF-THEN<br />

Exemplu:<br />

BEGIN<br />

END;<br />

/<br />

-- Declaratii <strong>de</strong> variabile<br />

vanzari NUMBER(8,2) := 10100;<br />

cota NUMBER(8,2) := 10000;<br />

bonus NUMBER(6,2);<br />

ang_id NUMBER(6) := 120;<br />

IF vanzari > (cota + 200) THEN<br />

END IF;<br />

bonus := (vanzari - cota)/4;<br />

UPDATE angajati SET salar = salar + bonus WHERE<br />

angajat_id = ang_id;<br />

Astfel scris IF serveşte la condiŃionarea unei acŃiuni. AcŃiunea este<br />

<strong>de</strong>clanşată dacă expresia logică are valoarea a<strong>de</strong>vărat. SecvenŃa <strong>de</strong> cod care<br />

<strong>de</strong>scrie acŃiunea este plasată între THEN şi END IF.


48<br />

b. IF-THEN-ELSE<br />

Exemplu:<br />

BEGIN<br />

END;<br />

/<br />

-- Declaratii <strong>de</strong> variabile<br />

vanzari NUMBER(8,2) := 12100;<br />

cota NUMBER(8,2) := 10000;<br />

bonus NUMBER(6,2);<br />

ang_id NUMBER(6) := 120;<br />

IF vanzari > (cota + 200) THEN<br />

ELSE<br />

END IF;<br />

bonus := (vanzari - cota)/4;<br />

bonus := 50;<br />

UPDATE angajati SET salar = salar + bonus WHERE<br />

angajat_id = ang_id;<br />

În secvenŃa anterioară prezenŃa clauzei ELSE permite <strong>de</strong>finirea a două<br />

blocuri <strong>de</strong> instrucŃiuni, unul cuprins între THEN şi ELSE şi al doilea cuprins între<br />

ELSE şi END IF. În funcŃie <strong>de</strong> valoarea <strong>de</strong> a<strong>de</strong>văr a expresiei logice va fi executat<br />

primul bloc sau al doilea.<br />

c. IF-THEN-ELSIF<br />

Uneori este necesară alegerea unei secvenŃe <strong>de</strong> cod din mai multe,<br />

fiecare fiind condiŃionată <strong>de</strong> câte o expresie logică. În acest caz se recomandă<br />

folosirea structurii IF-THEN-ELSIF.<br />

Exemplu:<br />

-- Declaratii <strong>de</strong> variabile<br />

vanzari NUMBER(8,2) := 20000;<br />

bonus NUMBER(6,2);<br />

ang_id NUMBER(6) := 120;<br />

BEGIN<br />

IF vanzari > 50000 THEN<br />

bonus := 1500;<br />

ELSIF vanzari > 35000 THEN<br />

bonus := 500;<br />

ELSE


49<br />

bonus := 100;<br />

END IF;<br />

UPDATE angajati SET salar = salar + bonus WHERE<br />

angajat_id = ang_id;<br />

END;<br />

/<br />

InstrucŃiunea CASE<br />

InstrucŃiunea CASE permite impunerea blocului care va fi executat în<br />

funcŃie <strong>de</strong> valoarea unei expresii. De cele mai multe ori expresia se reduce la o<br />

variabilă.<br />

Exemplu:<br />

BEGIN<br />

END;<br />

/<br />

-- Declaratii <strong>de</strong> variabile<br />

gra<strong>de</strong> CHAR(1);<br />

nivel := 'B';<br />

CASE nivel<br />

END CASE;<br />

WHEN 'A' THEN DBMS_OUTPUT.PUT_LINE('Excelent');<br />

WHEN 'B' THEN DBMS_OUTPUT.PUT_LINE('Foarte bun');<br />

WHEN 'C' THEN DBMS_OUTPUT.PUT_LINE('Bun');<br />

WHEN 'D' THEN DBMS_OUTPUT.PUT_LINE('Corect');<br />

WHEN 'F' THEN DBMS_OUTPUT.PUT_LINE('Slab');<br />

ELSE DBMS_OUTPUT.PUT_LINE('Nu ma pot pronunta');<br />

În exemplul prezentat valoarea variabilei nivel condiŃionează blocul care<br />

va fi executat. Valorile posibile sunt introduse prin clauze WHEN iar blocul <strong>de</strong><br />

instrucŃiuni care trebuie executat se scrie după THEN. Dacă valoarea variabilei<br />

nivel nu se regăseşte printre valorile introduse prin WHEN, se va executa blocul<br />

introdus prin clauza ELSE, plasată ultima. InstrucŃiunea se încheie cu END CASE.<br />

InstrucŃiuni <strong>de</strong> ciclare<br />

În limbajul PL/SQL există trei instrucŃiuni <strong>de</strong> coclare: LOOP, WHILE-LOOP<br />

şi FOR-LOOP.


50<br />

a. LOOP<br />

Un bloc LOOP - END LOOP permite <strong>de</strong>finirea unui ciclu din care se iese<br />

prin executarea unei instrucŃiuni EXIT. InstrucŃiunea EXIT este <strong>de</strong> regulă plasată<br />

într-un IF a cărui condiŃie trebuie să ajungă să fie satisfăcută pentru a se evita<br />

rularea blocului LOOP în ciclu infinit.<br />

Exemplu:<br />

credit_rating NUMBER := 0;<br />

BEGIN<br />

LOOP<br />

credit_rating := credit_rating + 1;<br />

IF credit_rating > 3 THEN<br />

EXIT; -- iesire imediata din loop<br />

END IF;<br />

END LOOP;<br />

-- dupa EXIT, executia se continuă <strong>de</strong> aici<br />

DBMS_OUTPUT.PUT_LINE ('Credit rating: ' || TO_CHAR(credit_rating));<br />

IF credit_rating > 3 THEN<br />

RETURN; -- în afara blocului LOOP se foloseşte RETURN, nu EXIT<br />

END IF;<br />

DBMS_OUTPUT.PUT_LINE ('Credit rating: ' || TO_CHAR(credit_rating));<br />

END;<br />

/<br />

Dacă ieşirea din ciclu se poate realiza printr-un simplu IF, se poate înlocui<br />

IF prin instrucŃiunea EXIT WHEN conditie_iesire.<br />

Exemplu:<br />

Exemplu:<br />

LOOP<br />

END LOOP;<br />

IF count > 100 THEN EXIT; ENDIF;<br />

EXIT WHEN count > 100;<br />

credit_rating := credit_rating + 1;<br />

EXIT WHEN credit_rating > 3


51<br />

b. WHILE - LOOP<br />

În PL/SQL pentru realizarea unei structuri repetitive condiŃionate anterior<br />

se utilizează instrucŃiunea WHILE - LOOP. Sintaxa unei astfel <strong>de</strong> structuri<br />

repetitive este următoarea:<br />

WHILE condiŃie LOOP<br />

END LOOP<br />

bloc <strong>de</strong> instrucŃiuni<br />

c. FOR - LOOP<br />

Ca şi în alte limbaje, parcurgerea unui şir <strong>de</strong> valori se realizează folosind<br />

o instrucŃiune FOR - LOOP. Exemplu <strong>de</strong> utilizare:<br />

-- Declaratii <strong>de</strong> variabile<br />

p NUMBER := 0;<br />

BEGIN<br />

FOR k IN 1..500 LOOP -- calcul pi ca suma a 500 termeni<br />

p := p + ( ( (-1) ** (k + 1) ) / ((2 * k) - 1) );<br />

END LOOP;<br />

p := 4 * p;<br />

DBMS_OUTPUT.PUT_LINE( 'pi este aproximativ : ' || p );<br />

END;<br />

/<br />

În exemplul dat variabila i va lua valori în intervalul <strong>de</strong> valori întregi<br />

introdus prin IN. Valorile sunt <strong>de</strong> regulă consecutive şi crescătoare. Dacă şirul<br />

valorilor introduse prin IN trebuie parcurs în ordine inversă se va folosi clauza<br />

REVERSE, ca în exemplul următor:<br />

BEGIN<br />

END;<br />

/<br />

FOR i IN REVERSE 1..5 LOOP<br />

END LOOP;<br />

DBMS_OUTPUT.PUT_LINE (TO_CHAR(i));<br />

Se interzice modificarea variabilei folosite la controlul ciclului în interiorul<br />

acestuia.<br />

Un exemplu tipic <strong>de</strong> utilizare a ciclului FOR în domeniul <strong>bazelor</strong> <strong>de</strong> <strong>date</strong><br />

este cel în care se actualizează într-un ciclu înregistrările dintr-un tabel.<br />

Exemple:


52<br />

-- Declaratii <strong>de</strong> variabile<br />

CURSOR ang_cursor IS SELECT * FROM angajati;<br />

REC angajati%ROWTYPE; -- var. structurata <strong>de</strong> tip record<br />

BEGIN<br />

FOR REC IN ang_cursor LOOP<br />

UPDATE angajati<br />

SET salar = ...<br />

WHERE ang_id = REC.ang_id;<br />

END LOOP;<br />

END;<br />

/<br />

CREATE OR REPLACE PROCEDURE Afisez<br />

AS<br />

CURSOR c1 IS SELECT * FROM edituri or<strong>de</strong>r by nume;<br />

REC edituri%ROWTYPE; -- var. structurata <strong>de</strong> tip record<br />

BEGIN<br />

FOR REC IN c1 LOOP<br />

DBMS_OUTPUT.PUT_LINE (rec.nume);<br />

END LOOP;<br />

END;<br />

/<br />

BEGIN<br />

OPEN c2;<br />

LOOP<br />

FETCH c2 INTO REC;<br />

-- preia linia curenta in REC<br />

EXIT WHEN c2%NOTFOUND;<br />

DBMS_OUTPUT.PUT_LINE( RPAD(REC.prenume, 25, ' ') ||<br />

REC.id_meserie );<br />

END LOOP;<br />

CLOSE c2;<br />

Notă FuncŃia RPAD() construieşte un şir <strong>de</strong> caractere având lungimea<br />

dată <strong>de</strong> al doilea argument. Şirul se obŃine prin completarea la dreapta a şirului<br />

dat ca prim argument cu şirul dat ca al treilea argument.<br />

În exemplul următor cursorul c1 conŃine doar două valori din tabelul<br />

angajaŃi. InstrucŃiunea FETCH va prelua cele două valori în două variabile locale.


53<br />

jobid angajati.job_id%TYPE; -- variabila pentru id_functie<br />

pren angajati.prenume%TYPE; -- variabila pentru prenume<br />

CURSOR c1 IS SELECT prenume, id_functie FROM angajati<br />

WHERE id_functie LIKE '%ZIDAR';<br />

BEGIN<br />

OPEN c1; -- <strong>de</strong>schid cursorul - execut select<br />

LOOP<br />

FETCH c1 INTO pren, jobid; -- preiau 2 coloane in variabile<br />

EXIT WHEN c1%NOTFOUND;<br />

DBMS_OUTPUT.PUT_LINE( RPAD(pren, 25, ' ') || jobid );<br />

END LOOP;<br />

CLOSE c1;<br />

Definirea unei proceduri<br />

De regulă secvenŃele <strong>de</strong> cod PL/SQL sunt conŃinute în proceduri sau<br />

funcŃii. Blocurile anonime pot fi folosite eventual pentru testarea corectitudinii<br />

unei secvenŃe <strong>de</strong> cod, dar după încheierea testării ele vor fi transformate în<br />

proceduri sau funcŃii memorate în baza <strong>de</strong> <strong>date</strong>.<br />

Codul poate fi scris în fereastra <strong>de</strong>stinată scrierii comenzilor SQL (SQL<br />

Command), în Script Editor sau folosind Object Browser / Create / Procedure.<br />

Indiferent <strong>de</strong> soluŃia adoptată, rezultatul va fi o procedură stocată în Oracle XE şi<br />

accesibilă folosind meniul Object Browser.<br />

Exemplul 1. Crearea unei proceduri folosind SQL Command:


54<br />

Declararea unei proceduri folosind fereastra SQL Command sau SQL*Plus<br />

începe cu secvenŃa :<br />

CREATE OR REPLACE PROCEDURE nume ...<br />

Pentru verificarea creării procedurii se selectează Object Browser /<br />

Browse / Procedures şi în fereastra care se afişează se selectează procedura<br />

(SALUT).<br />

Exemplul 2. Crearea unei proceduri folosind Object Browser / Create /<br />

Procedure:<br />

Exemplu:


55<br />

În pasul următor se <strong>de</strong>finesc parametrii <strong>de</strong> intrare şi <strong>de</strong> ieşire ai<br />

procedurii, dacă este cazul.<br />

În continuare se introduce corpul procedurii:<br />

Rezultat:


56<br />

Astfel generată, procedurii îi lipseşte secŃiunea <strong>de</strong>stinată <strong>de</strong>clarării<br />

variabilelor locale. Pentru adăugarea acestora se selectează Edit şi se inserează<br />

<strong>de</strong>claraŃiile necesare.<br />

Apelul procedurii se poate realiza din fereastra <strong>de</strong>stinată introducerii <strong>de</strong><br />

comenzi SQL (SQL / SQL Commands) :<br />

Din SQL*Plus apelul se poate face şi folosind comanda SQL CALL :<br />

Parametrii procedurilor PL/SQL<br />

Procedurile pot avea un număr <strong>de</strong> parametri <strong>de</strong> intrare (IN), parametri <strong>de</strong><br />

ieşire (OUT) sau <strong>de</strong> intrare / ieşire (IN OUT).<br />

Exemple:<br />

PROCEDURE maj ( v1 IN VARCHAR2, v2 IN VARCHAR2) IS ...<br />

PROCEDURE majusc ( v1 IN VARCHAR2, v2 OUT VARCHAR2) IS ...<br />

PROCEDURE majuscule ( v1 IN VARCHAR2, v2 IN OUT VARCHAR2) AS ...<br />

Dacă un parametru este <strong>de</strong>clarat <strong>de</strong> intrare (IN) modificarea sa în<br />

subprogram nu afectează valoarea eventualei variabile folosite ca parametru<br />

efectiv la apelarea funcŃiei.


57<br />

La apelul unei proceduri având parametri <strong>de</strong> tip OUT sau IN OUT, pe<br />

poziŃiile corespunzătoare acestora din lista <strong>de</strong> parametri efectivi trebuie utilizate<br />

variabile <strong>de</strong> acelaşi tip cu cel al parametrilor procedurii.<br />

Un bloc anonim sau o procedură poate avea în zona <strong>de</strong> <strong>de</strong>claraŃii o<br />

<strong>de</strong>claraŃie <strong>de</strong> procedură. Exemplu :<br />

DECLARE -- <strong>de</strong>claratii <strong>de</strong> variabile si subprograme<br />

nume VARCHAR2(20) := 'ionescu';<br />

prenume VARCHAR2(25) := 'marin';<br />

PROCEDURE nume_maj ( v1 IN OUT VARCHAR2, v2 IN OUT VARCHAR2) AS<br />

BEGIN<br />

v1 := UPPER(v1); -- trec sirurile in majuscule<br />

v2 := UPPER(v2);<br />

END;<br />

BEGIN<br />

DBMS_OUTPUT.PUT_LINE(nume || ' ' || prenume ); -- afisez val. initiale<br />

nume_maj (nume, prenume); -- apelez procedura cu parameteri<br />

DBMS_OUTPUT.PUT_LINE(nume || ' ' || prenume ); -- afisez noile valori<br />

END;<br />

/<br />

Deoarece procedura nume_maj este cuprinsă într-un bloc anonim,<br />

executarea blocului nu va <strong>de</strong>termina memorarea acesteia în baza <strong>de</strong> <strong>date</strong>.<br />

Definirea unei funcŃii<br />

FuncŃiile sunt subprograme care returnează o valoare. Ca şi în cazul<br />

procedurilor, o funcŃie poate fi scrisă în fereastra <strong>de</strong>stinată scrierii comenzilor<br />

SQL (SQL Command), în Script Editor sau folosind interfaŃa afişată prin<br />

selectarea opŃiunii Object Browser / Create / Function. Exemplu:


58<br />

FuncŃia salar poate fi apelată în mai multe moduri, cel mai simplu fiind în<br />

fraze select:<br />

a.<br />

b.<br />

Ca şi procedura, o funcŃie poate avea parametri <strong>de</strong> intrare. Lista<br />

acestora este<br />

CREATE OR REPLACE FUNCTION nume_prenume ( nume IN VARCHAR2,<br />

prenume IN VARCHAR2, casatorit IN VARCHAR2)<br />

RETURN VARCHAR2 AS<br />

nup VARCHAR2(45); -- variabila locala<br />

BEGIN<br />

-- Se construieste un sir cuprinzand numele si prenumele<br />

nup := upper(nume) || ' ' || prenume;<br />

if length(casatorit) > 0 THEN -- daca e casatorit, adaug casatorit<br />

nup := nup || ' ' || casatorit;<br />

END IF;<br />

RETURN nup; -- returneaza valoarea lui nup<br />

END;<br />

/<br />

Laborator nr. 5


59<br />

Laborator nr. 4<br />

RelaŃii între tabele. Comenzi SQL care selectează <strong>date</strong> din mai multe tabele<br />

1. PorniŃi aplicaŃia – Start -> Programs -> Oracle Database 10g Express Edition -> Go To<br />

Database<br />

Home Page sau scrieŃi adresa http://127.0.0.1:8080/apex/ în browser-ul dv.<br />

2. CreaŃi un utilizator nou, caine, cu parola caine<br />

3. CreaŃi o bază <strong>de</strong> <strong>date</strong> pentru evi<strong>de</strong>nŃa câinilor <strong>de</strong> rasă din diferite Ńări.<br />

Pentru aceasta creaŃi următoarele tabele<br />

TARI<br />

TALIE<br />

SCOP<br />

CAINE<br />

4. Se cere:<br />

cod_tara - cheie primară (număr)<br />

tara – tara <strong>de</strong> origine (caracter)<br />

cod_talie - cheie primară (număr)<br />

talie – marimea cainelui (caracter)<br />

cods - cheie primară (număr)<br />

scop - caracter<br />

cod_caine - cheie primară (număr)<br />

cod_tara – tara <strong>de</strong> origine (numar)<br />

cod_talie – talia cainelui (număr)<br />

rasa – rasa cainelui (caracter)<br />

cods – scopul folosirii cainelui (număr)<br />

• Să se adauge 10 Ńări, 5 talii, 6 scopuri şi 14 câini<br />

<strong>de</strong> diferite talii;<br />

TARI


60<br />

TALIE<br />

SCOP<br />

CAINE<br />

Folosind editorul <strong>de</strong> interogări (Query Buil<strong>de</strong>r) şi salvând interogările sub forma<br />

lab04_interogare1:<br />

• Să se afişeze toŃi câinii din toate Ńările:<br />

Fraza SQL corespunzătoare:<br />

select "CAINE"."RASA" as "RASA",<br />

"TARI"."TARA" as "TARA"<br />

from "TARI" "TARI",<br />

"CAINE" "CAINE"<br />

where "CAINE"."COD_TARA" =tari.cod_tara<br />

or<strong>de</strong>r by CAINE.RASA ASC


61<br />

• Să se afişeze toŃi câinii dintr-o Ńară (<strong>de</strong> ex. Germania), indiferent <strong>de</strong> rasă.<br />

select "CAINE"."RASA" as "RASA",<br />

"TARI"."TARA" as "TARA"<br />

from "TARI" "TARI",<br />

"CAINE" "CAINE"<br />

where "TARI"."TARA" ='Germania'<br />

and "CAINE"."COD_TARA" =tari.cod_tara<br />

rezultatul:<br />

• Să se afişeze toŃi câinii <strong>de</strong> talie medie dintr-o Ńară.<br />

select "CAINE"."RASA" as "RASA",<br />

"TARI"."TARA" as "TARA",<br />

"TALIE"."TALIE" as "TALIE"<br />

from "CAINE" "CAINE",<br />

"TALIE" "TALIE",<br />

"TARI" "TARI"<br />

where "TARI"."TARA" ='Germania'<br />

and "TALIE"."TALIE" ='medie'<br />

and "CAINE"."COD_TALIE" =talie.cod_talie<br />

and "CAINE"."COD_TARA" =TARI.COD_TARA<br />

or<strong>de</strong>r by CAINE.RASA ASC<br />

rezultatul:<br />

• Să se afişeze toŃi câinii utilitari, indiferent <strong>de</strong> Ńară sau talie.<br />

select<br />

from<br />

"CAINE"."RASA" as "RASA",<br />

"SCOP"."SCOP" as "SCOP",<br />

"TALIE"."TALIE" as "TALIE",<br />

"TARI"."TARA" as "TARA"<br />

"TARI" "TARI",<br />

"TALIE" "TALIE",


62<br />

"SCOP" "SCOP",<br />

"CAINE" "CAINE"<br />

where "CAINE"."CODS" =scop.cods<br />

and "SCOP"."CODS" =1<br />

and<br />

and<br />

"CAINE"."COD_TALIE" =talie.cod_talie<br />

"CAINE"."COD_TARA" =tari.cod_tara<br />

rezultat:<br />

• Să se afişeze câinii <strong>de</strong> companie <strong>de</strong> talie mică din FranŃa<br />

select "CAINE"."RASA" as "RASA",<br />

"TARI"."TARA" as "TARA",<br />

"TALIE"."TALIE" as "TALIE",<br />

"SCOP"."SCOP" as "SCOP"<br />

from "SCOP" "SCOP",<br />

"TALIE" "TALIE",<br />

"TARI" "TARI",<br />

"CAINE" "CAINE"<br />

where "TARI"."TARA" ='Franta'<br />

and "CAINE"."COD_TARA" =tari.cod_tara<br />

and "CAINE"."COD_TALIE" =1<br />

and "TALIE"."COD_TALIE" =caine.cod_talie<br />

and "SCOP"."SCOP" ='<strong>de</strong> companie'<br />

and "CAINE"."CODS" =scop.cods<br />

rezultat :<br />

5. CreaŃi câteva ve<strong>de</strong>ri (View):<br />

• afişaŃi câinii <strong>de</strong> talie mică, indiferent <strong>de</strong> scop şi Ńară<br />

Pentru asta alegeŃi succesiv Object Browser, Create, View


63<br />

?!?!……?!?!<br />

fraza SQL<br />

select "CAINE"."RASA" as "RASA",<br />

"TALIE"."TALIE" as "TALIE"<br />

from "TALIE" "TALIE",<br />

"CAINE" "CAINE"<br />

where "CAINE"."COD_TALIE" =1<br />

and "TALIE"."COD_TALIE" =caine.cod_talie<br />

rezultat :


64<br />

6. ScrieŃi o comandă SQL care să selecteze toŃi cânii dintr-o Ńară, indiferent <strong>de</strong> talie<br />

(numerotarea înregistrărilor se poate face apelând funcŃia rownum:<br />

select rownum, rasa, tara, talie from CAINe, tari, talie where caine.cod_tara = tari.cod_tara<br />

and caine.cod_talie = talie.cod_talie and tari.tara='Germania'<br />

rezultat :


65<br />

RelaŃii între tabele. Comenzi SQL.<br />

Laborator nr. 5<br />

1. PorniŃi aplicaŃia – Start -> Programs -> Oracle Database 10g Express Edition -> Go To<br />

Database<br />

Home Page sau scrieŃi adresa http://127.0.0.1:8080/apex/ în browser-ul dv.<br />

2. CreaŃi un utilizator nou, banca, cu parola banca<br />

3. CreaŃi o bază <strong>de</strong> <strong>date</strong> pentru gestionarea unor informaŃii dintr-o bancă.<br />

Pentru asta creaŃi următoarele tabele<br />

Obs.<br />

DEPONENT<br />

cod_<strong>de</strong>p - cheie primară (number - 6,0)<br />

nume – numele şi prenumele <strong>de</strong>ponentului (varchar2 - 60)<br />

adresa – adresa <strong>de</strong>ponentului (varchar2 - 100)<br />

telefon – numărul <strong>de</strong> telefon al <strong>de</strong>ponentului (number - 10)<br />

CONTURI<br />

cont – numărul contului (number - 6,0 – cheie primară)<br />

cod_<strong>de</strong>p – codul <strong>de</strong>ponentului (number - 6,0 – cheie străină)<br />

OPERAT<strong>II</strong><br />

cod_op – codul operaŃiunii (cheie primară – number - 4)<br />

cont – numărul contului (number - 6,0, cheie străină )<br />

data – data în care se efectuează operaŃiunea (dată)<br />

valoare – valoarea operaŃiunii, valoare pozitivă pentru <strong>de</strong>punere şi valoare negativă<br />

pentru retragere (număr)<br />

Un <strong>de</strong>ponent poate avea mai multe conturi;<br />

Pentru un cont pot exista mai multe operaŃii în tabelul <strong>de</strong> operaŃii<br />

Depunerile vor fi pozitive (operatii.valoare >0) iar retragerile negative<br />

(operatii.valoare < 0)<br />

4. Se cere:<br />

• Să se adauge 5 clienŃi (<strong>de</strong>ponenŃi), 7 conturi şi 11 operaŃii pentru diferite conturi;


66<br />

DEPONENT<br />

CONTURI<br />

OPERAT<strong>II</strong><br />

5. CreaŃi câteva ve<strong>de</strong>ri (View) – folosind Query Buil<strong>de</strong>r:


67<br />

• Să se afişeze , în ordine alfabetică, toŃi clienŃii băncii<br />

După alegerea opŃiunii<br />

rezultatul este<br />

Dacă după compilare răspunsul este No Error, rezultatul va fi<br />

• Să se afişeze toate operaŃiunile bancare în<br />

ordine crescătoare a <strong>date</strong>i


68<br />

• Să se afişeze toate operaŃiunile bancare efectuate într-o zi<br />

• Să se afişeze conturile unui <strong>de</strong>ponent:<br />

Obs. AdăugaŃi legăturile persistente în fereastrta Query buil<strong>de</strong>r-ului<br />

• Să se afişeze toate operaŃiunile efectuate <strong>de</strong> un <strong>de</strong>ponent într-un cont;


69<br />

• Să se afişeze toate conturile unui <strong>de</strong>ponent precum şi suma totală pe care acesta o<br />

are în fiecare dintre conturi;


70<br />

• Să se afişeze toate retragerile efectuate în perioada 01-02-2007 – 31-03-2007;

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!