Sunteți pe pagina 1din 97

SGBD

Laborator 1
ORACLE SQL
Vom folosi la laborator mediul de lucru Oracle, aplicatia Oracle Application Express 4.2.
In mediul oferit de Oracle Application Express, scriem interogari in SQL Workshop.

In exercitii vom folosi o baza de date model oferita de Oracle:

Exercitii 1.
1. Executati urmatoarea cerere:
SELECT last_name, job_id, salary as Salariu
FROM Employees;
2. Selectati toate datele din tabelul Departments.
3. Creati o interogare care sa afiseze numele de familie, data angajarii si numarul angajatului.
Folositi pentru coloana hire_date aliasul “Data angajarii”.
4. Creati o interogare pentru a afisa codurile job-urilor unice din tabelul Employees.
Indicatie. Folositi cuvantul cheie DISTINCT in clauza SELECT.
5. Afisati lista angajatilor cu numele in forma “Prenume Nume”, alipind coloana first_name cu
coloana last_name.
Indicatie. Operatorul de alipire de siruri de caractere este ||, iar ca delimitator de siruri de
caractere folositi ‘ ‘.
SELECT last_name || ', ' || first_name as Angajat FROM employees;
6. Creati o interogare care sa afiseze numele si salariul angajatilor care castiga mai mult de $12000.
7. Creati o interogare care sa afiseze numele si departamentul pentru angajatul cu id-ul 176.
8. Afisati lista angajatilor care au inceput serviciul intre 20 februarie 2000 si 1 mai 2005.
Indicatie. Folositi operatorul BETWEEN…AND…. Formatul pentru data este ’ll/zz/an’. Ex.
'02/20/2005'.
1
SGBD

9. Afisati lista angajatilor care au salariul in afara intervalului $5000 si $12000.


10. Afisati numele si departamentul pentru toti angajatii din departamentele 20 si 50. Ordonati lista
angajatilor dupa numele de familie (last_name).
11. Afisati numele angajatilor care nu au manager.
12. Afisati numele, salariul si comisionul pentru toti angajatii care castiga comision. Ordonati lista in
ordine descrescatoare a comisionului.
13. Afisati numele tuturor angajatilor pentru care a treia litera din last_name este ‘a’.
Indicatie. Conditia din clauza WHERE: last_name LIKE ‘__a%’.
14. Afisati lista angajatilor al caror nume de familie contine litera ‘e’
Indicatie. Conditia este last_name LIKE ‘%e%’.

Exercitii 2.
Pentru rezolvarea exercitiilor propuse, consultati listele de functii din Anexa.

1. Scrieti o interogare care sa afiseze data curenta. Indicatie. Folositi tabela DUAL.
2. Afisati numele intreg intr-o singura coloana Angajat si salariul tuturor angajatilor care castiga
mai mult de 12000.
3. Scrieti o interogare care sa afiseze lista angajatilor (nume intreg) si data angajarii.
4. Afisati lista angajatilor, specificand numele intreg, salariul curent si salariul marit cu 15%,
exprimat ca nr intreg (deci 0 zecimale). Denumiti noua coloana “Salariu nou”.
5. Aceeasi cerinta ca la exercitiul anterior, dar adaugati o coloana in care scadeti salariul curent din
salariul nou; noua coloana sa se numeasca “Marire”.
6. Afisati lista angajatilor specificand numele fiecaruia si lungimea numelui fiecaruia. Numele sa
fie de forma prima litera mare si restul literelor mici.
7. Restrictionati lista angajatilor de la pasul anterior, afisand doar angajatii al caror nume incepe cu
‘J’, ‘M’ ori ‘A’. Ordonati rezultatele dupa numele angajatilor.
8. Afisati lista angajatilor, specificand vechimea fiecaruia in luni (coloana se va numi Vechime).
Ordonati rezultatul dupa numarul de luni lucrate. Indicatie. Folositi in clauza ORDER BY
aliasul Vechime.
9. Reluati exercitiul anterior, dar aratati vechimea ca nr intreg.
10. Reluati exercitiul anterior, dar afisati vechimea exprimata in ani, intr-o noua coloana ‘Ani
vechime’.
11. Scrieti o interogare care afiseaza, pentru fiecare angajat, o propozitie:
<last_name first_name> castiga <salary> dar viseaza la <3*salary>’.
Numiti coloana ‘Vise’.
12. Scrieti o interogare care sa afiseze lista angajatilor care lucreaza in departamentele 20 sau 50 si
care a fost angajat in ultimii 5 ani.
13. Scrieti o interogare care sa afiseze lista angajatilor si vechimea lor exprimata in ani, pentru toti
angajatii al caror nume incepe cu litera ‘A’. Numele angajatilor sa fie scris cu toate literele mari,
iar rezultatul interogarii sa fie ordonat in ordine descrescatoare dupa vechime.
14. Creati o interogare care sa afiseze numele intreg al fiecarui angajat si salariul acestuia. Afisati
coloana salariu pe 10 caractere, eventual completati la stanga cu caracterul ‘$’ (indicatie. Folositi
functia LPAD).
15. Scrieti o interogare care afiseaza numele angajatilor si comisionul pe care il castiga. Daca un
angajat nu castiga comision, afisati ‘Nu are comision’.

2
SGBD

Anexa
Instructiunea SQL SELECT. Clauzele SELECT, FROM, WHERE, ORDER BY.
Cea mai simpla forma a instructiunii SELECT este:
SELECT lista_atribute FROM lista_tabele

Lista_atribute specifica acele coloane din care vor fi selectate datele, iar lista_tabele specifica lista
tabelelor din care provin aceste coloane.

Folosind cuvantul cheie DISTINCT inainte de lista_atribute, vom obtine in rezultatul interogarii doar
tuple distincte.

Pentru a realiza o selectie a inregistrarilor care satisfac anumite criterii, folosim clauza WHERE insotita
de o expresie logica.

Observatii.

1. Pentru a testa daca valorile unei coloane sunt NULL, se foloseste operatorul IS NULL (respectiv
IS NOT NULL).
2. Pentru a testa daca valorile unei coloane apartin unei multimi de valori, se foloseste operatorul
IN urmat de multimea de valori la care se testeaza apartenenta. De exemplu: last_name IN
(‘Grant’, ‘Fay’).
3. Pentru a testa daca valorile unei coloane sunt intr-un anumit interval se foloseste operatorul
BETWEEN … AND … .
4. Operatorul LIKE este folosit pentru a compara valorile unei coloane de tip sir de caractere cu un
sablon. In cadrul sablonului, se pot folosi caracterele masca (wildcard): % - reprezinta orice sir
de 0 ori mai multe caractere, _ reprezinta exact un caracter.
De exemplu: last_name LIKE ‘G%’ -> va selecta pe cei care au numele de familie incepand cu
litera G.
5. Operatorii logici AND, OR se folosesc pentru a inlantui conditii.
6. Aliasul unei coloane se va da neincadrat de " "; poate lipsi cuvantul cheie AS. Ex. SELECT
first_name Prenume, last_name Nume FROM employees; Daca aliasul este format din doua sau
mai multe cuvinte (nerecomandat!), atunci va fi incadrat de " "

Rezultatele unei interogari pot fi afisate ordonate dupa una sau mai multe coloane, folosint clauza
ORDER BY, urmata de numele coloanei si unul din cuvintele cheie ASC (este implicit), respectiv
DESC.

Functii SQL
Discutam in continuare despre functii care se aplica unui singur rand; acestea accepta argumente care
pot fi o coloana sau o expresie. Exista mai multe categorii: functii de conversie, functii pentru lucrul cu
caractere, functii pentru lucrul cu numere, functii pentru lucrul cu date calendaristice, functii cu caracter
general.

Documentatia ORACLE aferenta acestei sectiuni incepe aici


http://docs.oracle.com/cd/B28359_01/server.111/b28286/functions.htm.

3
SGBD

Functii pentru lucrul cu caractere:


• LOWER(expr) converteste literele din expr la litere mici;
• UPPER(expr) converteste literele la litere mari;
• INITCAP(expr) transforma prima litera a cuvintelor in litera mare si pe celelalte in litere mici;
• CONCAT(expr1, expr2) concateneaza cele doua expresii;
• SUBSTR(expr, m ,n) returneaza subsirul care incepe la pozitia m pana la sfarsitul sirului sau,
daca n este specificat, de lungime n;
• LENGTH(expr) numarul de caractere ale expresiei;
• INSTR(expr, sir,m,n) returneaza pozitia lui expr in sir, al treilea parametru este optional si
specifica pozitia de la care se porneste cautarea, cel de-al patrulea parametru, de asemenea
optional, determina a cata aparitie se va cauta ;
• LPAD(expr, n, sir) aliniaza expresia data la dreapta la un total de n caractere si completeaza la
stanga repetand sirul dat;
LPAD(salary, 10, ‘*’) => ******2356
• RPAD(expr, n, sir) analog;
• REPLACE(text, sir cautat, sir nou ) inlocuieste toate aparitiile sirului cautat din text cu sirul nou.

Functii numerice
• ROUND(expr, n) rotunjeste la n zecimale;
• TRUNC(expr, n) trunchiaza la n zecimale;
• MOD(m,n) calculeaza restul intreg al impartirii lui m la n.

Exemplu:
SELECT ROUND(45.923, 2), ROUND(45.923, 0)
FROM DUAL;
Observatie. DUAL este o tabela dummy care se foloseste pentru a vizualiza rezultatele executiei unor
calcule.

Functii pentru date calendaristice


Consultati si documentatia de aici
http://docs.oracle.com/cd/B28359_01/appdev.111/b28424/adfns_sqltypes.htm

• SYSDATE returneaza data curenta


• EXTRACT (year / month / day FROM data) returneaza anul, luna, respectiv ziua din data
specificata
• MONTHS_BETWEEN(data1, data2) returneaza numarul de luni cuprinse intre cele doua date;
• ADD_MONTHS(data, n) aduna numarul specificat de luni la data.
• ROUND(data, 'unitate de timp') rotunjeste la unitatea de timp specificata;
Presupunand ca SYSDATE returneaza ‘20-JUL-12’,
ROUND(SYSDATE, ‘MONTH’) => ‘1-AUG-12’
• TRUNC(data, 'unitate de timp') trunchiaza la unitatea de timp specificata.
Presupunand ca SYSDATE returneaza ‘20-JUL-12’,
TRUNC(SYSDATE, ‘MONTH’) => ’01-JUL-12’
4
SGBD

Calcule aritmetice cu date calendaristice se fac la nivel de numar de zile (e.g. scaderea a doua date
returneaza nr de zile dintre ele).

Conversii de tip
Consultati documentatia de aici
http://docs.oracle.com/cd/B28359_01/server.111/b28286/sql_elements002.htm#i46862.

Oracle pune la dispozitie cateva functii pentru conversii explicite de tip: TO_NUMBER primeste un
CHAR si returneaza un NUMBER, TO_CHAR primeste un NUMBER si un string de format si
returneaza un CHAR, TO_CHAR primeste un DATE si un format si returneaza un CHAR, TO_DATE
primeste un CHAR si returneaza un DATE.

Alte functii
Alte functii de interes sunt:

• NVL – converteste o valoare NULL intr-o alta valoare


ex. NVL(commision_pct, 0) – completeaza cu 0 acolo unde comisionul lipseste

• NVL2(expr1, expr2, expr3) - compara expr1 cu NULL si intoarce expr2 daca expr1 nu este
NULL, si expr3 daca este NULL. Atentie: daca expr2 si expr3 au tip diferit de date, sunt
convertite implicit pentru a avea acelasi tip de date; daca aceasta operatie nu este posibila
implicit, se va genera o eroare, in care caz conversia trebuie facuta explicit (cu una din functiie
TO_CHAR, TO_NUMBER, etc)

• NULLIF(expr1, expr2) – compara cele doua expresii si returneaza NULL daca sunt egale. Daca
nu sunt egale, returneaza expr1.

• CASE – o varianta a instr. IIF

Varianta 1:

CASE expr1

WHEN expr2 THEN expr3

ELSE expr4

END

5
SGBD

Varianta 2:

CASE expr1

WHEN expr2 THEN expr3

WHEN expr4 THEN expr5

ELSE expr6

END

Studiati exemplele din documentatia Oracle:


https://docs.oracle.com/cd/B19306_01/server.102/b14200/expressions004.htm

Ex. sa se afiseze angajatii si salariul lor, iar daca salariul are valoarea de 450$, sa se afiseze cu cat s-
ar mari daca s-ar aplica un spor de 15%.

SELECT first_name, salary,CASE salary WHEN 450 THEN salary*0.15 ELSE salary END mm from
Employees;

6
sgbd2017: Laborator 2 - Functii de grup http://www.disciplinele.ml/mod/page/view.php?id=1215

C&L Cristina Serban

Home ► 2017 - 2018 ► sgbd2017 ► Laborator 2 ► Laborator 2 - Functii de grup

NAVIGATION
Home
Dashboard
Site pages
Current course
sgbd2017 SQL permite agregarea datelor in interogari prin folosirea clauzei GROUP BY. Intr-o
Participants interogare in care apare aceasta clauza urmata de un camp (ori mai multe), motorul
General SQL va lucra la nivel de grup de inregistrari, nu la nivel de rand din tabel. In acest fel,
Laborator 1 sunt permise operatii care lucreaza cu grupuri de inregistrari, cum ar fi calcularea
minimului sau maximului dintr-un grup de valori, calculul de sume, medii, numaratori.
Laborator 2
Putem astfel calcula salariul minim dintr-o companie sau salariul maxim din fiecare
Laborator
departament al unei companii, suma tuturor salariilor lunare ale angajatilor dintr-un
2-
departament, sau a angajatilor ce ocupa un anumit job.
Operatii
JOIN Functiile de grup primesc ca argumente nume de coloane din tabelele bazei de date
folosite in interogare. Acestea au optiunea daca iau in considerare duplicatele in calcul,
Laborato prin folosirea cuvantului cheie DISTINCT. Implicit, sunt considerate toate valorile (ALL)
r2- in calcul.
Functii Pentru a efectua calcule la nivel de grup, se foloseste clauza GROUP BY, urmata de o
de grup lista de campuri, ce specifica dupa ce criterii se va face gruparea.
Laborator
2- Exemplu: Pentru a calcula salariul maxim dintr-un departament, folosim tabela
Subintero Employees. Trebuie sa grupam inregistrarile din aceasta tabela dupa campul
gari department_id, asa incat sa avem cate un grup de inregistrari pentru fiecare
departament. Peste grupul definit, calculam functia MAX.
Laborator 3
Laborator 4
Laborator 5
Laborator 6
Laborator 7
Laborator 8
Laborator 9
Laborator 10
Laborator 11
Laborator 12

1 of 4 08-Oct-17, 22:11
sgbd2017: Laborator 2 - Functii de grup http://www.disciplinele.ml/mod/page/view.php?id=1215
Laborator 13 Functiile de grup pe care le vom utiliza in continuare sunt
Laborator 14
functii ce opereaza cu valori numerice AVG, MIN, MAX, SUM
My courses COUNT – care returneaza numarul de linii dintr-un grup

Observatii.

1. Atunci cand intr-o interogare se foloseste clauza GROUP BY, in clauza SELECT se
pot regasi doar coloanele din clauza GROUP BY sau functii de grup aplicate altor
ADMINISTRATION
coloane. Orice coloana ori expresie care are valori individuale intr-un grup trebuie
Page module omisa.
administration
SELECT department_id, last_name, MAX(salary)as SalariuMaxim,
Edit settings
FROM employees
Locally
GROUP BY department_id
assigned roles
Permissions 2. Coloanele din clauza GROUP BY nu trebuie obligatoriu sa se regaseasca in lista
Check coloanelor din clauza SELECT.
permissions
Filters SELECT AVG(salary)
Logs FROM employees
Backup GROUP BY department_id ;
Restore 3. Functiile de grup ignora valorile NULL dintr-o coloana. Daca se doreste includerea
Course acestor valori, se poate folosi functia NVL.
administration 4. Daca in clauza SELECT se folosesc expresii cu functii de grup, dar lipseste clauza
Switch role to... GROUP BY, intreaga tabela va fi considerata “un grup”. De exemplu, interogarea
urmatoare numara angajatii din tabela Employees:

SELECT count(employee_id)
FROM employees

5. Se pot folosi mai multe coloane in clauza GROUP BY.


De exemplu, se doreste calculul sumelor aferente fiecarui tip de job din fiecare
departament:

6. Conditiile ce privesc grupurile de inregistrari se specifica in clauza HAVING. De


exemplu, daca ne intereseaza lista departamentelor in care salariul maxim este mai
mare decat 1000, scriem:

SELECT MAX(salary), department_id


FROM employees

2 of 4 08-Oct-17, 22:11
sgbd2017: Laborator 2 - Functii de grup http://www.disciplinele.ml/mod/page/view.php?id=1215
GROUP BY department_id
HAVING MAX(salary)>1000

8. Gruparea datelor se efectueaza dupa selectia randurilor specificata de clauza


WHERE.

Retineti:

conditiile din clauza WHERE realizeaza selectia inregistrarilor din care se vor forma
grupurile cu clauza GROUP BY
conditiile din clauza HAVING realizeaza selectia grupurilor de inregistrari

1. Calculati numarul de angajati, cel mai mic si cel mai mare salariu din tabela
Employees.
2. Modificati interogarea anterioara asa incat sa afiseze numarul de angajati, cel mai
mic salariu, cel mai mare salariu, respectiv salariul mediu pe fiecare departament.
Numiti coloana Diferenta. Afisati si numele departamentului.
3. Afisati denumirea departamentelor in care exista minim 5 angajati.
4. Afisati cel mai mic salariu al angajatilor care au manageri.
5. Afisati cel mai mic salariu pentru fiecare tip de job din fiecare departament.
6. Calculati numarul de persoane angajate pe fiecare tip de job. Afisati si tipul jobului.
Calculati diferentele intre cel mai mic salariu si cel mai mare salariu pentru fiecare
departament.
7. Calculati numarul de angajati ai managerului “King”.
8. Calculati salariul mediu pentru fiecare tip de job in parte. Afisati si tipul jobului.
9. Calculati numarul de angajati al caror nume incepe cu “A”.
10. Calculati numarul de angajati din departamentul “Executive”.
11. Afisati denumirea departamentului, locatia, numarul de salariati si salariul mediu
pentru fiecare departament.
12. Aflati numarul de departamente din fiecare tara. Rezultatul va contine coloanele
Tara, Nr. Departamente si inregistrarile vor fi ordonate alfabetic dupa nr. de
departamente.
13. Aflati numarul de angajati care s-au angajat dupa 2005.
14. Scrieti o interogare care calculeaza numarul de angajati din fiecare tara. Rezultatul
va contine coloanele Tara, Nr. Angajati.

3 of 4 08-Oct-17, 22:11
sgbd2017: Laborator 2 - Functii de grup http://www.disciplinele.ml/mod/page/view.php?id=1215
15. Scrieti o interogare care sa calculeze lista departamentelor (nume), impreuna cu
numarul de angajati din fiecare departament si salariul mediu al angajatilor din acel
departament rotunjit la 2 zecimale.
16. Scrieti o interogare care afiseaza lista tuturor managerilor impreuna cu numarul de
angajati ai fiecaruia.
17. Scrieti o interogare care calculeaza numarul de job-uri anterioare ale fiecarui
angajat, folosind tabela JOB_HISTORY. Pentru fiecare angajat, afisati si numele
acestuia.
18. Calculati numarul de departamente de la fiecare locatie a firmei. Rezultatul va
contine doua coloane: Locatie, Numar de departamente.
19. Calculati salariul minim, maxim, mediu din fiecare oras.
20. Aflati cati angajati au comision mai mare decat comisionul sefului lor

Last modified: Thursday, 7 September 2017, 2:53 PM

Moodle Docs for this page

You are logged in as Cristina Serban (Log out)


sgbd2017

4 of 4 08-Oct-17, 22:11
sgbd2017: Laborator 2 - Subinterogari http://www.disciplinele.ml/mod/page/view.php?id=1216

C&L Cristina Serban

Home ► 2017 - 2018 ► sgbd2017 ► Laborator 2 ► Laborator 2 - Subinterogari

NAVIGATION
Home
Dashboard
Site pages
SQL permite utilizarea de instructiuni SQL SELECT imbricate. In acest caz, se spune ca
Current course
folosim subinterogari (sub-queries).
sgbd2017
Subinterogarile pot apare in clauzele FROM sau WHERE, in ultimul caz subinterogarea
Participants
fiind executata o data inaintea interogarii principale:
General
Laborator 1 SELECT select_list
FROM (SELECT select_list FROM table);
Laborator 2
Laborator SELECT select_list
2- FROM table
Operatii WHERE expr operator (SELECT select_list FROM table);
JOIN
Observatii:
Laborator
2 - Functii Subinterogarile trebuie incluse intre paranteze ( ).
de grup Vor fi plasate in partea dreapta a conditiei din Where.

Laborato In subinterogari nu se foloseste clauza Order By.


r2- Daca subinterogarea returneaza un singur rand, se folosesc operatorii de comparatie
Subinter uzuali (<, >, <=, >=, <>, =).
ogari
Daca subinterogarea returneaza mai multe randuri, se folosesc cuvintele cheie IN, ANY,
Laborator 3
ALL impreuna cu operatorul de comparatie.
Laborator 4
IN – inseamna egal cu un element din lista
Laborator 5 ANY – compara valoarea cu toate elementele din lista
Laborator 6 5 < ANY (0, 100) este adevarat
Laborator 7 ALL – compara valoarea cu fiecare element din lista
Laborator 8 5 < ALL (0, 100) este fals.
Laborator 9 Exemple
Laborator 10
1. Aflati numele, jobul si salariul angajatului care are acelasi job cu angajatul 141 si are
Laborator 11 salariul mai mare decat angajatul 143.
Laborator 12
SELECT last_name, job_id, salary
Laborator 13

1 of 4 08-Oct-17, 22:12
sgbd2017: Laborator 2 - Subinterogari http://www.disciplinele.ml/mod/page/view.php?id=1216
Laborator 14 FROM employees
My courses
WHERE job_id = (SELECT job_id FROM employees WHERE employee_id = 141)

AND salary > (SELECT salary FROM employees WHERE employee_id =143);

2. Aflati ce angajati au salariul mai mare decat angajatul Abel:


ADMINISTRATION SELECT last_name,salary
Page module FROM employees
administration WHERE salary > (SELECT salary FROM employees WHERE last_name = 'Abel')
Edit settings 3. Aflati cel mai mic salariu mediu pe departamente.
Locally
SELECT min(avg(salary)) salariumediu
assigned roles
FROM employees
Permissions Group by department_id;
Check
permissions 4. Afisati lista angajatilor care au salariul minim.
SELECT last_name, job_id, salary
Filters
FROM employees
Logs
WHERE salary = (SELECT MIN(salary) FROM employees);
Backup
5. Afisati ce departamente au salariul minim egal cu salariul minim din departamentul
Restore
50.
Course SELECT department_id, MIN(salary)
administration FROM employees
GROUP BY department_id
Switch role to...
HAVING MIN(salary) = (SELECT MIN(salary) FROM employees WHERE
department_id = 50);

6. Lista angajatilor cu salariu si job care nu sunt IT_PROG si au salariul mai mic decat
UN angajat cu jobul IT_PROG.
SELECT employee_id, last_name, job_id, salary
FROM employees
WHERE salary < ANY (SELECT salary FROM employees WHERE job_id =
'IT_PROG')
AND job_id <> 'IT_PROG';

7. Lista angajatilor cu salariu si job, care nu sunt IT_PROG si au salariul mai mic decat
TOTI angajatii cu jobul IT_PROG.
SELECT employee_id, last_name, job_id, salary
FROM employees
WHERE salary < ALL (SELECT salary FROM employees WHERE job_id =
'IT_PROG')
AND job_id <> 'IT_PROG';

8. Lista angajatilor cu salariul mai mare decat salariul mediu al tipului lor de job.

SELECT employee_id,last_name,job_id, salary


FROM employees emp
where salary>(select avg(salary) from employees where job_id=emp.job_id) -
SUBINTEROGARE CORELATA

8. Aflati ce angajati nu sunt sefii nimanui:

Varianta 1:

2 of 4 08-Oct-17, 22:12
sgbd2017: Laborator 2 - Subinterogari http://www.disciplinele.ml/mod/page/view.php?id=1216
SELECT * FROM employees
WHERE employee_id NOT IN (SELECT distinct NVL(manager_id,0) FROM
employees);

Observatie: valoarea unei expresii NOT IN nu va fi TRUE daca expresia contine valori
null

3 IN (3, null) are valoare TRUE pentru ca 3 face parte din multime
3 NOT IN (3, null) are valoare UNKNOWN pentru ca nu se stie daca 3 este null sau
nu

Varianta 2: "afisati salariatii care nu au angajati" <=> nu este manager-ul vreunui angajat

SELECT * FROM employees manager


WHERE NOT EXISTS (SELECT last_name FROM employees emp where
emp.manager_id=manager.employee_id);

Interogari cu TOP N articole – Pseudocoloana ROWNUM


Se cer primele n articole (in ordine crescatoare or descrescatoare).

Sintaxa:

SELECT [column_list], ROWNUM


FROM (SELECT [column_list] FROM table ORDER BY Top-N_column)
WHERE ROWNUM <= N;

Exemplu:

SELECT ROWNUM as RANK, last_name, salary


FROM (SELECT last_name,salary FROM employees ORDER BY salary DESC)
WHERE ROWNUM <= 3;

1. Afisati lista angajatilor cu acelasi job cu cel al lui De Haan.


2. Afisati lista angajatilor si data la care au fost angajati toti angajatii care
lucreaza in acelasi departament cu Fay. Excludeti pe Fay din rezultat.
3. Scrieti o interogare pentru a afisa toti angajatii care au fost angajati dupa
Steven King.
3 of 4 08-Oct-17, 22:12
sgbd2017: Laborator 2 - Subinterogari http://www.disciplinele.ml/mod/page/view.php?id=1216
4. Afisati lista angajatilor care lucreaza in departamentele care au location_id
1700.
5. Afisati lista angajatilor si salariul celor care sunt subordonatii lui Steven King.
6. Afisati numele angajatilor si jobul celor care lucreaza in departamentul
Executive.
7. Creati o interogare care sa afiseze lista angajatilor care castiga mai mult
decat salariul mediu din firma. Ordonati inregistrarile dupa salariu.
8. Afisati lista angajatilor care au salariul mai mare decat salariul mediu din
departamentul lor. Rezultatul va contine coloanele: Angajat, Salariu,
Departament ID, Nume Departament. Ordonati dupa salariul angajatului.
9. Aflati cat castiga in medie un angajat care este sef (adica salariul mediu al
angajatilor care sunt sefi).
10. Afisati lista managerilor(id si nume) si cel mai mic salariu al angajatilor acelor
manageri care este mai mare decat salariul mediu din companie.
11. Aflati care sunt angajatii care castiga cel mai mic comision.
12. Aflati managerii (last_name) cu cel mai mic numar de angajati.
13. Aflati cate joburi anterioare a avut fiecare angajat. Aflati apoi angajatii care
au avut cele mai multe joburi anterioare.
14. Scrieti o interogare pentru a afisa angajatii care au unul sau mai multi colegi
in acelasi departament cu ei care au fost angajati dupa ei si au salarii mai
mari decat ei.
15. Scrieti o interogare pentru a afla angajatii cu salariul mai mare ca salariul
mediu al sefilor. Afisati numele angajatului si salariul.
16. Afisati lista primilor 5 angajati care au salariul cel mai mare. Afisati numele si
salariul lor.
17. Scrieti o interogare pentru a afisa numele angajatului cu idul 100,
departamentul, si toti colegii angajatului care lucreaza in acelasi
departament.

Last modified: Thursday, 7 September 2017, 3:35 PM

Moodle Docs for this page

You are logged in as Cristina Serban (Log out)


sgbd2017

4 of 4 08-Oct-17, 22:12
sgbd2017: Laborator 2 - Operatii JOIN http://www.disciplinele.ml/mod/page/view.php?id=1214

C&L Cristina Serban

Home ► 2017 - 2018 ► sgbd2017 ► Laborator 2 ► Laborator 2 - Operatii JOIN

NAVIGATION
Home
Dashboard
Site pages
In mod frecvent apar situatii in care se doreste vizualizarea informatiilor din doua sau
Current course
mai multe tabele. Aceasta operatie poarta denumirea de jonctiune (JOIN). Datele din
sgbd2017 tabelele pe care se fac jonctiuni sunt corelate, in general cu ajutorul cheilor primare si
Participants straine. De exemplu, daca ne intereseaza sa stim pentru fiecare angajat denumirea
General departamentului in care lucreaza facem corelarea intre cheia straina "department_id" din
Laborator 1 tabelul "employees" cu cheia primara din tabelul "departments".
Laborator 2 In lipsa unei conditii de jonctiune, interogarea datelor din mai multe tabele determina
realizarea unui produs cartezian intre randurile din fiecare tabel,
Laborato
De exemplu, interogarea
r2-
Operatii SELECT employees.employee_id, employees.last_name,
JOIN employees.department_id, departments.department_id,
Laborator departments.location_id
2 - Functii FROM employees, departments;
de grup
realizeaza un produs cartezian al tuturor inregistrarilor din tabelele implicate (aici,
Laborator
employees si departments). Daca dorim sa vizualizam lista angajatilor si departamentul
2-
in care lucreaza fiecare, trebuie sa specificam conditia de join astfel:
Subintero
gari WHERE employees.department_id = departments.department_id;
Laborator 3
In Oracle, operatia efectuata mai sus se numeste EQUIJOIN.
Laborator 4
Operatorul JOIN
Laborator 5
Laborator 6 SELECT employees.employee_id, employees.last_name,
Laborator 7 employees.department_id, departments.department_id,
Laborator 8 departments.location_id

Laborator 9 FROM employees JOIN departments ON employees.department_id =


departments.department_id;
Laborator 10
Laborator 11 Jonctiunile de tip JOIN afiseaza doar randurile care satisfac conditia de corelare.
Laborator 12
Laborator 13

1 of 5 08-Oct-17, 22:11
sgbd2017: Laborator 2 - Operatii JOIN http://www.disciplinele.ml/mod/page/view.php?id=1214
Laborator 14
My courses
Observatie: Uzual, coloanele de tip cheie straina au acelasi nume ca si coloanele de tip
cheie primara pe care le refera ele. De aceea, pentru a evita ambiguitatile, in interogari
se folosesc fie aliasuri pentru tabele – caz in care se prefixeaza numele coloanelor cu
numele aliasului corespunzator, fie se foloseste prefixarea direct cu numele tabelei (ca
ADMINISTRATION mai sus).

Page module Operatorii de OUTER JOIN


administration
Va reamintiti ca in MsAccess exista operatorii de JOIN extern (LEFT si RIGHT).
Edit settings Jonctiunile de tip OUTER JOIN afiseaza si randurile care nu satisfac conditia de
Locally corelare, deci pe langa randurile cuprinse in rezultatul INNER JOIN intre cele doua
assigned roles tabele, sunt afisate si randurile din tabelul din stanga (respectiv dreapta) care nu au
Permissions corespondent (conform conditiei de JOIN) in cea de a doua tabela.
Check
permissions
Filters
Logs
Backup Operatorii de OUTER JOIN:
Restore
LEFT OUTER JOIN....ON, RIGHT OUTER JOIN ...ON
Course
administration SELECT e.last_name, e.department_id, d.department_name
FROM employees e RIGHT OUTER JOIN departments d ON
Switch role to... (e.department_id = d.department_id);

(+) : se poate adauga in clauza WHERE dupa coloana din tabelul deficient in
informatii.

De exemplu, pentru a afla lista tuturor departamentelor impreuna cu angajatii lor, inclusiv
acele departamente care nu au angajati, folosim un outer join (in acest caz, left):

SELECT e.last_name, e.department_id, d.department_name


FROM employees e, departments d
WHERE e.department_id(+) = d.department_id ;

In figura de mai jos sunt exemplificati operatorii JOIN si OUTER JOIN

2 of 5 08-Oct-17, 22:11
sgbd2017: Laborator 2 - Operatii JOIN http://www.disciplinele.ml/mod/page/view.php?id=1214

Auto-jonctiunea

Un caz special de jonctiune este SELF JOIN-ul. Acesta are loc atunci cand corelarea se
face in cadrul aceluiasi tabel. De exemplu daca dorim sa facem legatura intre angajati si
managerii acestora corelam coloanele "employee id" cu "manager id". In astfel de
cazuri apare tabelul de doua ori in clauza FROM avand alias-uri diferite.

SELECT worker.last_name || ' works for ' || manager.last_name


FROM employees worker, employees manager
WHERE worker.manager_id = manager.employee_id ;

Clauza WHERE

In mediul Oracle jonctiunile se pot exprima si prin specificarea conditiei de JOIN in


cadrul clauzei WHERE.

In clauza WHERE se pot specifica si conditii suplimentare, dupa cum cere logica
interogarii pe care trebuie sa o efectuam.

Pentru a specifica mai multe operatii de JOIN, in WHERE vor apare mai multe conditii
de legatura.

In Oracle se pot implementa si operatii de JOIN in care operatorul folosit in WHERE nu


este cel de egalitate (se numesc NON-EQUIJOIN). De exemplu, putem afla angajatii
care au salariul intre doua trepte de valoare specificate in JOBS:

SELECT e.last_name, e.salary, j.job_title


FROM employees e, jobs j
WHERE e.salary BETWEEN j.min_salary AND j.max_salary;

In cele doua exemple de mai sus apar doar acele linii din tabele care corespund
criteriului specificat.

3 of 5 08-Oct-17, 22:11
sgbd2017: Laborator 2 - Operatii JOIN http://www.disciplinele.ml/mod/page/view.php?id=1214

1. Afisati lista tuturor job-urilor (distincte) din departamentul 80.


2. Includeti numele orasului in care se afla angajatul cu jobul respectiv in rezultatul
interogarii anterioare.
3. Afisati lista angajatilor al caror nume incepe cu ‘a’ impreuna cu departamentul in
care lucreaza.
4. Afisati pentru fiecare angajat care lucreaza in departamentele “Shipping”,
“Finance” sau “Executive” numele angajatului, functia, numele departamentului.
Ordonati rezultatele crescator dupa departament si dupa numele de familie al
angajatului.
5. Afisati lista tuturor angajatilor, job-ul lor, numele departamentului, pentru acei
angajati care lucreaza in Toronto.
6. Afisati lista departamentelor si orasele in care se gasesc acestea.
7. Afisati lista oraselor si departamentele care se gasesc in aceste orase, dar
includeti in rezultat si orasele unde nu se gaseste nici un departament.
8. Afisati doar lista oraselor unde nu exista nici un departament.
9. Afisati lista tarilor si a departamentelor care exista acolo, inclusiv tarile unde nu
exista nici un departament.
10. Afisati lista angajatilor (nume intreg) si id-ul lor, impreuna cu managerul lor (nume
intreg) si id-ul acestuia.
11. Modificati interogarea anterioara si includeti si angajatii care nu au manager.
Ordonati dupa numele angajatilor.
12. Afisati lista angajatilor si departamentul unde lucreaza, impreuna cu seful lor si
departamentul sefului. Ordonati rezultatul dupa numele sefului.
13. Modificati interogarea anterioara si afisati doar acei angajati al caror sef lucreaza
in alt departament decat ei.
14. Afisati lista angajatilor care au fost angajati inaintea managerului lor. Rezultatul va
contine numele intreg al angajatului, data angajarii, numele sefului, data angajarii
sefului. Folositi aliasuri corespunzatoare pentru coloanele selectate.
15. Afisati lista angajatilor cu jobul lor curent impreuna cu numele departamentului la
care lucreaza acum.
16. Afisati joburile angajatilor anterioare, impreuna cu departamentele la care au fost
angajati si cu intervalul de timp (luni) in care au fost angajati. Indicatie. Folositi
tabela JOB_HISTORY.

4 of 5 08-Oct-17, 22:11
sgbd2017: Laborator 2 - Operatii JOIN http://www.disciplinele.ml/mod/page/view.php?id=1214
Atentie! In lista se vor regasi TOTI angajatii, inclusiv cei care nu au avut joburi
anterioare.
17. Afisati lista tuturor joburilor pe care le-a avut dna Neena Kochhar.
18. Scrieti o interogare care afiseaza lista tuturor angajatilor care castiga comision mai
mare decat 0.25, impreuna cu departamentul in care lucreaza si cu orasul.
19. Exista angajati care castiga comision mai mare decat comisionul sefului lor? Afisati
lista angajatilor care castiga comision mai mare decat cel al sefului lor. Rezultatul
va contine coloanele Angajat, Comision angajat, Sef, Comision sef.
20. Exista angajati care castiga comision mai mare decat comisionul sefului lor si care
au fost angajati dupa seful lor?
21. Exista angajati care castiga comision mai mare decat comisionul sefului lor, dar au
fost angajati inaintea sefului lor?

Observatie. Mariti numarul de randuri afisate pentru a putea verifica rezultatele


interogarilor pe care le efectuati.

Last modified: Thursday, 7 September 2017, 2:53 PM

Moodle Docs for this page

You are logged in as Cristina Serban (Log out)


sgbd2017

5 of 5 08-Oct-17, 22:11
SGBD

Laborator 3
Data Definition Language (DDL)
Data Manipulation Language (DML)

EXERCITII

Data Definition Language


DDL – reprezinta un set de instructiuni pentru crearea, modificarea si stergerea obiectelor (e.g.
tabelelor) din cadrul unei scheme de baze de date.

Instructiuni DDL:
- crearea structurii unui tabel
CREATE TABLE
CREATE TABLE ….AS SELECT…..- selecteaza datele dintr-un tabel existent si creeaza cu acelea un
nou tabel. Atentie: nu se vor seta in noul tabel constrangerile de integritate asupra datelor din vechiul
tabel (cu exceptia constrangerii NOT NULL).

- modificarea structurii unui tabel (adaugare/modificare/stergere coloane)


ALTER TABLE table ADD …
ALTER TABLE table MODIFY …
ALTER TABLE table DROP …
- lucrul cu constrangeri
ALTER TABLE … ADD CONSTRAINT …
ALTER TABLE … DROP CONSTRAINT …
ALTER TABLE … DISABLE CONSTRAINT …
ALTER TABLE … ENABLE CONSTRAINT …
- stegerea (definitiva!) a unui tabel (structura + date)
DROP TABLE …
- stergerea inregistrarilor din tabel
TRUNCATE TABLE
- redenumirea unui tabel
RENAME…
- adaugarea de comentarii tabelelor
COMMENT ON …

Data Manipulation Language


DML – reprezinta un set de instructiuni pentru adaugarea, modificarea si stergerea datelor din baze de
date relationale.
Instructiuni DML:
- introducerea unui rand in tabel
INSERT INTO …VALUES …
- introducerea a n randuri in tabel
INSERT INTO … SELECT….
- actualizarea datelor coloanelor
UPDATE ….SET…[WHERE]…
- stergerea randurilor din tabel
1
SGBD

DELETE FROM …. [WHERE]…


Pentru server-ul ORACLE: instructiunea MERGE.

Data Definition Language


Instructiunea CREATE
Sintaxa instructiunii Create este:

CREATE TABLE [schema.] table ( col1 tip_data [DEFAULT expresie ] , . . . ) ;

Exemplu:
CREATE TABLE departamente
(iddept NUMBER(2),
dnume VARCHAR2(14),
loc VARCHAR2(13));

CREATE TABLE angajati


( idang NUMBER( 2 ) ,
nume VARCHAR2( 14 ) ,
prenume VARCHAR2( 20 ) ,
data_angajarii DATE DEFAULT SYSDATE) ;

Confirmarea ca o tabela a fost creata:


DESCRIBE angajati;

Crearea unui tabel se poate realiza folosind o subinterogare, caz in care se adauga la tabelul creat
randurile returnate:

CREATE TABLE dept80 AS


SELECT employee_id, last_name, salary*12 ANNSAL, hire_date FROM employees
WHERE department_id = 80;

Consultati documentatia de la
http://docs.oracle.com/cd/E11882_01/server.112/e26088/sql_elements001.htm pentru mai multe detalii
despre tipurile de date folosite de Oracle. Exemple de tipuri de date:
• VARCHAR2(size [BYTE | CHAR]): Variable-length character string having maximum length size
bytes or characters.
• NUMBER [ (p [, s]) ]: Number having precision (nr cifre) p and scale (nr zecimale) s.
• DATE: Valid date range from January 1, 4712 BC, to December 31, 9999 AD
• CLOB: A character large object containing single-byte or multibyte characters. A CLOB is used
to store large documents in any character set.
• BLOB: A binary large object .A BLOB (Binary Large Object) can hold up to 4 GB of data.
BLOB's are handy for storing digitized information (e.g., images, audio, video).

2
SGBD

Instructiunea ALTER
Pentru a modifica structura unui tabel se foloseste instructiunea ALTER TABLE. Astfel, se pot adauga,
modifica, sterge coloane/constrangeri din tabele.

• ALTER TABLE table ADD (column datatype [DEFAULT expr] [, column datatype]...);
• ALTER TABLE table MODIFY (column datatype [DEFAULT expr] [, column datatype]...);
• ALTER TABLE table DROP COLUMN (column);

Exemplu:
ALTER TABLE dept80 ADD (job_id VARCHAR2(9));

Se poate folosi clauza SET UNUSED pentru a marca anumite coloane ca fiind nefolosite:
ALTER TABLE table SET UNUSED (column);
ALTER TABLE table SET UNUSED COLUMN column;

Apoi se pot sterge coloanele nefolosite:


ALTER TABLE table DROP UNUSED COLUMNS;

Instructiunea DROP TABLE


Este folosita pentru a sterge un tabel. Acesta va fi sters definitiv, nu se poate face rollback. Este sters
intreg tabelul impreuna cu inregistrarile din acesta.

Exemplu:
DROP TABLE dept80;

Instructiunea RENAME
Se foloseste pentru a redenumi un obiect: RENAME dept TO detail_dept;

Instructiunea TRUNCATE
Sterge toate inregistrarile din tabel:

Exempu: TRUNCATE TABLE detail_dept;

Instructiunea COMMENT
Se foloseste pentru a adauga un comentariu legat de un tabel ori coloana din baza de date.

Exemplu:
COMMENT ON TABLE employees IS 'Employee Information';

Constrangeri
Constrangerile sunt folosite pentru a stabili reguli la nivel de tabele.

Tipurile de constrangeri sunt:


• NOT NULL – nu permite valori nule,
• UNIQUE – nu permite valori duplicate,
• PRIMARY KEY – cheie primara (include NOT NULL si UNIQUE),
3
SGBD

• FOREIGN KEY si
• CHECK – defineste o conditie care sa fie satisfacuta de fiecare inregistrare.

Acestea se pot crea simultan cu tabelul sau ulterior, si se declara la nivel de coloana sau la nivel de tabel.

Constrangerea de tip FOREIGN KEY:


• FOREIGN KEY: defineste coloana din tabelul copil pe care se impune constrangerea
• REFERENCES: identifica tabelul si coloana in tabelul parinte
• ON DELETE CASCADE: sterge in mod automat inregistrarile dependente din tabelul copil
atunci cand se sterge o inregistrare din tabelul parinte
• ON DELETE SET NULL: converteste valorile de pe coloana cheie straina la NULL atunci cand
se sterge o inregistrare in tabela parinte

Exemplu:
CREATE TABLE angajati ( idang NUMBER( 2 ) ,
nume VARCHAR2( 14 ) ,
prenume VARCHAR2( 20 ) ,
data_ang DATE DEFAULT SYSDATE,
email VARCHAR2( 25 ) UNIQUE,
iddep NUMBER( 2 ) ,
functie VARCHAR2( 10 ) NOT NULL,
salariu NUMBER( 2 ) ,
CONSTRAINT idang_pk PRIMARY KEY (idang ) ,
CONSTRAINT iddept_fk FOREIGN KEY ( department_id ) REFERENCES
departments(depatment_id),
CONSTRAINT salmin CHECK (salariu > 0));

Obs. setarea constrangerii NOT NUL se va face astfel:


ALTER TABLE table_name MODIFY column_name datatype NOT NULL;

Sintaxa pentru lucrul cu constrangeri este:


• ALTER TABLE [ schema . ] table ADD CONSTRAINT [denumire ] tipconstrangere(coloana) ;
• ALTER TABLE [ schema . ] table DROP CONSTRAINT denumire [CASCADE] ;
• ALTER TABLE [ schema . ] table DISABLE CONSTRAINT denumire [CASCADE] ;
• ALTER TABLE [ schema . ] table ENABLE CONSTRAINT denumire ;

4
SGBD

Data Manipulation Language


Instructiunea INSERT
Instructiunea INSERT realizeaza inserarea datelor intr-un tabel. Sintaxa acestei instructiuni este:

INSERT INTO table [(column [, column...])]


VALUES (value [, value...]);

Instructiunea INSERT, scrisa in forma de mai sus, insereaza un singur rand intr-un tabel. Valorile se
precizeaza in ordinea in care sunt coloanele in tabel, sau in ordinea in care sunt scrise coloanele in
instructiune (daca sunt scrise). Valorile tip caracter si cele tip data calendaristica se pun intre apostrofuri.

Exemplu:
INSERT INTO departments(department_id, department_name, manager_id, location_id)
VALUES (70, 'Public Relations', 100, 1700);

Pentru a insera inregistrari ce contin si valori NULL:


• Fie se omit coloanele in lista de coloane
INSERT INTO departments (department_id, department_name) VALUES (30, 'Purchasing');
• Fie se precizeaza cuvantul cheie NULL
INSERT INTO departments VALUES (100, 'Finance', NULL, NULL);

Pot fi folosite si functii pentru a insera, de ex. SYSDATE:


INSERT INTO employees (employee_id, first_name, last_name, email, phone_number, hire_date,
job_id, salary, commission_pct, manager_id, department_id)
VALUES (113, 'Louis', 'Popp', 'LPOPP', '515.124.4567', SYSDATE, 'AC_ACCOUNT', 6900, NULL,
205, 100);

In instructiunea INSERT pot fi folosite subinterogari. Astfel, se pot insera date ce provin din tabele. NU
se foloseste clauza VALUES in acest caz.
INSERT INTO sales_reps(id, name, salary, commission_pct)
(SELECT employee_id, last_name, salary, commission_pct
FROM employees
WHERE job_id LIKE '%REP%' );

Numarul de coloane din clauza INSERT trebuie sa fie identic cu nr de coloane din subinterogare (la fel,
tipurile de date trebuie sa corespunda).

Instructiunea UPDATE
Instructiunea UPDATE se foloseste pentru a modifica inregistrari din baza de date (una sau mai multe).
Sintaxa:
UPDATE table
SET column = value [, column = value, ...]
[WHERE condition];

Exemplu:

5
SGBD

UPDATE employees SET department_id = 70 WHERE employee_id = 113;

Daca lipseste clauza WHERE, atunci TOATE inregistrarile din tabela respectiva vor fi modificate.

Pot fi modificate mai multe coloane:


UPDATE employees
SET job_id = (SELECT job_id FROM employees WHERE employee_id = 205),
salary = (SELECT salary FROM employees WHERE employee_id = 205)
WHERE employee_id = 114;

UPDATE copy_emp
SET department_id = (SELECT department_id FROM employees WHERE employee_id = 100)
WHERE job_id = (SELECT job_id FROM employees WHERE employee_id = 200);

Instructiunile de UPDATE/INSERT trebuie sa respecte constrangerile existente in baza de date.


Ce se obtine la executia instructiunii urmatoare?
UPDATE employees
SET department_id = 55
WHERE department_id = 110;

Instructiunea DELETE
Pentru a sterge inregistrari dintr-un tabel se foloseste instructiunea DELETE.
DELETE [FROM] table
[WHERE condition];

Exemplu:
DELETE FROM departments
WHERE department_name = 'Finance';

Atentie! Daca lipseste clauza WHERE, vor fi sterse TOATE randurile.

Pot fi folosite subinterogari in cadrul instructiunii DELETE:


DELETE FROM employees WHERE department_id = (SELECT department_id FROM departments
WHERE department_name LIKE '%Public%');

Instructiunea MERGE
Permite modificarea/inserarea de noi inregistrari intr-un tabel, tinand cont de o conditie: daca
inregistrarea deja exista, o modifica; altfel, o insereaza. Aceasta instructiune este indeosebi utila in cazul
in care se doreste mutarea/copierea de date de dimensiuni mari.

Sintaxa:
MERGE INTO table_name table_alias USING (table|view|sub_query) alias ON (join condition)
WHEN MATCHED THEN
UPDATE SET col1 = col_val1, col2 = col2_val
[DELETE WHERE condition]
WHEN NOT MATCHED THEN

6
SGBD

INSERT (column_list)
VALUES (column_values);

Clauza DELETE a instrucțiunii MERGE va acționa numai asupra înregistrărilor care au fost actualizate.

Exemplu: Executati scriptul de mai jos:


Indicatii. Din interfata SQL Workshop, selectati tabul SQL Scripts. In fereastra, dati click pe Create. In
text area-ul ce apare, alipiti scriptul de mai jos. Salvati scriptul si rulati-l (Run). Apoi alegeti View
results. Selectati optiunea Detail pentru a vedea rezultatele detaliate ale executarii scriptului. Ce
observati?
CREATE TABLE employee (
employee_id NUMBER(5),
first_name VARCHAR2(20),
last_name VARCHAR2(20),
dept_no NUMBER(2),
salary NUMBER(10));

INSERT INTO employee VALUES (1, 'Dan', 'Morgan', 10, 100000);


INSERT INTO employee VALUES (2, 'Helen', 'Lofstrom', 20, 100000);
INSERT INTO employee VALUES (3, 'Akiko', 'Toyota', 20, 50000);
INSERT INTO employee VALUES (4, 'Jackie', 'Stough', 20, 40000);
INSERT INTO employee VALUES (5, 'Richard', 'Foote', 20, 70000);
INSERT INTO employee VALUES (6, 'Joe', 'Johnson', 20, 30000);
INSERT INTO employee VALUES (7, 'Clark', 'Urling', 20, 90000);

CREATE TABLE bonuses (


employee_id NUMBER,
bonus NUMBER DEFAULT 100);

INSERT INTO bonuses (employee_id) VALUES (1);


INSERT INTO bonuses (employee_id) VALUES (2);
INSERT INTO bonuses (employee_id) VALUES (4);
INSERT INTO bonuses (employee_id) VALUES (6);
INSERT INTO bonuses (employee_id) VALUES (7);
COMMIT;

SELECT * FROM employee;


SELECT * FROM bonuses;

MERGE INTO bonuses b


USING (
SELECT employee_id, salary, dept_no
FROM employee
WHERE dept_no =20) e
ON (b.employee_id = e.employee_id)
WHEN MATCHED THEN
UPDATE SET b.bonus = e.salary * 0.1
7
SGBD

DELETE WHERE (e.salary < 40000)


WHEN NOT MATCHED THEN
INSERT (b.employee_id, b.bonus)
VALUES (e.employee_id, e.salary * 0.05)
WHERE (e.salary >= 40000);
SELECT * FROM bonuses;

Obs. Instr. MERGE va introduce in BONUSES noi angajați din EMPLOYEE, cu conditia sa fie din
departamentul 20 si sa aiba salariul mai mare decat 40000, va actualiza bonusul angajaților existenți și
va elimina angajații din BONUSES din departamentul 20 al căror salariu este mai mic decat 40000.

Exercitii
Creati tabelul DEPT folosind informatiile de mai jos. Verificati apoi daca s-a creat tabelul.

Creati tabelul EMP folosind urmatoarea schema

1. Modificati o coloana in EMP astfel incat sa permita nume de familie lungi de 50 de caractere.
2. Creati tabelul EMPLOYEES2 pe baza tabelului EMPLOYEES, incluzand doar coloanele
employee_id, first_name, last_name, salary si department_id. Redenumiti coloanele
corespunzatoare, in noul tabel, cu id, salariu si dept_id.
3. Stergeti tabelul EMP.
4. Redenumiti pe EMPLOYEES2 in EMP.
5. Adaugati comentarii tabelelor DEPT si EMP.
6. Stergeti coloana first_name din EMP. Verificati daca s-a sters.
8
SGBD

7. Marcati coloana DEPT_ID ca UNUSED.


8. Stergeti coloanele UNUSED din tabelul EMP.
9. Adaugati o constrangere tip cheie primara la tabela EMP pe coloana ID.Constrangerea se va
denumi my_emp_id_pk la crearea ei.
10. Creati o constangere tip cheie primara in tabelul DEPT pe coloana ID. Numele ei va fi
my_dept_id_pk.
11. Adaugati o coloana DEPT_ID la tabelul EMP. Adaugati o constrangere tip cheie straina la tabela
EMP care sa asigure faptul ca un angajat nu poate fi asignat unui departament inexistent.
Denumiti constrangerea my_emp_dept_id_fk.
12. Stergeti constrangerea creata la ex. 11.
13. Adaugati constrangerea my_emp_dept_id_fk definita la ex. 11, punand in plus conditia de setare
cu NULL, in mod automat, a inregistrarilor dependente din emp atunci cand se sterge o
inregistrare din dept
14. Modificati tabelul "EMP" adaugand o coloana "COMISION" de tip "NUMBER". Adaugati o
constrangere acestei coloane care sa asigure faptul ca valorile sale trebuie sa fie mai mari sau
egale cu 0.
15. Inserati in tabelul DEPT toate randurile din tabelul departments, coloanele department_id si
department_name.
16. Adaugati in tabelul EMP angajatii din employees
(employee_id,departmant_id,salary,commission_pct) din departamentul 80. Folositi MERGE.
17. Modificati in tabelul DEPT denumirea departamentului cu id=70 in PR.
18. Adaugati in tabelul DEPT o coloana numita total_sal. Actualizati apoi tabelul astfel incat coloana
total_sal sa contina valoarea totala a salariilor angajatilor în departamentul respectiv.

9
SGBD

Laborator 4
Vederi (views)
Secvente
Indecsi
Tranzactii

Vederi
Vederea este un tabel virtual si este stocata in baza de date sub forma unei interogari SELECT. O
vedere reprezinta, asadar, o combinatie de date din unul sau mai multe tabele sau alte vederi.

Conținutul unei vederi nu este memorat fizic în baza de date: se recalculează de fiecare dată când
vederea este utilizata, ceea ce determina executia interogarii care o definește.

Sintaxa:
CREATE [OR REPLACE] VIEW view [lista_atribute]
AS subquery
[WITH CHECK OPTION]
[WITH READ ONLY];

Exemplu:
CREATE VIEW empvu80
AS SELECT employee_id, last_name, salary
FROM employees
WHERE department_id = 80;

Daca lista_atribute lipseste, se vor utiliza denumirile atributelor din interogarea care defineste vederea.
Numele atributelor trebuie să fie specificate dacă:
• ele reprezintă rezultatul unei expresii
• două coloane (din diferite tabele) au același nume

Exemplu:
CREATE VIEW dept_info_sal (name, minsal, maxsal, avgsal)
AS SELECT d.department_name, MIN(e.salary), MAX(e.salary),AVG(e.salary)
FROM employees e, departments d
WHERE e.department_id = d.department_id
GROUP BY d.department_name;

Observatie: name, minsal, maxsal, avgsal reprezinta atributele vederii!

O vedere este un obiect al bazei de date, deci poate fi utilizata în interogări, ca și cum ar fi un
tabel.

Exemplu:
CREATE VIEW dept_sal
AS SELECT employee_id ID, last_name NAME, salary, d.department_id DEPTID, department_name

1
SGBD

DEPT
FROM employees e, departments d
WHERE e.department_id=d.department_id and d.department_id in (50,60,70);

SELECT * FROM dept_sal;

Avantaje ale folosirii vederilor:


• simplificarea interogarilor
o expresii foarte complexe pot fi definite într-un mod mai simplu prin utilizarea vederilor
• permit diferite definitii asupra acelorasi date
• permit restrictionarea accesului la date
o fiecare utilizator sau grup accesează baza de date numai prin intermediul vederilor
corespunzatoare operatiilor pe care sunt autorizati sa le efectueze
o atribuirea drepturilor de acces ale unui utilizator la o vedere inseamna limitarea:
 vizibilitatii pe tabelele referite
 a operațiunilor pe care le poate executa

Modificarea unei vederi:


ALTER VIEW view [lista_atribute]
AS subquery

Pentru a sterge un view: DROP VIEW view


Exemplu:
DROP VIEW detp_sal;

Stergerea unui tabel referit de o vedere poate avea diverse efecte, care depind de SGBD-ul utilizat:
• eliminarea automată a vederilor asociate
• invalidarea automată a vederilor asociate
• interdicție de a executa operația de stergere

Actualizarea datelor din vedere

Vederile ofera posibilitatea vizualizarii si modificarii acestora <=> Prin intermediul unui view pot fi
efectuate operatii DML.

Pot fi modificate datele unei vederi in care exista o corespondență univocă (unu-la-unu) între un tuplu
din vedere și tuplul din tabelele pe care este definită. In acest caz, este posibil să se propage fără
ambiguitate modificările aduse în vedere catre fiecare tabel pe care aceasta este definita.

Pot fi sterse/modificate/adaugate randuri daca:


• actualizarea afecteaza un tabel de baza de tip "key-preserved" (cu conservare cheie): un tabel
de baza a carui cheie primara este unica si in vedere

Exemplu: actualizeaza salariul angajatilor din departamentul Shipping; se actualizeaza tabelul


employees, a carui cheie primara este unica in vedere

2
SGBD

UPDATE dept_sal
SET salary=salary*1.2
WHERE DEPT=’Shipping’;

Actualizarea
UPDATE dept_sal
SET dept='ShippingRo'
WHERE DEPT='Shipping';
va genera mesajul de eroare ORA-01779: cannot modify a column which maps to a non key-
preserved table, deoarece se incearca actualizarea tabelului departments, a carui cheie primara nu
este unica in vedere (vederea are atributul DEPTID, dar acesta nu este unic in vedere, din cauza join-
ului cu tabelul Employees!).

• interogarea pe care este definita vederea nu contine clauza ORDER BY


• interogarea pe care este definita vederea nu conține funcții de agregare si clauza GROUP BY
• interogarea pe care este definita vederea nu contine conține DISTINCT
• interogarea pe care este definita vederea nu contine subinterogare

Probleme care apar la modificarea datelor folosind vederile


Deoarece ceea ce vedeti intr-o vedere poate fi un set de date dintr-un grup de tabele, modificarea datelor
in tabelele de baza nu este totdeauna la fel de directa.
• Instructiunea INSERT nu este permisa decat daca toate coloanele cu atributul NOT NULL
folosite in tabelul de baza sunt incluse in vedere. Aceasta se datoreaza faptului ca procesorul
SQL nu cunoaste ce valori sa insereze intr-o coloana NOT NULL.
• Daca inserati sau actualizati (INSERT – UPDATE) inregistrari intr-o vedere a unui JOIN, toate
inregistrarile care sunt actualizate trebuie sa apartina aceluiasi tabel fizic (care are conservare
de cheie).
• O coloana virtuala (o coloana care este rezultatul unui calcul sau al unei expresii) nu poate fi
actualizata

Exista si clauza WITH READ ONLY care nu permite operatii DML intr-un view.

Clauza WITH CHECK OPTION


Este folosita pentru a nu permite modificari ale datelor vederii (INSERT sau UPDATE) care ar avea ca
rezultat randuri ce violeaza conditiile din clauza WHERE.

Exemplu: se vor modifica/introduce doar angajati al caror cod de departament este 10!
CREATE OR REPLACE VIEW empvu10 (employee_number, employee_name, job_title)
AS SELECT employee_id, last_name, job_id
FROM employees
WHERE department_id = 10 WITH CHECK OPTION;

ATENTIE:
1) Daca o vedere are clauza WITH CHECK OPTION si o interogare construita cu ajutorul
operatorului JOIN, NU permite inserari sau actualizari (INSERT – UPDATE)

3
SGBD

2) Pentru o instrucțiune DELETE, dacă JOIN-ul are ca rezultat mai multe tabele cu conservare de
cheie, atunci Oracle Database șterge din primul tabel intalnir în clauza FROM, indiferent dacă
vederea a fost creată sau nu WITH CHECK OPTION.

Exercitii 1
1. Creati un view numit EMPLOYEES_DEPTS bazat pe id-ul, numele si numele departamentul
angajatilor din tabela EMPLOYEES. Redenumiti coloanele ID, NUME, DEPARTAMENT
2. Vizualizati continutul acestui view.
3. Folosind acest view, scrieti o interogare pentru a afisa numele angajatilor din departamentul
Executive.
4. Creati o vedere DEPT50 care contine idurile, numele si departamentele angajatilor din
departamentul 50. Coloanele in view se vor numi EMPNO, EMPLOYEE, DEPTNO. Nu
permiteti ca un angajat din acest view sa poata sa fie setat in alt departament
5. Incercati sa distribuiti angajatul Matos din acest view departamentului 80. Ce obtineti?

Secvente

Secventele sunt obiecte ale bazei de date create de utilizatori pentru a fi folosite la generarea de numere
intregi unice, in general pentru campurile cu constrangeri de tip chei primare.

Aceeasi secventa poate fi utilizata de mai multi useri.

Fiind stocate si generate independent pot fi folosite pentru mai multe tabele.

Sintaxa:
CREATE SEQUENCE denumire_secventa
[INCREMENT BY n ]
[START WITH n ]
[ MAXVALUE n| NOMAXVALUE ]
[ MINVALUE n| NOMINVALUE ]

Exemplu:
CREATE SEQUENCE deptid_seq
INCREMENT BY 10
START WITH 500
MAXVALUE 9999;

Pentru a accesa valorile din cadrul unei secvente se foloseste pseudocoloana NEXTVAL. Apeland
denumire_secventa.NEXTVAL se genereaza un nou numar si se extrage pentru a putea fi folosit.

Exemplu:
INSERT INTO departments ( department_id , department name , location_id )
VALUES ( deptid_seq.NEXTVAL, ' Cercetare ' , 2500 ) ;

4
SGBD

O secventa se poate modifica sau sterge.

ALTER SEQUENCE denumire_secventa


[INCREMENT BY n ]
[ MAXVALUE n | NOMAXVALUE ]
[ MINVALUE n | NOMINVALUE ]

DROP SEQUENCE denumire_secventa ;

Exercitii 2
1. Creati o secventa care sa fie folosita cu rol de cheie primara pentru tabelul "DEPT". Secventa ar trebui
sa inceapa de la ultima valoare din tabelul DEPT (verificati!) si sa aiba o valoare maxima de 1000. Setati
pasul de incrementare la 10. Denumiti secventa "DEPT_ID_SEQ".
2. Inserati in tabelul "DEPT" doua linii folosind secventa creata pentru coloana "ID".

Indecsi
Intr-o baza de date, datele sunt reprezentate sub forma unor colecții de înregistrări memorate într-unul
sau mai multe fișiere.
• organizarea fizică a datelor într-un fișier influențează timpul necesar pentru accesarea informației
• nu există o organizare de date fizice eficienta pentru orice tip de citire și scriere a datelor

Un index reprezinta un obiect din schema bazei de date care poate sa creasca performanta operatiilor de
obtinere de informatii din baza de date.

Exemplu:
Daca se creeaza un index pe atributul Residence, atunci pentru fiecare valoare a atributului Residence
sunt memorate toate locațiile fizice ale înregistrărilor care corespund acestei valori (locația fizică: indică
poziția unei înregistrări într-un fișier)

5
SGBD

Acestia se creeaza

• automat - pe coloanele cu constrangeri PRIMARY KEY si UNIQUE sau


• manual de catre utilizatori.

Avantaje:
• se evita citirea secvențială a întregului fișier
• acces direct numai la înregistrările de interes
• costurile de întreținere a indecsilor sunt mai mici decât costurile de întreținere a unui fiser
cu o structură neordonată

Dezavantaje:
• ocupă mai mult spațiu
• indecsii se utilizeaza doar cand atributele pe care sunt definiti apar in interogare

Pentru crearea indecsilor se pot folosi arbori sau tabele hash.

Indecsii sunt creati independent de tabele, prin urmare pot fi creati sau stersi fara sa afecteze tabelele
corespunzatoare.

Sintaxa:
CREATE INDEX denumire_index ON tabel (col 1 [ , col2 , . . . ] ) ;

Observatie: ordinea atributelor col 1, col 2,…. este importanta! Valorile indecsilor sunt ordonate dupa
col1, in caz de egalitate a valorilor de pe col1 atunci se ordoneaza dupa col2, s.a.m.d.

6
SGBD

Exemplu:
CREATE INDEX emp_last_name_idx
ON employees (last_name);

Este recomandat sa se creeze indecsi pe coloanele care

1. contin un domeniu larg de valori


2. contin multe valori NULL
3. sunt folosite frecvent intr-o clauza WHERE sau pentru a crea jonctiuni

Pentru a sterge un index se foloseste comanda


DROP INDEX denumire_index;

Exercitii 3
1. Creati un index pe cheia straina "DEPT_ID" din tabelul "EMP".

Tranzactii
Exemplu:
Operațiune bancara: retragere de numerar dintr-un cont curent folosind un card
Operații:
• specifica suma necesara
• verifică disponibilitatea
• actualizeaza suma din cont
• permite retragerea sumei necesare
Toate operațiile trebuie să fie efectuate în mod corect, în caz contrar, suma nu poate fi retrasa!

Corecta gestionare a informațiilor necesită:


• mecanisme pentru gestionarea accesului simultan la baza de date
• mecanisme de recuperare a stării corecte a bazei de date, în cazul unei funcționări defectuoase

O tranzacție este o secvență de operații care:


• reprezintă o singura unitate logica de lucru
• se poate încheia cu succes sau eșec
o în cazul unui succes, rezultatul operațiunilor sunt permanente în baza de date
o în caz de eșec, baza de date trebuie să se întoarcă la starea inițială de dinainte de
tranzacție
7
SGBD

Tranzactii se impart in doua clase:


• tranzactii DML: consta in instructiuni DML care reprezinta o modificare consistenta a datelor
• tranzactii DDL: consta intr-o singura instructiune DDL, dupa a carei executie se executa un
COMMIT automat
• tranzatii DCL: consta intr-o singura instructiune DCL, dupa a carei executie se executa un
COMMIT automat

Inchiderea normală a unei baze de date determina, de asemenea, executia unui COMMIT automat.

Tranzactii DML
Executarea instructiunilor DML este tranzacțională (ACID) :
A - Atomic: toate rândurile implicate (dacă se respecta toate constrangerile) sau nici unul (dacă cel puțin
o valoare încălca cel puțin o constrângere) sunt afectate de schimbarea respectivă

C - Consistent: baza de date ramane in stare consistenta (nu poate încălca nici una din constrângerile
sale) la sfarsitul tranzactiei, deși, uneori, în timpul unei tranzacții, constrângerile pot fi încălcate
temporar

I – Independent: orice tranzacție care ruleaza in medii concurente trebuie să se comporte la fel, ca și cum
ar fi rulată singură, indiferent de orice altă tranzacție concurenta

D - Durabil: La sfârșitul fiecărei tranzacții incheiate cu succes, toate datele noi sunt stocate pentru
totdeauna: numai tranzacțiile ulterioare le-ar putea modifica

O tranzactie incepe cand s-a efectuat prima instructiune DML.

Se termina atunci cand s-a efectuat un eveniment de tip:


• COMMIT - face permanente si vizibile celorlalti utilizatori modificarile din cadrul unei tranzactii
• ROLLBACK - anuleaza modificarile din cadrul unei tranzactii.

Daca sistemul “crapa” ori se inchide serverul sau se termina anormal sesiunea de lucru curenta,
tranzactia se termina prin efectuarea unui ROLLBACK automat.

Inainte de COMMIT/ROLLBACK:
• se poate oricand reveni la starea anterioara a datelor
• utilizatorul poate vizualiza rezultatele operatiilor tip DML folosind SELECT
• ceilalti utilizatori nu pot vedea aceste modificari
• randurile afectate sunt locked, nici un alt utilizator nu poate modifica acele randuri.

Dupa COMMIT:
• modificarile sunt permanente in bd
• nu se mai poate reveni la starea anterioara
• toti userii vad rezultatele
• sunt eliberate randurile (nu mai sunt locked)
• sunt sterse toate savepoint-urile anterioare
8
SGBD

Atentie!
• Dacă nu se execută explicit tranzacţia şi programul se termină anormal, ultima tranzacţie
executată va fi anulată.
• Utilizatorul ar trebui sa termine explicit tranzactiile folosind COMMIT ori ROLLBACK.
• ORACLE asigura consistenta datelor la citire, asa incat toti utilizatorii sa aiba o vedere
consistenta asupra datelor in orice moment.

Exemplu:
DELETE FROM employees WHERE employee_id = 99999;
INSERT INTO departments VALUES (290, 'Corporate Tax', NULL, 1700);
COMMIT;
DELETE FROM copy_emp;
ROLLBACK;

Dupa COMMIT:
• se sterge angajatul cu id 99999
• se insereaza un nou rand in departments (doar daca noile valori respecta constrangerile tabelului
departments)
• datele sunt un-locked.
Dupa ROLLBACK:
• se anuleaza stergerea tabelului copy_emp
• datele sunt un-locked.

Puncte de salvare
• Punctele de salvare (savepoints) permit utilizatorului să reţină toată munca sa la orice moment
din timp, cu opţiunea de a înregistra mai târziu totul sau a anula totul sau o parte din ea.
• Astfel, pentru o tranzacţie lungă, se pot salva părţi din ea, pe măsura execuţiei, la sfârşit
înregistrându-se sau refăcându-se conţinutul iniţial.
• Dincolo de un punct de salvare, daca apare o comanda de revenire, tranzactia este adusa la starea din
punctul de salvare. Toate instructiunile care au fost executate pana in acest punct de salvare sunt
salvate.
• La crearea unui nou punct de salvare cu acelaşi nume ca al unuia dinainte, primul punct este
şters.
• Numărul maxim de puncte de salvare pentru un proces utilizator este implicit 5.
o Aceasta limită poate fi schimbată.
• Avantaj folosire puncte de salvare: la apariţia unei erori nu trebuie executat din nou fiecare bloc.

SAVEPOINT - Poate fi utilizat pentru a împărţi o tranzacţie în bucăţi mai mici.

Sintaxa:
SAVEPOINT nume_savepoint

Exemplu :
SAVEPOINT terminare_actualizari

9
SGBD

..............
ROLLBACK to SAVEPOINT nume_punct_salvare

Exercitii
Creati tabelul my_employee folosind instructiunea de mai jos:

CREATE TABLE my_employee


(id NUMBER(4) CONSTRAINT my_employee_id_nn NOT NULL,
last_name VARCHAR2(25),
first_name VARCHAR2(25),
salary NUMBER(9,2));

1. Debifati Autocommit din tabul SQL Commands SAU deschideti un script si completati-l cu
comenzile de la punctele urmatoare
2. Creati o secventa care incepe de la 1, pasul de incrementare este 1 iar valoarea maxima 10.
Denumiti secventa myemp_seq.
3. Inserati in my_employee 3 inregistrari (folositi secventa creata la pasul 2):
1. Mark Smith, 500
2. Bob Stark, 1200
3. William Reeves,850
4. Modificati numele angajatului 3 in Drexler.
5. Modificati salariul angajatilor care castiga mai putin de 900 la 1000.
6. Stergeti pe William Drexler din my_employee.
7. GOLITI tabela.
8. Executati COMMIT pentru a face modificarile permanente.

10
SGBD

Laborator 5
Aplicatii cu SQL
Dictionarul de date ORACLE

Aplicatii cu SQL
Sunt aplicații scrise in limbaje de nivel inalt, numite limbaje gazda, ex.C, C ++, Java, C#, ...
care trebuie:
• sa administreze datele de intrare
o optiunile utilizatorilor, diversi parametri
• sa gestioneze logica aplicației
o fluxul operațiilor ce trebuie executate
• sa returneze utilizatorilor diverse rezultate, folosind formate diferite
o documente XML, grafice, rapoarte, etc.

Pentru astfel de aplicatii, de obicei este necesar accesul la o bază de date.

Comenzile SQL sunt utilizate în aplicații pentru a accesa baza de date si a realiza:
• interogari
• actualizări (DML si DDL)
Principalele tehnici de integrare a limbajului SQL in aplicatii:
• client-side:
o SQL Embedded
o Call Level Interface (CLI)
 SQL / CLI, ODBC, JDBC, OLE DB, ADO.NET, ..
o aplicația este în afara SGBD
o conține toate logica aplicației
o impune ca SGBD-ul sa execute comenzi SQL și să întoarcă rezultatul
o procesează datele returnate de către SGBD
• server-side:
o aplicația este în cadrul SGBD
o procedurile sunt stocate in dictionarul de date
o procedurile contin comenzi SQL si cod aplicatie scris intr-un limbaj procedural propriu
SGBD-ului ales.
 PL/SQL (Oracle), Transact-SQL (Microsoft SQL Server), PL/pgSQL
(PostgreSQL)

SQL Embedded
• Comenzile SQL sunt „integrate“ în aplicatiile scrise cu limbaje de nivel inalt (C, C ++, Java, ..)
• Sintaxa SQL este diferită de cea a limbajelor gazda =>
• Comenzile SQL nu pot fi compilate în mod direct printr-un compilator normal => Precompilator
o identifică comenzile SQL încorporate în codul gazda
 acestea sunt precedate de cuvântul cheie EXEC SQL
o înlocuiește comenzile SQL cu apeluri de functii din API-uri specifice ale SGBD-ului ales
1
SGBD

o trimite comenzile SQL statice catre SGBD pentru pentru compilare și optimizare

Figure 1 Executia SQL Embedded

Figure 2 Exemplu SQL Embedded

Call Level Interface (CLI)


• Cererile sunt trimise la SGBD prin utilizarea unor funcții ale limbajului gazdă
o soluție bazată pe interfețe predefinite: API (Application Programming Interface)
(independent de SGBD)
o comenzile SQL sunt transmise la gazdă ca parametri
o nu este nevoie de un precompilator
• Programul gazdă include în mod direct apelurile către funcțiile oferite de API
• Exemple:
2
SGBD

o ODBC (Open Database Connectivity) - soluție oferita de Microsoft


o JDBC (Java Database Connectivity) - soluție pentru mediul Java
o OLE DB
o ADO.NET
• Structura:
o deschide conexiune la SGBD
o executa comenzile SQL
o inchide conexiune la SGBD

JDBC (Java DataBase Connectivity)


• Soluție CLI pentru mediul JAVA
• Arhitectura cuprinde
o un set de clase standard și interfețe
 folosit de programatorul Java
 independent de SGBD
o un set de drivere
 asigura comunicarea cu un anumit SGBD
 dependente de SGBD
 invocate în timpul rulării
• Interactiunea cu SGBD:
o se incarca driverul specific pentru SGBD
 Object Class.forName(String driverName)
 e.g., “oracle.jdbc.driver.OracleDriver”
o deschide o conexiune
 Connection DriverManager.getConnection(String url, String user, String
password)
• url
o informatia necesara pentru a identifica SGBD-ul catre care se face
conexiunea
o formatul depinde de driver
o executa comenzi SQL
 creeaza o declaratie (Statement)
• Statement createStatement()
 submite comanda pentru executare
• actualizari (DML si DDL)
o int executeUpdate(String SQLCommand)
• interogari:
o ResultSet executeQuery(String SQLCommand)
o ResultSet reprezinta un set de tuplii
 ofera metode pentru
• a parcurge setul de tuplii
o next()
o first()
o ...
• extrage valorile de interes din tuplii
o getInt(String attributeName)

3
SGBD

o getString(String attributeName)
o ....
 proceseaza rezultatul (în cazul interogărilor)
o inchide declarația
 se apeleaza void close() – metoda a unui obiect Statement
o inchide conexiunea
 se apeleaza void close() – metoda a unui obiect Connection

Declaratiile de tip prepared sunt declaratii


• contin simbolul „?“ este folosit pentru a indica faptul ca trebuie specificata valoarea unui
parametru
Exemplu:
PreparedStatement pstmt;
pstmt=conn.prepareStatement(“SELECT SId, NEmployees FROM S WHERE City=?”);
• compilate o singură dată, la începutul execuției programului
• executate de mai multe ori
o valorile curente pentru parametrii trebuie să fie specificate înainte de fiecare execuție
o PreparedStatement prepareStatement(String SQLCommand)
• Executie:
o interogare: ResultSet executeQuery()
o actualizare: int executeUpdate()
.....
PreparedStatement pstmt=conn.prepareStatement(“UPDATE P SET Color=? WHERE PId=?”);

/* Assign color Crimson to product P1 */


pstmt.setString(1, “Crimson”);
pstmt.setString(2, “P1”);
pstmt.executeUpdate();

/* Assign color SteelBlue to product P5 */


pstmt.setString(1, “SteelBlue”);
pstmt.setString(2, “P5”);
pstmt.executeUpdate();

Exemplu: selectia unor angajati din departamentul Accounting


Pentru a rula exemplul, descarcati driver-ul JDBC corespunzator server-ului Oracle instalat pe
calculatorul vostru (click aici). Mutati apoi arhiva JAR in directorJDK/jre/lib/ext.

import java.io.*;
import java.sql.*;

class AccountingEmployees {
public static void main(String argv[]) {
Connection conn;
Statement stmt;
ResultSet rs;
4
SGBD

String query;
String varDept;

/* inregistrare driver */
try {
Class.forName("oracle.jdbc.driver.OracleDriver");

}
catch(Exception e) {
System.err.println("Driver unavailable: "+e);
}

try {
/* conexiune la baza de date */
conn=DriverManager.getConnection("jdbc:oracle:thin:@127.0.0.1:1521:xe", "student","student");

/* crearea unui Statement */


stmt = conn.createStatement();

/* crearea unei interogari */


varDept ="Accounting";
query="SELECT employee_id, first_name || ' ' || last_name as name FROM employees e join
departments d on e.department_id=d.department_id WHERE department_name = '"+varDept+"'";

/* executia interogarii */
rs=stmt.executeQuery(query);

System.out.println("Angajati in departamentul "+varDept);

/* parcurge tuplii din rezultat */


while (rs.next()) {
System.out.println(+rs.getInt("employee_id")+" "+rs.getString("name"));
}

/* inchide ResultSet, Statement si Connection */


rs.close();
stmt.close();
conn.close();
}
catch(Exception e) {
System.err.println("Error: "+e);
}
}
}

5
SGBD

Conexiunile sunt create implicit cu auto-COMMIT după fiecare execuție cu succes a unei comenzi SQL
comandă.

Atunci când este necesar să se execute un singur COMMIT după o secvență de comenzi SQL, trebuie sa
se anuleze apelul automat al comenzii COMMIT dupa fiecare comanda SQL, ceea ce se realizeaza cu
instructiunea void setAutoCommit(boolean autoCommit);

In cazul in care auto-COMMIT este anulat, trebuie sa se apeleze explicit comenzile void commit(); sau
void rollback()
In concluzie:
• SQL Embedded:
(+) precompileaza interogări SQL statice
(-) depinde de SGBD ales si de sistemul de operare (datorită prezenței unui compilator)
(-) în mod normal nu permite accesul la mai multe baze de date în același timp (sau este o operațiune
complexă)
• Call Level Interface
(+) independent de SGBD ales la momentul compilarii (driver-ul este încărcat și invocat în mod
dinamic la rulare
(+) nu are nevoie de un precompilator
(+) permite accesul la baze de date multiple din cadrul aceleiași aplicații
(-) se folosește SQL dinamic => eficiență mai scăzută
(-) suportă, de obicei, un subset al limbajului SQL
• procedurile stocate
(+) Eficiență mai mare:
fiecare procedura este compilata si optimizata o singura data, dupa definire sau la primul apel
exploatează integrarea strânsă cu SGBD
reduce schimbul de date prin rețea

Dictionarul de date
Schema Oracle

• Schema este o colectie de structuri de date (obiecte)


o schema include obiecte cum ar fi tabele, view-uri, secvente, indecsi, proceduri memorate,
triggers, etc
o obiectele schemei pot fi create si administrate cu SQL
• Fiecare utilizator al bazei de date detine o singura schema, a carei denumire este aceeasi cu cea a
utilizatorului => schema  contul unui utilizator
• Pentru a accesa un obiect din schema altui utilizator, acesta trebuie prefixat cu denumirea celui
care detine schema
• Consultati https://docs.oracle.com/cd/B19306_01/server.102/b14220/schema.htm pentru
descrieri detaliate ale obiectelor unei scheme pe server-ul Oracle

Urmatoarele tipuri de obiecte pot fi create intr-o baza de date dar nu fac parte dintr-o schema: roluri,
utilizatori

6
SGBD

Dictionarul de date

• Fiecare baza de date Oracle are un dictionar al datelor, creat odata cu baza de date
• Un dictionar al datelor Oracle este un set de tabele si view-uri de sistem care sunt folosite ca
referiri read-only asupra bazei de date.
• Dictionarul de date va va spune:
o numele utilizatorilor ORACLE
o drepturile si privilegiile care le-au fost acordate
o numele obiectelor bazei de date (tabele, vederi, indecsi, sinonime,secvente,...)
o constrangeri aplicate tabelei
o informatii de revizie: cine a accesat si actualizat obiectele bazei de date specificate.
• Pentru a reflecta cu acuratete starea bazei de date in orice moment, dictionarul este automat
actualizat de Oracle ca raspuns la actiunile specifice (cum ar fi modificarea structurii bazei de
date).
• Dictionarul este critic pentru operatiile bazei de date. De exemplu, in timpul operarii bazei de
date, Oracle citeste dictionarul pentru a verifica daca obiectele schemei exista si daca utilizatorii
au drepturi corespunzatoare de acces

Tabelele si vederile Dictionarului de Date

• Tabele

Tabelele dictionarului de date sunt create automat de declaratia SQL CREATE DATABASE si nu sunt
in posesia utilizatorului SYS. Tabelele de baza sunt rareori accesate direct, deoarece informatia din ele
nu este usor de inteles.

• Vederi

Vederile dictionarului de date contin informatii intr-o forma care este usor de inteles pentru utilizator.
Accesul public la dictionarul de date este dat prin vederi mai degraba decat prin tabele de baza.

Vederile au fost numite pentru a reflecta tipul de utilizare dorit. Vederile sunt clasificate in 3 grupe
distingandu-se intre ele prin prefixele USER, ALL si DBA.

Cele trei clase de vederi sunt:

USER_xxxxx
Obiectele detinute de utilizator ce pot fi accesate. De exemplu, vederile cu acest prefix permit
utilizatorului sa afiseze informatii despre tabelele create de utilizator si privilegiile acordate de utilizator.

ALL_xxxxx
Utilizatorii pot accesa obiecte la care au drepturi de acces, pe langa obiectele pe care le detin.

DBA_xxxxx
Pentru utilizare de catre utilizatori cu privilegiu DBA - pot accesa orice obiect in baza de date.

7
SGBD

Consultati https://docs.oracle.com/cd/E11882_01/nav/catalog_views.htm pentru descrieri detaliate ale


vederilor din dictionarul de date Oracle.
Table 1 Exemple de vederi ale utilizatorului curent
Obiecte ale utilizatorului curent Tabel din dictionarul de date
Tabele USER_TABLES
ALL_TABLES
Coloanele tabelelor USER_TAB_COLUMNS
ALL_TAB_COLUMNS
Comentarii Comentariile pe coloanele tabelelor:
USER_COL_COMMENTS
ALL_COL_COMMENTS
Comentariile pe tabele:
USER_TAB_COMMENTS
ALL_TAB_COMMENTS
Constrangeri USER_CONS_COLUMNS
• C - Check constraint on a table USER_CONSTRAINTS
• P - Primary key
• U - Unique key ALL_CONS_COLUMNS
• R - Referential integrity ALL_CONSTRAINTS
• V - With check option, on a view
• O - With read only, on a view

Indecsi USER_INDEXES
USER_IND_COLUMNS

ALL_INDEXES
ALL_IND_COLUMNS
Secvente USER_SEQUENCES
ALL_SEQUENCES
Vederi USER_VIEWS
ALL_VIEWS
USER_UPDATABLE_COLUMNS
Obiecte USER_OBJECTS
ALL_OBJECTS
Trigger USER_TRIGGERS
ALL_TRIGGERS
Proceduri stocate USER_PROCEDURES
ALL_PROCEDURES

Exemple:
Date despre tabelele utilizatorului curent:
SELECT * FROM user_tables;
SELECT * FROM all_tables WHERE owner=’CSERBAN’;

8
SGBD

Comentariile pe tabele utilizatorului curent:


SELECT * FROM user_tab_comments;
SELECT * FROM all_tab_comments WHERE owner=’CSERBAN’;

Coloanele dintr-un tabel asociate cu o constrangere:


SELECT constraint_name, column_name
FROM user_cons_columns
WHERE table_name = 'EMPLOYEES'

Constrangerile (nume, tip, expresie) dintr-un tabel:


SELECT *
FROM user_constraints
WHERE table_name = 'EMPLOYEES';

Informatii despre secventele create:


SELECT sequence_name, min_value, max_value, increment_by, last_number
FROM user_sequences;

Numele si textul vederilor:


SELECT view_name, text FROM user_views;

Descrierea trigger-ilor:
SELECT description FROM user_triggers;

Informatii despre procedurile stocate:


SELECT * FROM user_procedures;

Exercitii

1. Confirmati ca tabelele DEPT si EMP se gasesc in schema voastra.


2. Aflati utilizatorii BD care au comentarii setate pe tabela EMPLOYEES. Vizualizati si
comentariile.
3. Aflati daca tabela EMPLOYEES din schema voastra are cheie primara si care este coloana pe
care este setata aceasta constrangere. Folositi: a) clasa de vederi ALL_xxxxx b) clasa de vederi
USER_xxxxx
4. Aflati tabelele din schema voastra care nu au cheie primara. Utilizati operatorul SQL MINUS

Operatorul SQL MINUS este utilizat pentru a returna toate rândurile din prima instrucțiune
SELECT care nu sunt returnate de a doua instrucțiune SELECT .Sintaxa: SELECT......MINUS
SELECT.....

5. Determinati tablele din schema voastra care nu au chei straine. Utilizati clasa de vederi
USER_xxxxx.
9
SGBD

6. Determinati coloanele chei straine ale tabelei JOB_HISTORY din schema voastra. Folositi clasa
de vederi ALL_XXX. Afisati tabelul, proprietarul, denumirea constrangerii tip cheie straina,
coloana cheie straina, tabelul referit, denumirea constrangerii cheii primare referite.
7. Cerinta de la ex.6, afisati in plus si coloana cheie primara referita.
8. Afisati toate datele constrangerilor de tip cheie straina care refera tabelul EMPLOYEES (aflati
tabelele care refera tabelul EMPLOYEES din schema voastra).
9. Determinati coloanele actualizabile dintr-o vedere (view).
10. Determinati coloanele cu constrangeri NOT NULL din tabelul EMPLOYEES din schema
voastra.
11. Determinati tabelele din schema voastra care nu au nicio constrangere NOT NULL.
12. Aflati indecsii tabelelor din schema voastra si coloanele pe care sunt creati. Utilizati clasele de
vederi USER_xxxxx si ALL_xxxxx.
13. Determinati coloanele de tip NUMBER ale tabelului EMPLOYEES din schema voastra. Utilizati
clasa de vederi ALL_xxxxx.
14. Determinati ce tip de date au cheile primare ale tabelelor din schema voastra. Utilizati clasa de
vederi ALL_xxxxx.

Alte vederi din dictionarul de date, ce ofera informatii despre obiectele detinute de utilizatorul curent,
precum si despre obiectele la care acesta are drepturi de acces.

* grantee: denumirea utilizatorului/rolului care a primit un privilegiu (drept de acces)


**grantor: denumirea utilizatorului care a acordat privilegiul

.
Numele Tabelului Comentarii
-------------- ----------

ALL_CATALOG Toate tabelele, vederile, sinonimele, secven-


tele accesibile utilizatorului

ALL_COL_COMMENTS Comentarii pe coloanele tabelelor si vederi-


le accesibile

ALL_COL_PRIVS Permisiuni pe coloanele pentru care utiliza-


torul este "grantor", "grantee", proprietar,
sau un rol posibil sau PUBLIC este "grantee"

ALL_COL_PRIVS_MADE Permisiuni pe coloanele pentru care utiliza-


e proprietar sau "grantor"

ALL_COL_PRIVS_RECD Permisiuni pe coloanele pentru care utiliza-


torul, PUBLIC sau rolul posibil este "gran-
tee"

ALL_CONSTRAINTS Definitii de constrangeri pe tabele accesi-


bile

ALL_CONS_COLUMNS Informatii despre coloanele accesibile in

10
SGBD
definitiile de constrangeri

ALL_DB_LINKS Legaturile bazei de date accesibile utiliza-


torului

ALL_DEF_AUDIT_OPTS Optiuni de revizuire pentru noile obiecte


create

ALL_DEPENDENCIES Dependente dinspre si inspre obiectele acce-


sibile utilizatorului

ALL_ERROR Erorile curente pe obiectele stocate la care


utilizatorul este permis sa creeze

ALL_INDEXES Descrierea indecsilor pe tabelele accesibile


utilizatorului

ALL_IND_COLUMNS Coloanele cuprinzand indecsi pe tabele acce-


sibile

ALL_OBJECTS Obiectele accesibile utilizatorului

ALL_SEQUENCES Descrierea SEQUENCE-urilor accesibile utili-


zatorului

ALL_SNAPSHOTS Instantanee la care poate privi utilizatorul

ALL_SOURCE Sursa curenta a obiectelor create pe care u-


tilizatorul are permisiunea sa le creeze

ALL_SYNONYMS Toate sinonimele accesibile utilizatorului

ALL_TABLES Descrierea tabelelor accesibile utilizatoru-


lui

ALL_TAB_COLUMN Coloanele tuturor tabelelor, vederilor si


clusterelor

ALL_TAB_COMMENTS Comentarii pe tabele si vederi accesibile u-


tilizatorului

ALL_TAB_PRIVS Permisiuni pe obiecte pentru care utilizato-


rul e "grantor", "grantee" sau proprietar,
sau un rol posibil sau PUBLIC garantie

ALL_TAB_PRIVS_MADE Permisiunile utilizatorilor si permisiuni pe


obiectele utilizatorilor

ALL_TAB_PRIVS_RECD Permisiuni pe obiecte pentru care utilizato-


rul, PUBLIC sau un rol posibil este "gran-
tee"

ALL_TRIGGERS TRIGGER-uri accesibile utilizatorului curent

ALL_TRIGGER_COLS Utilizarea coloanelor in trigger-ul utiliza-


torilor sau in trigger-uri pe tabelele uti-
lizatorilor

11
SGBD

ALL_USERS Informatii despre toti utilizatorii bazei de


date

ALL_VIEWS Textul vederilor accesibile utilizatorilor

AUDIT_ACTIONS Tabela de descriere pentru actiunea de urma-


rire a reviziei tipului de coduri

CAT Sinonim cu USER_CATALOG

CLU Sinonim cu USER_CLUSTERS

COLS Sinonim cu USER_TAB_COLUMNS

COLUMN_PRIVILEGES Permisiuni pe coloane pentru care utilizato-


rul e "grantor", "grantee", proprietar, sau
un rol posibil sau PUBLIC este "grantee"

DICT Sinonim cu DICTIONARY

DICTIONARY Descrierea tabelelor si vederilor Dictiona-


rului de Date

GLOBAL_NAME Numele bazei de date globale

IND Sinonim pentru USER_INDEXES

INDEX_HISTOGRAM Statistica pe chei cu numarare repetata

INDEX_STATS Statistica pe arbori-B

OBJ Sinonim pentru USER_OBJECTS

RESOURCE_COSTS Costul fiecarei resurse

ROLE_ROLE_PRIVS Roluri permise rolurile

ROLE_SYS_PRIVS Privilegiile sistem permise rolurilor

ROLE_TAB_PRIVS Privilegii de tabela permise rolurilor

SEQ Sinonim pentru USER_SEQUENCES

SESSION_PRIVS Privilegii pe care utilizatorul le-a setat


in mod curent

SESSION_ROLES Roluri pe care utilizatorul le-a facut posi-


bile in mod curent

SYN Sinonim pentru USER_SYNONYMS

TABLE_PRIVILEGES Alocatii pe obiecte pe care utilizatorul


este "grantor", "grantee", posesor, sau un
rol facut posibil, sau PUBLIC este "gran-
tee-ul"

12
SGBD

TABS Sinonim pentru USER_TABLES

USER_AUDIT_OBJECTS Inregistrarea urmelor examinate pentru de-


claratii referitoare la obiecte, si anume:
tabel, cluster, vedere, index, secventa,
legatura bazei de date [publica], sinonim
[public], procedura, trigger, segment roll-
back, spatiu de tabela, rol, utilizator

USER_AUDIT_STATEMENT Inregistrarea urmelor examinate referitoare


la alocatie, anulare, examinare, neexamina-
re si sistem modificat

USER_AUDIT_TRAIL Intrari ale urmelor revizuite, relevante u-


tilizatorului

USER_CATALOG Tabele, vederi, sinonime si secvente detinute


de utilizator

USER_CLU_COLUMNS Maparea coloanelor tabelei pentru a aduna


impreuna coloanele

USER_COL_COMMENTS Comentarii despre coloanele tabelelor si ve-


derile utilizatorului

USER_COL_PRIVS Permisiuni pe coloanele pentru care utiliza-


torul este posesorul, "grantor" sau "gran-
tee"

USER_COL_PRIVS_MADE Toate permisiunile pe coloanele obiectelor


detinute de utilizator

USER_COL_PRIVS_RECD Permisiuni pe coloane pentru care utilizato-


rul este "grantee"

USER_CONSTRAINTS Definitiile constrangerilor pe tabelele uti-


lizatorului

USER_CONS_COLUMNS Informatii despre coloanele accesibile in


definitiile constrangerilor

USER_DB_LINKS Legaturile bazei de date detinute de utili-


zator

USER_DEPENDENCIES Dependente dinspre si inspre obiectele uti-


lizatorilor

USER_ERRORS Erori curente pe obiecte stocate, detinute


de utilizator

USER_EXTENTS Extensii cuprinzand segmente ale utilizato-


rului

USER_FREE_SPACE Extensii libere in spatiul tabelelor accesi-

13
SGBD
bile utilizatorului

USER_INDEXES Descrierea indecsilor utilizatorului

USER_IND_COLUMNS Coloanele cuprinzand indecsi ai utilizatoru-


lui sau pe tabele ale utilizatorului

USER_OBJECTS Obiecte detinute de utilizator

USER_OBJECT_SIZE Dimensiuni, in octeti, a diferitelor obiecte


pl/sql

USER_OBJ_AUDIT_OPTS Optiuni de revizuire pentru tabelele si vede-


rile utilizatorului

USER_RESOURCE_LIMITS Afiseaza limita resurselor utilizatorului

USER_ROLE_PRIVS Roluri permise utilizatorului curent

USER_SEGMENTS Spatiu de stocare alocat pentru segmentele


bazei de date

USER_SEQUENCES Descrierea SEQUENCE-lor utilizatorului

USER_SNAPSHOTS Instantanee pe care utilizatorul le poate ve-


dea

USER_SNAPSHOTS_LOGS Toate jurnalele instantanee detinute de uti-


lizator

USER_SOURCE Sursa obiectelor stocate accesibile utiliza-


torului

USER_SYNONYMS Sinonimele private ale utilizatorului

USER_SYS_PRIVS Privilegii de sistem permise utilizatorului


curent

USER_TABLES Descrierea tabelelor utilizatorului

USER_TABLESPACES Descrierea spatiilor tabelelor accesibile

USER_TAB_COLUMNS Coloane ale tabelelor, vederilor si clustere-


lor utilizatorului

USER_TAB_COMMENTS Comentarii despre tabelele si vederile pose-


date de utilizator

USER_TAB_PRIVS Permisiuni pe obiecte pentru care utilizato-


rul este posesorul, "grantor-ul", sau "gran-
tee-ul"

USER_TAB_PRIVS_MADE Toate permisiunile pe obiecte detinute de u-


tilizator

USER_TAB_PRIVS_RECD Permisiuni pe obiecte pentru care utilizato-

14
SGBD
rul este "grantee-ul"

USER_TRIGGERS Tigger-uri detinute de utilizator

USER_TRIGGER_COLS Folosirea coloanei in trigger-ul utilizatoru-


lui

USER_TS_QUOTAS Cota spatiului de tabela pentru utilizator

USER_USERS Informatii despre utilizatorul curent

USER_VIEWS Text de vederi detinut de utilizator

15
SGBD

Laborator 7
PL/SQL
PL/SQL este extensia procedurala a limbajului SQL, cu trasaturi specifice limbajelor de programare.

El permite ca manipularea datelor si procedurile de interogare din SQL sa fie incluse in blocuri
stucturate si proceduri, PL/SQL devenind astfel un puternic limbaj de procesare a tranzactiilor.

Caracteristici principale:

o Stuctura de bloc: PL/SQL este un limbaj structurat, adica programele pot fi impartite in
blocuri logice, fiecare continand resursele necesare in acel bloc. variabilele pot fi
declarate local in cadrul blocului in care vor fi folosite, iar tratarea erorilor (sau
Exceptiile) se poate face in blocul in care apar

o Controlul executiei: Deciziile si buclele pot fi folosite pentru a controla executia


programelor.

o Portabilitatea: Deoarece PL/SQL deriva din ORACLE, programele pot fi portate pe toate
masinile ce suporta ORACLE si PL/SQL.

o Integrarea: PL/SQL joaca un rol din ce in ce mai important in aplicatiile ORACLE.


Variabilele si tipurile de date din PL/SQL sunt compatibile cu cele din SQL. PL/SQL
acopera golul dintre nevoia de access la tehnologia bazelor de date si nevoia de facilitati
pentru programarea procedurala.

1. Blocuri anonime PL/SQL

• Programele PL/SQL sunt formate din unitati de cod numite blocuri. Acestea pot fi secventiale
sau imbricate (bloc ın bloc).
• Un program poate cuprinde unul sau mai multe blocuri. Un bloc poate fi anonim sau neanonim.
o Blocurile anonime sunt blocuri PL/SQL fara nume, care sunt construite dinamic si sunt
executate o singura data. Acest tip de bloc nu are argumente si nu returneaza un rezultat
o Blocurile neanonime sunt fie blocuri având un nume (etichetate), care sunt construite
static sau dinamic si sunt executate o singura data, fie subprograme sau declansatori
(triggers)
• Un bloc PL/SQL este compus din maxim 3 secţiuni:
o declarativă (opţională)
o executabilă (obligatorie) şi
o de tratare a excepţiilor (opţională).

1
SGBD

• Structura unui bloc anonim PL/SQL este data de urmatoarea schema:

[DECLARE
/∗ declarare si eventual initializare de variabile,cursoare, exceptii
definite de utilizator ∗/ ]

BEGIN
/∗ instructiuni SQL sau PL/SQL ∗/

[EXCEPTION
/∗ actiuni de efectuat atunci cand apar erori ∗/ ]
END;

2. Instructiuni de iesire
• Deoarece limbajul PL/SQL nu are implementate instructiuni de intrare/iesire se folosesc
functionalitati Oracle in acest sens.
o se utilizeaza SET SERVEROUTPUT ON pentru activarea modului afisare.
• Pentru a afisa mesaje se foloseste instructiunea DBMS_OUTPUT.PUT_LINE() ca in exemplul
de mai jos:

DBMS_OUTPUT.PUT_LINE( ‘ Prenumele angajatului este ‘ | | v_fname ) ;

/*Exemplu de bloc anonim PL/SQL care afiseaza continutul unei variabile locale*/
DECLARE
v_myname VARCHAR2(20);
BEGIN
DBMS_OUTPUT.PUT_LINE('My name is: '||v_myname);
v_myname := 'John';
DBMS_OUTPUT.PUT_LINE('My name is: '||v_myname);
END;

/*Exemplu: care afiseaza numele unui angajat cu id cunoscut*/


DECLARE
v_fname VARCHAR2(20);
BEGIN
SELECT first_name INTO v_fname FROM employees WHERE employee_id = 100;
DBMS_OUTPUT.PUT_LIne(v_fname);
END;

/*Exemplu care afiseaza idul unei tari cunoscute*/


DECLARE
country_id CHAR(2);
BEGIN
SELECT country_id INTO country_id FROM countries WHERE country_name =
'Canada';
DBMS_OUTPUT.PUT_LINE(country_id);
END;

2
SGBD

/*Exemplu de folosire a functiilor SQL pentru date calendaristice in PL/SQL */


DECLARE
v_new_date DATE;
v_num_months NUMBER := 6;
BEGIN
v_new_date := ADD_MONTHS(SYSDATE,v_num_months);
DBMS_OUTPUT.PUT_LINE(v_new_date);
END;

Observatii:

• Se pune ; dupa fiecare instrucţiune SQL sau instr.de control PL/SQL


• Cuvintele cheie de delimitare a secţiunilor DECLARE, BEGIN si EXCEPTION nu sunt urmate
de ;. END şi celelalte instrucţiuni PL/SQL au nevoie de acest delimitator.
• Exista doua tipuri de comentarii:
o pe o singura linie, prefixate de simbolurile “--”, care încep în orice punct al liniei si se
termina la sfârsitul acesteia
o pe mai multe linii, care sunt delimitate de simbolurile “/*” si “*/”.
• Instructiunea de atribuire ın PL/SQL este “:=”, dupa cum se poate observa in exemplele de mai
sus.

Denumire_var := expresie ;

3. Tipuri de date scalare


Nu au componente interne (contin valori atomice). Se împart în 5 clase.

• Tipurile de date ce stocheazq valori numerice cuprind

o tipul NUMBER cu subtipurile DEC, DECIMAL, DOUBLE PRECISION, FLOAT, INTEGER,


INT, NUMERIC, REAL, SMALLINT;
o tipul BINARY_INTEGER cu subtipurile NATURAL, NATURALN, POSITIVE, POSITIVEN,
SIGNTYPE;
o tipul PLS_INTEGER.

• Tipurile de caractere date ce stocheaza cuprind

o tipul VARCHAR2 cu subtipurile STRING, VARCHAR;


o tipul de date CHAR cu subtipul CHARACTER;

• Tipurile de date ce stocheaza data calendaristica si ora cuprind tipurile DATE, TIMESTAMP,

TIMESTAMP WITH TIME ZONE, TIMESTAMP WITH LOCAL TIME ZONE, INTERVAL YEAR TO
MONTH, INTERVAL DAY TO SECOND.

• Tipurile de date globalizare ce stocheaza date unicode includ tipurile NCHAR si NVARCHAR2.
• Tipul de date BOOLEAN stocheaza valori logice (true, false sau null).

Obs : Mai mute informatii despre tipurile de date PL/SQL la


http://www.stanford.edu/dept/itss/docs/oracle/9i/appdev.920/a96624/03_types.htm
3
SGBD

4. Variabile simple
• Declararea variabilelor se face ın partea declarativa a blocurilor.

Denumire_var [CONSTANT] tip de data [NOT NULL] [:= expresie ];

Observatii:

• Pentru usurinta referirii se convine prefixarea numelor de variabile astfel:


o prefixarea cu litera v (v_valoare) pentru varibilele PL/SQL
o prefixarea cu litera c (c_valoare) pentru constante
• Variabilele pot fi initializate, iar daca o variabila nu este initializata, valoarea implicita a acesteia
este NULL. Daca o variabila este declarata NOT NULL, atunci ea va fi obligatoriu initializata.

Exemple:
v_hiredate DATE;
v_deptno NUMBER(2) NOT NULL := 10;
v_location VARCHAR2(13) := ’Atlanta’ ;
c_comm CONSTANT NUMBER := 1400;
v_orderdate DATE := SYSDATE;
c_tva CONSTANT NUMBER(3,2) := 0.24;
v_valid BOOLEAN NOT NULL := TRUE;

• In contextul lucrului cu baze de date apare frecvent situatia in care o variabila este folosita pentru
a stoca valori obtinute din campuri ale tabelelor.
o Atributul %TYPE permite definirea unei variabile având tipul unei variabile declarate
anterior sau tipul unei coloane dintr-un tabel

Denumire_var1 tabel.coloana%TYPE;

sau

Denumire_var2 Denumire_var1%TYPE;

Exemple:
v_lname employees.last_name%TYPE; --declararea var.v_lname de tipul campului
-- last_name din tabelul employees
v_salariu NUMBER(7,2);
v_salariu_min v_salariu%TYPE := 1000;

4
SGBD

/*Exemplu de blocuri imbricate.


Variabilele care sunt declarate in blocul exterior se vad si in blocul interior, nu si invers. Cele declarate
in blocul interior sunt locale acestuia.*/

DECLARE
v_father_name VARCHAR2(20):='Patrick';
v_date_of_birth DATE:='03/20/1972';
BEGIN
DECLARE
v_child_name VARCHAR2(20):='Mike';
v_date_of_birth DATE:='12/12/2002';
BEGIN
DBMS_OUTPUT.PUT_LINE('Father''s Name: '||v_father_name);
DBMS_OUTPUT.PUT_LINE('Date of Birth: '||v_date_of_birth);
DBMS_OUTPUT.PUT_LINE('Child''s Name: '||v_child_name);
END;
DBMS_OUTPUT.PUT_LINE('Date of Birth: '||v_date_of_birth);
END;

5. Variabile de legatura (bind)


• Sunt folosite pentru transferul la executie al valorilor numerice sau de tip caracter în/din unul
sau mai multe programe PL/SQL
• Se noteaza prefixate de :

/*Exemplul urmator afiseaza salariul unui angajat al carui id este cerut de la tastatura*/

DECLARE
emp_salary NUMBER;
BEGIN
SELECT salary INTO emp_salary
FROM employees WHERE employee_id = :empno;
DBMS_OUTPUT.PUT_LINE(emp_salary);
END;

6. Variabile de substitutie

• Sunt folosite pentru a prelua informatii de la utilizator in timpul rularii.


• Se noteaza prefixate de &

Exemplu:
% SQL Developer
ACCEPT p_cod_dep PROMPT “Introduceti codul departamentului “;

DECLARE
v_cod_dep departments.department_id%TYPE := &p_cod_dep;

5
SGBD

7. Instructiuni SQL in PL/SQL


In PL/SQL se pot folosi:

1. Instructiunea SELECT
2. Instructiuni DML (INSERT, UPDATE, DELETE)
3. Instructiuni de control a tranzactiilor (COMMIT, ROLLBACK)

NU se pot folosi instructiuni DDL (CREATE, ALTER, DROP) si nici DCL (GRANT, REVOKE) in
mod direct in PL/SQL

• La folosirea instructiunilor SELECT, este obligatoriu de folosit clauza INTO – pentru a preciza
numele variabilelor in care sa se depuna rezultatele SELECT=ului.
o Interogarea trebuie sa returneze un singur rand.
o Daca interogarea returneaza mai multe randuri, se va genera eroare. In acest caz,
manipularea rezultatului interogarii se face diferit (nu doar cu “INTO variabila”).

/* Exemplu in care se afiseaza numele unei tari */


DECLARE
v_country_name countries.country_name%TYPE;
BEGIN
SELECT country_name INTO v_country_name
FROM countries WHERE country_id= 'CA';
DBMS_OUTPUT.PUT_LINE(' The country name is : '||v_country_name);
END;
/

/* Exemplu in care se afiseaza date despre un angajat. */


DECLARE
v_emp_hiredate employees.hire_date%TYPE;
v_emp_salary employees.salary%TYPE;
BEGIN
SELECT hire_date, salary
INTO v_emp_hiredate, v_emp_salary
FROM employees
WHERE employee_id = 100;
DBMS_OUTPUT.PUT_LINE('Hiredate is: ' || v_emp_hiredate ||
' and Salary is: ' || v_emp_salary);
END;
/
/* Exemplu care foloseste functie de agregare */
DECLARE
v_sum_sal NUMBER(10,2);
v_deptno NUMBER NOT NULL := 60;
BEGIN
SELECT SUM(salary)
INTO v_sum_sal FROM employees
WHERE department_id = v_deptno;
DBMS_OUTPUT.PUT_LINE ('The sum of salary is '|| v_sum_sal);
END;
/
6
SGBD

8. Functii SQL ın PL/SQL


• Cu exceptia functiilor DECODE si de grup, toate celelalte functii SQL se pot folosi in
instructiuni procedurale PL/SQL.

DECLARE
v_size INTEGER(5);
v_sequence VARCHAR2(70) := ’ Hello world ! ’ ;
v_date DATE := TO_DATE( ’November 22 , 2011 ’ , ’Month DD, YYYY’ ) ;
BEGIN
V_size := LENGTH( v_sequence ) ;
DBMS_OUTPUT.PUT_LINE(v_size);
END;

9. Comenzi SQL in PL/SQL


• Instructiunea SELECT poate fi folosita ın cadrul instructiunilor procedurale doar ımpreuna cu
clauza INTO.
• Rezultatul interogarii trebuie sa fie format din exact un rand.
• De asemenea, instructiuni DML pot sa apara ın blocuri PL/SQL.

BEGIN
INSERT INTO copy_emp
(employee_id, first_name, last_name, email,
hire_date, job_id, salary)
VALUES (99, 'Ruth', 'Cores',
'RCORES', SYSDATE, 'AD_ASST', 4000);
END;
/
DECLARE
v_sal_increase employees.salary%TYPE := 800;
BEGIN
UPDATE copy_emp
SET salary = salary + v_sal_increase
WHERE job_id = 'ST_CLERK';
END;
/
DECLARE
v_deptno employees.department_id%TYPE := 10;
BEGIN
DELETE FROM copy_emp
WHERE department_id = v_deptno;
END;
/

7
SGBD

Exercitii
Creati tabelele EMP_name, DEPT_name, JOBS_name, LOCATIONS_name, pe baza tabelelor
EMPLOYEES, DEPARTMENTS, respectiv JOBS (structura si date), unde name este numele vostru!

1. Se considera urmatorul bloc PL/SQL:


DECLARE
v_cantitate NUMBER(3) := 300;
v_mesaj VARCHAR2(255) := ‘Produs 1’;
BEGIN
DECLARE
v_cantitate NUMBER(3) := 1;
v_mesaj VARCHAR2(255) := ‘Produs 2’;
v_locatie VARCHAR2(50) := ‘Europa’;
BEGIN
v_cantitate := v_cantitate + 1;
v_locatie := v_locatie || ‘de est’;
END;
v_cantitate:= v_cantitate + 1;
v_mesaj := v_mesaj ||’ se afla in stoc’;
v_locatie := v_locatie || ‘de est’ ;
END;
/

Evaluati:
- valoarea variabilei v_cantitate în subbloc
- valoarea variabilei v_locatie la pozitia în subbloc
- valoarea variabilei v_cantitate în blocul principal
- valoarea variabilei v_mesaj în blocul principal
- valoarea variabilei v_locatie în blocul principal.
2. Creati si executati un bloc simplu anonim care afiseaza mesajul “Hello world!”.
3. Adaugati exercitiului anterior o sectiune declarativa. Declarati o variabila “v_today” de tip
DATE initializata cu data curenta si o variabila “v_tomorrow” de tipul lui “v_today”. Calculati
valoarea variabilei “v_tomorrow” (se adauga 1 la “v_today”). Afisati ın continuare valorile celor
doua variabile.
4. Sa se creeze un bloc anonim în care se declara o variabila v_oras de tipul coloanei city
(locations.city%TYPE). Atribuiti acestei variabile numele orasului în care se afla departamentul
având codul 30.
5. Creati un bloc PL/SQL care selecteaza din tabelul DEPT_name id-ul de departament cu valoare
maxima, atribuie aceasta valoare unei variabile “v_max_deptno”, apoi afisati valoarea acestei
variabile.
6. Sa se creeze un bloc PL/SQL care insereaza un nou departament in tabelul DEPT_name. Se va
folosi variabila bind pentru numele departamentului. Codul este dat de valoarea variabilei
calculate anterior (la ex.5) +1. Locatia va avea valoarea null.
7. Actualizati valoarea campului location_id pentru ınregistrarea care a fost adaugata astfel ıncat sa
fie egala cu 3000.
8. Sa se creeze un bloc PL/SQL care sterge departamentul creat la exercitiul 6. Se va folosi un
parametru de substitutie pentru numarul departamentului. Ce se intampla daca se introduce un
cod de departament care nu exista?
8
SGBD

9. Sa se creeze un bloc anonim în care sa se afle media salariilor pentru angajatii al caror
departament este 50. Se vor folosi variabilele v_media_sal de tipul coloanei salary si v_dept de
tipul coloanei department_id.
10. Creati un script anonim in care scrieti o interogare in partea executabila a blocului care
selecteaza numele si salariul angajatului cu id 110 si incarca variabilele v_name si v_emp_sal cu
aceste valori. Declarati doua variabile “v_basic_percent” si “v_pf_percent” de acelasi tip de date
cu v_emp_sal. Initializati-le cu valorile 45, respectiv 12. Cu ajutorul variabilelor v_basic_percent
si v_pf_percent calculati contributia angajatului catre fondul de pensii. Aceasta contributie se
calculeaza ca fiind12% din salariul de baza, care reprezinta 45% din salariu. Afisati un mesaj de
tip "Angajatul ...... cu salariul ...... contribuie la fondul de pensii cu suma de ......"
11. Sa se calculeze suma salariilor pentru un job al carui cod este introdus de utilizator. Cautarea se
va face case-insensitive.

9
SGBD

Laborator 8
Instructiuni PL/SQL

1. Structuri decizionale si repetitive


Instructiunea IF
Permite executarea selectiva a actiunilor ın functie de valoarea de TRUE sau FALSE a unei expresii
logice.

Sintaxa:
IF conditie THEN
instructiuni ;
[ ELSIF conditie THEN
Instructiuni; ]
[ELSE
instructiuni; ]
END IF;

Exemplu:
DECLARE
V_varsta NUMBER := 32;
BEGIN
IF v_varsta < 18 THEN
DBMS_OUTPUT.PUT_LINE( 'MINOR') ;
ELSE
DBMS_OUTPUT.PUT_LINE( 'MAJOR ' ) ;
END IF ;
END;
/
Observatie: Se scrie / pe o linie noua pt.a forta rularea blocului anonim PL/SQL din bufferul SGBD-
ului!

Clauza CASE

• Este implementata in doua moduri: ca expresie sau ca instructiune.


• In ambele situatii se evalueaza o conditie si se ia o decizie: fie se returneaza o valoare, fie se
efectueaza o secventa de instructiuni.

Expresia CASE
Sintaxa:
var:= CASE
WHEN expresie1 THEN rez1
WHEN expresie2 THEN rez2
. . .
[ELSE rez0 ]
END;

1
SGBD

Exemplu:
DECLARE
v_cal CHAR(1):= UPPER(:calificativ);
descriere VARCHAR2(20);
BEGIN
descriere := CASE v_cal
WHEN 'A' THEN 'Foarte Bine '
WHEN 'B' THEN 'Bine '
WHEN 'C' THEN 'Satisfacator '
WHEN 'D' THEN 'Nesatisfacator '
ELSE 'Nu exista acest calificativ '
END;
DBMS_OUTPUT.PUT_LINE( descriere ) ;
END;
/

Instructiunea CASE
Sintaxa
CASE var
WHEN expresie1 THEN instructiuni
WHEN expresie2 THEN instructiuni
. . .
END CASE;
/

Exemplu:
DECLARE
deptid NUMBER;
deptname VARCHAR2(20);
emps NUMBER;
mngid NUMBER:= :mngid;
BEGIN
CASE mngid
WHEN 108 THEN
SELECT department_id, department_name INTO deptid, deptname FROM
departments WHERE manager_id=108;
SELECT count(*) INTO emps FROM employees WHERE department_id=deptid;
WHEN 200 THEN
SELECT department_id, department_name INTO deptid, deptname FROM
departments WHERE manager_id=200;
SELECT count(*) INTO emps FROM employees WHERE department_id=deptid;
ElSE DBMS_OUTPUT.PUT_LINE ('Introduceti mngid 108 sau 200');
deptname:='Unknown';
emps:=0;
END CASE;
DBMS_OUTPUT.PUT_LINE ('You are working in the '|| deptname|| '
department. There are '||emps ||' employees in this department');
END;
/

2
SGBD

2. Structuri repetitive
Sunt de trei feluri:

• simple,
• cu numar cunoscut de pasi,
• cu numar necunoscut de pasi.

Instructiunea LOOP

• Trebuie sa contina obligatoriu clauza EXIT pentru a nu se forma cicluri infinite.

Sintaxa
LOOP
instructiuni ;
EXIT WHEN conditie;
END LOOP;

Exemplu:
Creati o copie a tabelului locations. Denumiti tabelul prefixat cu prenumele vostru; exemplu:
marialocations. Folositi aceasta denumire in codul de mai jos.
DECLARE
countryid marialocations.country_id%TYPE := 'CA';
loc_id marialocations.location_id%TYPE;
counter NUMBER(2) := 1;
new_city marialocations.city%TYPE := 'Montreal';
BEGIN
SELECT MAX(location_id) INTO loc_id FROM marialocations WHERE
country_id = countryid;
LOOP
INSERT INTO marialocations(location_id, city, country_id)
VALUES((loc_id + counter), new_city, countryid);
counter := counter + 1;
EXIT WHEN counter > 3;
END LOOP;
END;
/

Instructiunea WHILE
Sintaxa
WHILE conditie LOOP
instructiuni ;
END LOOP;

Exemplu:
DECLARE
countryid marialocations.country_id%TYPE := 'CT';
loc_id marialocations.location_id%TYPE;
new_city marialocations.city%TYPE := 'CONSTANTA';
counter NUMBER := 1;
3
SGBD

BEGIN
SELECT MAX(location_id) INTO loc_id FROM marialocations
WHERE country_id = countryid;
WHILE counter <= 3 LOOP
INSERT INTO marialocations(location_id, city, country_id)
VALUES((loc_id + counter), new_city, countryid);
counter := counter + 1;
END LOOP;
END;

Instructiunea FOR
Sintaxa:
FOR counter IN [REVERSE] lower_bound..upper_bound LOOP
statement1;
statement2;
. . .
END LOOP;

• Daca este prezenta optiunea REVERSE, iteratia se face în sens invers


• Variabila counter nu trebuie declarata, ea fiind implicit de tip BINARY_INTEGER si este
neidentificata în afara ciclului.
• Pasul are implicit valoarea 1 si nu poate fi modificat.
• Limitele domeniului pot fi variabile sau expresii care pot fi convertite la întreg.

Exemplu:
DECLARE
countryid marialocations.country_id%TYPE := 'CT';
loc_id marialocations.location_id%TYPE;
new_city marialocations.city%TYPE := 'Mangalia';
BEGIN
SELECT MAX(location_id) INTO loc_id FROM marialocations WHERE
country_id = countryid;
FOR i IN 1..3 LOOP
INSERT INTO marialocations(location_id, city, country_id)
VALUES((loc_id + i), new_city, countryid );
END LOOP;
END;

Exercitii
Atentie: in exercitiile de mai jos, prefixati denumirea tabelelor pe care trebuie sa le creati cu
prenumele vostru!

1.Creati si executati un bloc PL/SQL care cere de la tastatura 2 numere. Daca al doilea numar este 0,
rezultatul va fi patratul primului numar (x2), altfel primul numar se va imparti la al doilea, si se va
adauga rezultatului cel de-al doilea numar. Rezultatul va fi retinut intr-o variabila PL/SQL si va fi tiparit
pe ecran.

4
SGBD

2. Creati tabelul "messages" care contine coloana results de tip sir de caractere cu dimensiune maxima
80 de caractere. Intr-un bloc PL/SQL: inserati in noul tabel numerele ıntregi de la 1 la 10 exceptand pe
6 si pe 8 (folositi si functia de conversie to_char!). Folositi instructiunea LOOP.

3. In tabelul EMP_ name adaugati coloana stars de tip sir de caractere cu dimensine maxima 50.
Rezolvati cerintele de mai jos intr-un bloc PL/SQL.
a) Declarati o variabila v_empno de tipul coloanei EMP_name.employee_id si initializati-o cu
valoarea 176.
Declarati o variabila v_asterisk de tipul lui EMP_name.stars si dati valoarea initiala NULL.
Creati o variabila v_sal de tipul coloanei EMP_name.salary.
b) Atribuiti variabilei v_sal valoarea salariului angajatului cu id-ul v_empno.
c) Adaugati la sirul de caractere v_asterisk cate o steluta pentru fiecare 1000 de dolari din salariu
(de exemplu: daca angajatul castiga 9300, atunci se vor adauga 9 stelute).
d) Actualizati coloana stars cu valoarea variabilei v_asterisk (pentru angajatul cu id v_empno).
e) Verificati daca modificarile s-au realizat corect.

4. În functie de o valoare introdusa de utilizator, utilizând comanda CASE se va afisa un mesaj prin
care este specificata ziua saptamânii (a carei abreviere este chiar valoarea respectiva; ex. L pentru Luni,
M pentru Marti, Mi pentru Miercuri etc.). Utilizati cele 2 forme ale comenzii CASE.

5. Creati structura tabelului NUMBERS constând din doua coloane, cod de tip INTEGER ce contine un
contor al înregistrarilor si text de tip VARCHAR2 ce contine un text asociat fiecarei înregistrari. Sa se
introduca 10 de înregistrari în acest tabel: pe coloana cod se vor introduce primele 10 nr naturale
divizibile cu 3, iar pe coloana text se va introduce textul “indice”. Rezolvati cu instr. WHILE.

6. Creati structura tabelului NUMERE constând din doua coloane, cod de tip INTEGER ce contine un
contor al înregistrarilor si text de tip VARCHAR2 ce contine un text asociat fiecarei înregistrari. Sa se
introduca 20 de înregistrari în acest tabel, indicând pe coloana text daca numarul cod este par sau impar.
Rezolvati cu instr. FOR.

7. Sa se creeze un bloc PL/SQL care calculeaza si modifica valoarea comisionului pentru un angajat al
carui cod este dat de la tastatura, pe baza salariului acestuia, astfel:
- daca salariul este mai mic decat 1000$, comisionul va fi 10% din salariu;
- daca salariul ete intre 1000 si 1500$, comisionul va fi 15% din salariu;
- daca salariul depaseste 1500$, comisionul va fi 20% din salariu;
Modificarile se fac în tabelul EMP_name.

5
SGBD

Laborator 9
Tipuri compuse de date
Variabilele cu tipuri de date compuse pot memora simultan mai multe valori. Acestea pot fi:

1. inregistrari (records – similare structurilor din limbajul C): sunt folosite atunci cand se doreste sa
se pastreze valori de tipuri de date diferite
• Se utilizeaza de obicei pentru a crea variabile de tipul unei inregistrari dintr-un tabel ori
view.
2. colectii (date de acelasi tip): tabele INDEX BY

Documentatia extinsa pentru acest laborator:


http://docs.oracle.com/cd/E11882_01/appdev.112/e25519/composites.htm#LNPLS005

Variabilele de tip record


• Tipul de date record este format din campuri care se pot declara individual sau conform unei
submultimi de coloane dintr-un tabel sau vedere

TYPE nume_tip IS RECORD


(nume_câmp1 {tip_câmp | variabila%TYPE | nume_tabel.coloana%TYPE |
nume_tabel%ROWTYPE} [ [NOT NULL] {:= | DEFAULT} expresie1],
(nume_câmp2 {tip_câmp | variabila%TYPE | nume_tabel.coloana%TYPE |
nume_tabel%ROWTYPE} [ [NOT NULL] {:= | DEFAULT} expresie2],…);

Crearea unei variabile record: se defineste tipul compus de date, apoi se declara o variabila de acest tip

Exemplu:
TYPE emp_record_type IS RECORD
(last_name VARCHAR2(25),
job_id VARCHAR2(10),
salary NUMBER(8,2));
emp_record_var emp_record_type;

• Atributul %ROWTYPE se foloseste pentru a declara o variabila record ca fiind o colectie de


coloane dintr-un tabel ori view. Campurile din variabila record vor avea aceleasi nume ca si
coloanele din table sau view.
o se foloseste %ROWTYPE cand nu se cunosc coloanele dinainte, sau cand sunt preluate
informatiile din tabel cu o instructiune SELECT *.

Sintaxa:
DECLARE
nume_record tabel_referit%ROWTYPE;

Exemplu:
emp_record employees%rowtype;

1
SGBD

Oracle9i introduce câteva facilitati legate de acest tip de date.


• Se poate insera (INSERT) o linie într-un tabel utilizând tipul RECORD.
• Se poate actualiza (UPDATE) o linie într-un tabel utilizând tipul RECORD (cu sintaxa SET
ROW)
• se poate regasi si returna sau sterge informatia din clauza RETURNING a comenzilor UPDATE
sau DELETE.

Exemplul 1:
Rulati intai:

create table retired_emps as (select * from employees);


truncate table retired_emps

Apoi:
DECLARE
ver employees%rowtype;
BEGIN
select * into ver from employees where employee_id=100;
insert into retired_emps values ver;
ver.salary := 0;
update retired_emps SET ROW =ver where employee_id=100;
end;
/

select * from retired_emps;

Exemplul 2:
Rulati mai intai:
ALTER TABLE retired_emps ADD leave_date Date;

Apoi:
DECLARE
employee_number retired_emps.employee_id%TYPE:=100;
emp_rec retired_emps%ROWTYPE;
BEGIN
SELECT * INTO emp_rec FROM retired_emps where
employee_id=employee_number;
emp_rec.leave_date:=SYSDATE;
UPDATE retired_emps SET ROW = emp_rec WHERE
employee_id=employee_number;
END;
/
SELECT * FROM retired_emps;

Exemplul 3:
Sa se stearga angajatul având codul 200 din tabelul emp. Sa se retina într-o variabila de tip RECORD
codul, numele, salariul si departamentul acestui angajat (clauza RETURNING). Sa se afiseze
înregistrarea respectiva.
Rulati mai intai:
2
SGBD

drop table emp_student;


create table emp_student as (select * from employees);

Apoi:
DECLARE
TYPE info_ang IS RECORD (
cod_ang NUMBER(4),
nume VARCHAR2(20),
salariu NUMBER(8),
cod_dep NUMBER(4));
v_info_ang info_ang;
BEGIN
DELETE FROM emp_student WHERE employee_id = 200
RETURNING employee_id, last_name, salary, department_id
INTO v_info_ang;
DBMS_OUTPUT.PUT_LINE(‘A fost stearsa linia continand valorile ‘ ||
v_info_ang.cod_ang ||’ ‘||v_info_ang.nume||’ ‘
||v_info_ang.salariu ||’ ‘|| v_info_ang.cod_dep) ;
END;
/

Colectii
• Colectiile permit sa fie prelucrate simultan mai multe valori de acelasi tip.
• Fiecare element are un indice unic, care determina pozitia sa în colectie.
• În PL/SQL exista trei tipuri de colectii:
o tablouri indexate (index-by tables);
o tablouri imbricate (nested tables);
o vectori (varrays sau varying arrays).
• Singura diferenta sintactica între tablourile indexate si cele imbricate este clauza INDEX BY.
Daca aceasta clauza lipseste, atunci tipul este tablou imbricat.
• Atribute si metode ale unei colectii:

Ultimele 3 metode nu sunt valide pentru index-by tables.

3
SGBD

Tablouri indexate (index-by tables)

• Acestea sunt structuri PL/SQL cu doua coloane:


o cheia primara: poate fi de tip intreg (BINARY INTEGER, PLS INTEGER) sau sir de
caractere si este folosita pentru acces la liniile tabloului
o o coloana care include valoarea efectiva a elementelor tabloului, care pot fi valori scalare
sau de tip record
• Elementele unui tablou indexat nu sunt într-o ordine particulara si pot fi inserate cu chei
arbitrare.
• Tablourile INDEX BY nu au restrictii la dimensiune: pot avea atatea elemente cat permite tipul
de data al cheii.
• Dimensiunea tablourilor INDEX BY creste dinamic, in urma adaugarii de elemente.
• Tabloul indexat PL/SQL nu poate fi initializat în declararea sa.
• Daca se face referire la o linie care nu exista, atunci se produce exceptia NO_DATA_FOUND.
• Pentru a sterge liniile unui tablou fie se asigneaza elementelor tabloului valoarea null, fie se
declara un alt tablou PL/SQL (de acelasi tip) care nu este initializat si acest tablou vid se
asigneaza tabloului PL/SQL care trebuie sters. În PL/SQL 2.3 stergerea liniilor unui tabel se
poate face utilizând metoda DELETE.

Sintaxa:
TYPE type_name IS TABLE OF
{column_type | variable%TYPE | table.column%TYPE} [NOT NULL] |
table%ROWTYPE
[INDEX BY PLS_INTEGER | BINARY_INTEGER | VARCHAR2(<size>)];

identifier type_name;

• Exista mai multe metode care se pot folosi cu structurile INDEX BY: EXISTS(n), COUNT,
FIRST, LAST, PRIOR(n),NEXT(n), DELETE(n).

Pentru mai multe detalii consultati documentatia,


http://docs.oracle.com/cd/E11882_01/appdev.112/e25519/composites.htm#LNPLS005

Exemplul 4:
Sa se defineasca un tablou indexat PL/SQL având elemente de tipul NUMBER. Sa se introduca
20 de elemente în acest tablou. Sa se afiseze, apoi sa se stearga tabloul utilizând diverse metode.
DECLARE
TYPE tablou_numar IS TABLE OF NUMBER
INDEX BY PLS_INTEGER;
v_tablou tablou_numar;
v_aux tablou_numar; -- tablou folosit pentru stergere
BEGIN
FOR i IN 1..20 LOOP
v_tablou(i) := i*i;
DBMS_OUTPUT.PUT_LINE(v_tablou(i));
END LOOP;
--v_tablou := NULL;
--aceasta atribuire da eroarea PLS-00382

4
SGBD

FOR i IN v_tablou.FIRST..v_tablou.LAST LOOP -- metoda 1 de stergere


v_tablou(i) := NULL;
END LOOP;
--sau
v_tablou := v_aux; -- metoda 2 de stergere
--sau
v_tablou.delete; --metoda 3 de stergere
DBMS_OUTPUT.PUT_LINE('tabloul are ' || v_tablou.COUNT ||' elemente');
END;
/

Exemplul 5:
DECLARE
TYPE emp_table_type IS TABLE OF employees%ROWTYPE
INDEX BY PLS_INTEGER;
my_emp_table emp_table_type;
--fiecare element din my_emp_table este un record.

max_count NUMBER(3):= 104;


BEGIN
FOR i IN 100..max_count LOOP
SELECT * INTO my_emp_table(i) FROM employees
WHERE employee_id = i;
END LOOP;
FOR i IN my_emp_table.FIRST..my_emp_table.LAST LOOP
DBMS_OUTPUT.PUT_LINE('la idul ' || i|| ' este ' ||
my_emp_table(i).last_name);
END LOOP;
END;

Tablouri imbricate

• Un tablou imbricat este o multime neordonata de elemente de acelasi tip.


o tablourile imbricate (nested table) sunt tablouri indexate cu o singura coloana (fara
coloana cheie primara)
o folosesc drept indici numere consecutive ;
o nu au dimensiune limitata, ele cresc dinamic;
o initial, un tablou imbricat este dens (are elementele pe pozitii consecutive) dar pot aparea
spatii goale prin stergere ;
o o metoda NEXT ne permite sa ajungem la urmatorul element ;
o pentru a insera un element nou, tabloul trebuie extins cu metoda EXTEND(nr_comp) ;
• Sintaxa:

TYPE nume_tip IS TABLE OF tip_ elemente [NOT NULL];

• Pentru adaugarea de linii intr-un tablou imbricat, acesta trebuie sa fie initializat cu ajutorul
constructorului.
o PL/SQL apeleaza un constructor numai în mod explicit.
o Tablourile indexate nu au constructori.

5
SGBD

o Constructorul primeste ca argumente o lista de valori numerotate în ordine, de la 1 la


numarul de valori date ca parametrii constructorului.
o Dimensiunea initiala a colectiei este egala cu numarul de argumente date în constructor,
când aceasta este initializata.
o Atunci când constructorul este fara argumente, va crea o colectie fara nici un element
(vida), dar care are valoarea not null.

Exemplul 6:
DECLARE
TYPE NumberList IS TABLE OF NUMBER;
n NumberList := NumberList(1966,1971,1984,1989,1999);
BEGIN
DBMS_OUTPUT.PUT_LINE('Colectia are '|| n.COUNT ||' elemente' );
FOR i in n.FIRST..n.LAST LOOP
DBMS_OUTPUT.PUT_LINE(n(i));
END LOOP;
IF n.EXISTS(2) THEN
DBMS_OUTPUT.PUT_LINE('OK, elementul de pe pozitia #2 exista.');
END IF;
DBMS_OUTPUT.PUT_LINE('Dupa elementul de pe pozitia #2 este cel de pe
pozitia #' || n.NEXT(2) || ' si anume '||n(n.NEXT(2)));
DBMS_OUTPUT.PUT_LINE('Inaintea elementului de pe pozitia #2 este cel de
pe pozitia #' || n.PRIOR(2) || ' si anume '||n(n.PRIOR(2)));
n.DELETE(3); -- Delete an element to show how NEXT can handle gaps.
DBMS_OUTPUT.PUT_LINE('Acum, dupa elementul de pe pozitia #2 este cel de
pe pozitia #' || n.NEXT(2)|| ' si anume '||n(n.next(2)));
IF n.PRIOR(n.FIRST) IS NULL THEN
DBMS_OUTPUT.PUT_LINE('Nu putem folosi PRIOR pentru primul element si
NEXT pentru ultimul');
END IF;
END;
/

Exemplul 7:
Analizati urmatorul exemplu, urmarind exceptiile semnificative care apar în cazul utilizarii incorecte a
colectiilor:
DECLARE
TYPE numar IS TABLE OF INTEGER;
alfa numar;
BEGIN
alfa(1) := 77;
-- declanseaza exceptia COLLECTION_IS_NULL
alfa := numar(15, 26, 37);
alfa(1) := ASCII('X');
alfa(2) := 10*alfa(1);
alfa('P') := 77;
/* declanseaza exceptia VALUE_ERROR deoarece indicele
nu este convertibil la intreg */
alfa(4) := 47;
/* declanseaza exceptia SUBSCRIPT_BEYOND_COUNT deoarece
indicele se refera la un element neinitializat */
6
SGBD

alfa(null) := 7; -- declanseaza exceptia VALUE_ERROR


alfa(0) := 7; -- exceptia SUBSCRIPT_OUTSIDE_LIMIT
alfa.DELETE(1);
IF alfa(1) = 1 THEN … -- exceptia NO_DATA_FOUND

END;
/

Exemplul 8:
Definiti un tip tablou imbricat EmpTab cu elemente de tipul liniilor tabelului EMP_student Definiti o
variabilade tip EmpTab si apoi inserati linia corespunzatoare în tabelul EMP_student.
DECLARE –cod partial!
TYPE EmpTab IS TABLE OF emp_student%ROWTYPE;
v_EmpList EmpTab;
BEGIN
v_EmpList(1) := EmpTab( … );

END;
/

Varrays
Trebuie specificate dimensiunea si tipul datelor stoate in array.

TYPE varray_type_name IS VARRAY(n) of <element_type>

Ex. TYPE namearray AS VARRAY(3) OF VARCHAR2(10);

Exemplul 9:

DECLARE
type namesarray IS VARRAY(5) OF VARCHAR2(10);
type grades IS VARRAY(5) OF INTEGER;
names namesarray;
marks grades;
total integer;
BEGIN
names := namesarray('Mimi', 'Irina', 'Alina', 'Radu', 'Andreea');
marks:= grades(9, 10, 8, 7, 9);
total := names.count;
dbms_output.put_line('Total '|| total || ' Studenti');
FOR i in 1 .. total LOOP
dbms_output.put_line('Student: ' || names(i) || '
Nota: ' || marks(i));
END LOOP;
END;
/

7
SGBD

Obs.
• Varrays sunt tablouri unidimensionale.
• În mediul Oracle, indicele de pornire pentru varrays este întotdeauna 1.
• Puteți inițializa elementele varray folosind constructorul de tip varray, care are același nume ca
varray.
• Un varray este automat NULL atunci când este declarat și trebuie inițializat înainte ca elementele
sale să poată fi utilizate

Exercitii

1. Scrieti un bloc PL/SQL care afiseaza informatii despre o tara.

A1.Declarati o variabila v_countryid de tip sir de caractere, dimensiune 2. Dati valoarea ‘CA’.
A2.Folositi atributul %ROWTYPE si declarati variabila v_country_record de tipul unei inregistrari
din COUNTRIES.
A3.Preluati informatiile din tabelul COUNTRIES folosind v_countryid. Afisati informatiile
selectate. Ar trebui sa obtineti un output de forma:

A4. Modificati blocul PL/SQL astfel:

• declarati un tablou imbricat denumit countryid_list cu date de tip sir de caractere cu dimensiune
maxima 2
• declarati o variabila countryid de tipul colectiei countryid_list si dati valorie 'CA', 'UK', 'US'.
• folosind o structura repetitiva, afisati datele tarilor al caror id se regaseste in colectia
countryid. Ar trebui sa obtineti un output de forma:

2. Scrieti un bloc PL/SQL care sa preia numele unor departamente din tabelul DEPARTMENTS si sa le
afiseze pe ecran, folosind o variabila INDEX BY.

A1.Declarati un tablou indexat numit dept_table de tipul departments.department_name (indexat cu


pls_integer)
A2.Declarati o variabila my_dept_table de tipul colectiei dept_table
A3.Declarati doua variabile: loop_count (cu valoarea initiala 10) si deptno (cu valoarea initiala 1) de
tip NUMBER.
A4.Folosind o structura repetitiva, preluati numele a 10 departamente si stocati-le in tabloul indexat.
Incepeti cu departamentul cu id 10 (id-urile vor fi 10, 20, 30,...)

8
SGBD

A5.In alta o structura repetitiva (folositi FIRST si LAST), preluati numele departamentelor si afisati-
le. La executia scriptului, ar trebui sa primiti rezultatul urmator:

3. Sa se defineasca o înregistrare având tipul celor din tabelul DEPT_student. Sa se actualizeze


numele departamentului cu id 10 si sa se introduca în tabelul DEPT_student.
• Declarati o variabila record dept_row de tipul unei inregistrari din tabelul DEPT_student.
• Actualizati in variabila dept_row datele departamentului cu id 10.
• Actualizati departament in tabelul DEPT_sudent

9
SGBD

Laborator 10
Cursoare explicite

Un cursor este o modalitate de a parcurge (linie cu linie) multimea de linii returnate de o cerere
‘multiple-row’. Această mulţime se numeşte active set.

Cursoarele pot fi:

• implicite –sunt declarate de PL/SQL in mod implicit pentru toate comenzile DML si comanda
SELECT, inclusiv comenzile care returneaza o singura linie.
• explicite – pentru cereri care returneaza mai mult de o linie; sunt denumite de programator si
manipulate prin intermediul unor comenzi specifice.

Etapele utilizarii unui cursor:


a) Declarare (în sectiunea declarativa a blocului PL/SQL):

CURSOR c_nume_cursor [ (parametru tip_de_Date, ..)] IS Comanda_SELECT;

b) Deschidere (comanda OPEN), operatie ce identifica multimea de linii (active set):

OPEN c_nume_cursor [ (parametru, …)];

c) Incarcare (comanda FETCH ). Numarul de variabile din clauza INTO trebuie sa se potriveasca cu
lista SELECT returnata de cursor.

FETCH c_nume_cursor INTO variabila, …;

d) Verificare daca nu am ajuns cumva la finalul multimii de linii folosind atributele:

C_nume_cursor%NOTFOUND – valoare booleana

C_nume_cursor%FOUND – valoare booleana

Daca nu s-a ajuns la final mergi la c).

e) Inchidere cursor (operatiune foarte importanta avand in vedere ca daca nu e inchis cursorul ramane
deschis si consuma din resursele serverului)

CLOSE c_nume_cursor;

Exemplul 1

DECLARE

CURSOR emp_cursor IS
1
SGBD

SELECT employee_id , last_name FROM employees

WHERE department_id = 50;

v_empno employees.employee_id%TYPE;

v_lname employees.last_name%TYPE;

BEGIN

OPEN emp_cursor ;

LOOP

FETCH emp_cursor INTO v_empno , v_lname ;

EXIT WHEN emp_cursor%NOTFOUND;

DBMS_OUTPUT.PUT_LINE(v_empno || ' ' || v_lname ) ;

END LOOP;

CLOSE emp_cursor ;

END;

Table 1 Atributele cursoarelor

Este posibil sa se defineasca inregistrari cu structura unui cursor si sa se obtina informatiile din cursor
direct intr-un record declarat de tipul cursorului, ca in exemplul 2

Exemplul 2

DECLARE

CURSOR emp_cursor IS

SELECT employee_id , last_name FROM employees

2
SGBD

WHERE department_id = 50;

emp_rec emp_cursor%ROWTYPE;

BEGIN

FOR emp_rec IN emp_cursor

LOOP

DBMS_OUTPUT.PUT_LINE( emp_rec.employee_id || ' ' || emp_rec.last_name );

END LOOP;

END;

• Atentie! Structura FOR are urmatoarele actiuni realizate implicit (NU este nevoie de OPEN
cursor si CLOSE cursor):
o cursorul este deschis
o la fiecare iteratie se obtine randul curent
o la sfarsit cursorul este inchis

Cursoarele pot primi parametri. Tipurile de data ale parametrilor se specifica fara dimensiune.

Exemplul 3

DECLARE
CURSOR emp_cursor (deptno NUMBER) IS
SELECT employee_id , last_name FROM employees
WHERE department_id = deptno ;
...
BEGIN
OPEN emp_cursor (10) ;
...
CLOSE emp_cursor ;
OPEN emp_cursor (20) ;
...
END;
/

Exercitii
1. Scrieti un bloc PL/SQL care realizeaza urmatoarele:
A1.In sectiunea declarativa, declarati o variabila v_deptno de tip NUMBER si dati-i valoarea
10.

3
SGBD

A2.Declarati un cursor, c_emp_cursor, care preia numele de familie, salariul si id-ul


managerului pentru angajatii care lucreaza in departamentul v_deptno.
A3.In sectiunea executabila, folositi un FOR pentru a parcurge datele din cursor. Daca
salariul unui angajat este <=5000 si manager_ID este 101 sau 124, afisati mesajul
“<<nume>> trebuie sa primeasca o marire de salariu”. Altfel, afisati mesajul “<<nume>>
nu trebuie sa primeasca o marire de salariu.
2. Sa se obtina câte o linie de forma ‘ <nume> are salariul anual <salariu annual> pentru fiecare
angajat din departamentele 50,60 si 70.
3. Scrieti un bloc PL/SQL pentru a efectua urmatoarele cerinte.
A1.Declarati un cursor c_dept_cursor care sa obtina DEPARTMENT_ID si
DEPARTMENT_NAME ale acelor departamente care au id-ul mai mic decat 100.
A2.Declarati inca un cursor c_emp_cursor care preia id-ul departamentului ca parametrusi
returneaza numele de familie, functia, data angajarii si salariul acelor angajati al caror id
este mai mic decat 120 si care lucreaza in departamentul specificat de parametru.
A3.Declarati cu ajutorul atributului %TYPE variabile care sa poata memora valori din fiecare
cursor (in total doua pentru primul cursor si patru pentru cel de-al doilea).
A4. Deschideti cursorul c_dept_cursor si obtineti valorile in variabilele declarate. Pentru
fiecare departament afisati informatiile si deschideti cursorul c_emp_cursor cu valoarea
parametrului egala cu id-ul curent. Afisati toate informatiile obtinute despre angajati.
A5.La final inchideti toate buclele si cursoarele.
4. Creati un bloc PL/SQL care determina cele mai mari n salarii, urmând pasii descrisi în
continuare:
A1.creati un tabel TOP_SALARII, având coloana salary.
A2.În sectiunea declarativa a blocului PL/SQL se va declara v_num de tip NUMBER
reprezentand numarul celor mai bine platiti salariati; se va introduce de catre utilizator (se
va folosi o variabila bind).
A3.Se va declara varaibila v_sal de tipul coloanei salary.
A4.Se va declara un cursor emp_cursor pentru regasirea salariilor în ordine descrescatoare
A5.Se vor introduce cei mai bine platiti n angajati în tabelul top_salarii
A6.Afisati continutul tabelului top_salarii
5. Realizati o copie a tabelului employees. Sa se declare un cursor cu un parametru de tipul codului
departamentului angajatului, care regaseste numele si salariul angajatilor având departamentul cu
codul transmis ca parametru. Sa se declare o variabila record de tipul unei linii a cursorului. Sa
se parcurga liniile cursorului, sa se verifice daca salariul este mai mic decat 5000, iar daca este,
sa se seteze un comision de 5%.

4
SGBD

Laborator 11
Tratarea erorilor

In exemplul de mai jos sintaxa este corecta insa la executie apare o eroare din cauza faptului ca
interogarea returneaza mai mult de un rand, iar blocul PL/SQL este terminat.

Exemplul 1:
DECLARE
v_lname VARCHAR2( 15 ) ;
BEGIN
SELECT last_name INTO v_lname
FROM employees
WHERE first_name = 'John' ;
DBMS_OUTPUT.PUT_LINE( ' John ''s last name is ' || v_lname ) ;
END;

Tratarea erorilor se realizeaza în sectiunea EXCEPTION a blocului PL/SQL:

EXCEPTION
WHEN nume_exceptie1 [OR nume_exceptie2 …] THEN
secventa_de_instructiuni_1;
[WHEN nume_exceptie3 [OR nume_exceptie4 …] THEN
secventa_de_instructiuni_2;]

[WHEN OTHERS THEN
secventa_de_instructiuni_n;]
END;

Pentru a rezolva problema de mai sus se poate proceda astfel:

Exemplul 1

DECLARE
v_lname VARCHAR2(15) ;
BEGIN
SELECT last_name INTO v_lname
FROM employees
WHERE first_name = 'John' ;

DBMS_OUTPUT.PUT_LINE( ' John ''s last name is ' || v_lname ) ;

EXCEPTION
WHEN TOO_MANY_ROWS THEN
DBMS_OUTPUT.PUT_LINE( 'SELECT a returnat prea multe randuri ' ) ;
END;

1
SGBD

Cu ajutorul functiilor SQLCODE si SQLERRM se pot obtine codul si mesajul asociate exceptiei
declansate. Codul erorii este:
• un numar negativ, în cazul unei erori sistem;
• numarul +100, în cazul exceptiei NO_DATA_FOUND;
• numarul 0, în cazul unei executii normale (fara exceptii);
• numarul 1, în cazul unei exceptii definite de utilizator.

DBMS_OUTPUT.PUT_LINE(SQLCODE);

DBMS_OUTPUT.PUT_LINE(SQLERRM);

Exceptiile pot fi :
• Interne - se produc atunci când un bloc PL/SQL nu respecta o regula Oracle sau depaseste o
limita a sistemului
o Predefinite - nu trebuie declarate în sectiunea declarativ, deoarece au deja anumite
denumiri asociate, si sunt tratate automat de catre server-ul Oracle. Ele sunt referite prin
denumire (CURSOR_ALREADY_OPEN, DUP_VAL_ON_INDEX,
NO_DATA_FOUND, TOO_MANY_ROWS, ZERO_DIVIDE)
o Nepredefinite – nu au denumiri predefinite, de aceea trebuie declarate în sectiunea
declarativ; sunt tratate automat de catre server-ul Oracle.
 unei exceptii nepredefinite i se asociaza o denumire cu codul Oracle de eroare
interna
• denumirea este data de utilizator
• codul de eroare poate sa fie orice nr intreg negativ mai mare decat -
10000000 (fara -1403, care este un cod pentru exceptia "no data found")
o https://docs.oracle.com/database/121/ERRMG/toc.htm
o se poate obtine cu SQLCODE
• directiva PRAGMA EXCEPTION_INIT permite asocierea denumire -
cod de eroare.
 exceptiile nepredefinite sunt gestionate in sectiunea EXCEPTION
 tratarea exceptiei se face în urmatoarea maniera:
• se declara numele exceptiei în partea declarativa sub forma:
nume_exceptie EXCEPTION;
• se asociaza numele exceptiei cu un cod eroare standard Oracle, utilizând
comanda:
PRAGMA EXCEPTION_INIT (nume_exceptie, cod_eroare);

• se refera exceptia în sectiunea de gestiune a erorilor (exceptia este tratata


automat, fara a fi necesara comanda RAISE).

DECLARE
nume_exceptie EXCEPTION;
PRAGMA EXCEPTION_INIT(nume_exceptie, cod_eroare) ;
BEGIN
. . .
EXCEPTION
WHEN nume_exceptie THEN
2
SGBD

instructiuni;
END;
Exemplul 2
DECLARE
uniquekeyerror EXCEPTION;
PRAGMA EXCEPTION_INIT(uniquekeyerror, -1);

BEGIN
UPDATE employees
SET email = 'LDEHAAN'
WHERE employee_id =103;

EXCEPTION
WHEN uniquekeyerror THEN
dbms_output.put_line('Eroare! Acest email exista deja in baza de
date!');

END;

• Externe (user-defined) - definite în partea declarativa a blocului, deci posibilitatea de referire la


ele este asigurata.
o in mod implicit, toate exceptiile externe au asociat acelasi cod (+1)
o sunt declansate cu directiva RAISE sau cu procedura RAISE_APPLICATION_ERROR

Declararea si prelucrarea exceptiilor externe respecta urmatoarea sintaxa:


DECLARE
nume_exceptie EXCEPTION; -- declarare exceptie
BEGIN

RAISE nume_exceptie; --declansare exceptie
-- codul care urmeaza nu mai este executat

EXCEPTION
WHEN nume_exceptie THEN
-- definire mod de tratare a erorii

END;

Exemplul 3
DECLARE
e_invalid_dept EXCEPTION;
BEGIN
UPDATE departments
SET department_name = ' Testing '
WHERE department_id = 900;

IF SQL%NOTFOUND THEN
RAISE e_invalid_dept;
END IF ;
3
SGBD

EXCEPTION
WHEN e_invalid_dept THEN
DBMS_OUTPUT.PUT_LINE( 'Nu exista un departament cu acest id ' ) ;
END;

Exemplul 4
DECLARE
CURSOR emp_cursor IS
SELECT employee_id , last_name FROM
employees
WHERE department_id = 1000;
v_empno employees.employee_id%TYPE;
v_lname employees.last_name%TYPE;
no_data Exception;

BEGIN
OPEN emp_cursor ;
LOOP
FETCH emp_cursor INTO v_empno , v_lname;
IF v_empno IS NULL THEN
RAISE no_data;
END IF;
EXIT WHEN emp_cursor%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(v_empno || ' ' || v_lname ) ;
END LOOP;
CLOSE emp_cursor ;
EXCEPTION
WHEN no_data THEN
DBMS_OUTPUT.PUT_LINE('Nu sunt date in tabel!');
END;

RAISE_APPLICATION_ERROR poate fi folosita pentru a returna un mesaj de eroare unitatii care o


apeleaza, mesaj mai descriptiv decât identificatorul erorii. Unitatea apelanta poate fi o procedura stocata
PL/SQL sau o aplicatie client. Procedura are urmatorul antet:

RAISE_APPLICATION_ERROR (numar_eroare IN NUMBER,mesaj_eroare IN


VARCHAR(2));

Atributul numar_eroare este un numar cuprins între –20000 si –20999, specificat de utilizator pentru
exceptia respectiva, iar mesaj_eroare este un text asociat erorii, care poate avea maximum 2048
octeti.

Eroarea returnata trebuie declarata si tratata cu directiva PRAGMA EXCEPTION_INIT

Exemplul 5
CREATE PROCEDURE hiredate_status (v_date DATE)
IS
BEGIN

IF v_date<to_date('01-Jan-2012','dd-mon-yy') THEN
4
SGBD

RAISE_APPLICATION_ERROR(-20205,'Data angajarii trebuie sa fie dupa


data de 01 ianuarie 2012 ');
END IF ;
UPDATE employees
SET hire_date = v_date
WHERE employee_id = 100;
END;

DECLARE
v_date date:=to_date('2-Feb-2013','dd-mon-yy');
wrong_hd EXCEPTION; --se declara exceptia
PRAGMA EXCEPTION_INIT (wrong_hd, -20205); -- asociaza denumire-cod
BEGIN
hiredate_status (v_date); -- apeleaza procedura
EXCEPTION
WHEN wrong_hd THEN -- trateaza exceptia
DBMS_OUTPUT.PUT_LINE(TO_CHAR(SQLERRM(-20205)));

END;

Exercitii
1. (Exceptii interne predefinite) Rezolvati cerintele de mai jos intr-un bloc PL/SQL
A1. Obtineti din tabelul EMPLOYEES numele de familie al acelor angajati care au salariile
egale cu 6000. Stocati numele de familie intr-o variabila de tipul coloanei
EMPLOYEES.LAST NAME. Nu folositi cursoare explicite!
A2. Daca interogarea a returnat un singur rand inserati in tabelul MESSAGES numele si
salariul angajatului.
A3. Daca interogarea nu returneaza nici un rand tratati exceptia si inserati in tabelul
MESSAGES mesajul "Nu exista angajati cu salariul 6000 ".
A4. Si in cazul in care interogarea returneaza mai mult de un rand tratati exceptia si inserati
mesajul "Exista mai mult de un angajat cu salariul 6000".
A5. Tratati orice alta eroare aparuta si inserati mesajul "A aparut o eroare".
2. (Exceptii interne nepredefinite) In acest exercitiu se va evidentia modalitatea de a trata eroarea
ORACLE -02292 (integrity constraint violated - child record found). Rezolvati cerintele de mai
jos intr-un bloc PL/SQL.
A1.In sectiunea declarativa creati exceptia e_childrecord_exists si asociati aceasta exceptie
cu cea predefinita ORACLE - 02292.
A2.Afisati mesajul "Angajatul cu id 124 va fi sters ...". Scrieti codul SQL corespunzator care
realizeaza stergerea angajatului cu id egal cu 124.
A3.Tratati eroarea e_childrecord_exists si afisati un mesaj corespunzator (de exemplu: 'Nu se
poate sterge angajatul cu id 40 deoarece este manager);
3. (Exceptii externe) Sa se scrie un bloc PL/SQL care afiseaza numarul departamentelor în care
lucreaza angajati al caror salariu este mai mare decât o valoare specificata. Sa se tipareasca un
mesaj adecvat, daca nu exista nici un departament care îndeplineste aceasta conditie.

5
SGBD

4. (Procedura RAISE_APPLICATION_ERROR) Determinati comisionul angajatului cu id 110.


Daca este null, afisati mesajul de eroare “nu are comision!”. Testati apoi programul pentru
id=169.

6
SGBD

Laborator 12-13
Functii si proceduri stocate
Triggeri (Declansatori)

Functii si proceduri stocate


Un subprogram este un bloc PL/SQL cu nume (spre deosebire de blocurile anonime) care poate primi
parametri si poate fi invocat dintr-un anumit mediu.

Exista 2 tipuri de subprograme:


• proceduri;
• functii (trebuie sa contina cel putin o comanda RETURN);

Subprograme stocate (create cu comanda CREATE) - odata create, procedurile si functiile sunt stocate
în baza de date de aceea ele se numesc subprograme stocate.

Sintaxa simplificata pentru crearea unei proceduri este urmatoarea:


[CREATE [OR REPLACE] ] PROCEDURE nume_procedura [ (lista_parametri) ]
{IS | AS}
[declaratii locale]
BEGIN
partea executabila
[EXCEPTION
partea de tratare a exceptiilor]
END [nume_procedura];

Sintaxa simplificata pentru crearea unei functii este urmatoarea:

[CREATE [OR REPLACE] ] FUNCTION nume_functie [ (lista_parametri) ]


RETURN tip_de_date
{IS | AS}
[declaratii locale]
BEGIN
partea executabila
[EXCEPTION
partea de tratare a exceptiilor]
END [nume_functie];

Lista de parametri contine specificatii de parametri separate prin virgula de forma:


nume_parametru tip_parametru;

O functie îndeplineste urmatoarele conditii:


• Accepta numai tipuri de date SQL
• Returneaza valori de tipuri de date SQL.

1
SGBD

• Poate fi folosita in lista de expresii a comenzii SELECT, clauza WHERE si HAVING,


ORDER BY, GROUP BY, clauza VALUES a comenzii INSERT, clauza SET a comenzii
UPDATE.

În cazul în care se modifica un obiect (vedere, tabel etc) de care depinde un subprogram, acesta este
invalidat. Revalidarea se face fie prin recrearea subprogramului fie prin comanda:

ALTER PROCEDURE nume_proc COMPILE;


ALTER FUNCTION nume_functie COMPILE;

Stergerea unei functii sau proceduri se realizeaza prin comenzile:


DROP PROCEDURE nume_proc;
DROP FUNCTION nume_functie;

Informatii despre procedurile si functiile detinute de utilizatorul curent se pot obtine interogând
vizualizarea USER_OBJECTS din dictionarul datelor.
SELECT OBJECT_NAME, OBJECT_TYPE, STATUS
FROM USER_OBJECTS
WHERE OBJECT_TYPE IN ('PROCEDURE','FUNCTION');

Exemplul 1: Procedura de mai jos insereaza in tabelul DEPARTMENTS o inregistrare noua cu valorile
primite ca parametru.

CREATE PROCEDURE add_dept ( v_dept_id departments.department_id%TYPE,


v_dept_name departments.department_name%TYPE)
IS
BEGIN
INSERT INTO departments ( department_id , department_name )
VALUES ( v_dept_id , v_dept_name ) ;
DBMS_OUTPUT.PUT_LINE( 'Au fost inserate ' || SQL%ROWCOUNT || ' randuri ' ) ;
END;

Procedura de mai sus poate fi apelata intr-o aplicatie specificand valorile corespunzatoare parametrilor.

BEGIN
add_dept (280, 'Departament de test ' ) ;
END;

Exemplul 2:

CREATE FUNCTION checksal ( v_empno employees.employee_id%TYPE)


RETURN VARCHAR2
IS
v_manid employees . employee_id%TYPE;
v_empsal employees . salary%TYPE;
v_mansal employees . salary%TYPE;
BEGIN
SELECT manager_id ,salary INTO v_manid, v_empsal

2
SGBD

FROM employees
WHERE employee_id = v_empno;
SELECT salary INTO v_mansal
FROM employees
WHERE employee_id = v_manid ;

IF v_empsal<v_mansal THEN
RETURN 'Salariul angajatului mai mic decat al managerului';
ELSE
RETURN 'Salariul angajatului mai mare decat al managerului';
END IF ;
END;

Functia de mai sus poate fi apelata intr-o aplicatie specificand valorile corespunzatoare parametrilor.

DECLARE
sir Varchar2(200);
BEGIN
sir:=checksal(102);
dbms_output.put_line(sir);
END;

Exercitii
1. Creati o procedura stocata numita hello care sa afiseze mesajul "Hello World".
A1.Creati un bloc anonim care sa apeleze procedura hello.
A2.Stergeti procedura cu urmatoarea comanda DROP PROCEDURE hello
A3. Modicati procedura astfel incat sa accepte un argument p_name de tip VARCHAR2.
A4.Afisati mesajul "Hello nume" in loc de "Hello world".
A5.Creati un bloc anonim care sa apeleze procedura hello.
2.
A1. Creati tabelul JOBS_name (numele vostru) cu structura si datele tabelului JOBS.
A2.Adaugati o constrangere de cheie primara pe campul job_id din tabelul JOBS_name
A3.Creati o procedura ADD_JOB_name care insereaza un nou job în tabelul JOBS_name.
Procedura va avea 2 parametri p_id si p_title corespunzatori codului si denumirii noului
job. Includeti o exceptie corespunzatoare situatiei în care jobul exista deja in tabel.
A4.Testati procedura, invocând-o astfel:
ADD_JOB_ name(‘IT_DBA’, ‘Database Administrator);
ADD_JOB_ name(‘IT_DBA’, ‘Database Administrator);
3.
A1.Creati o procedura stocata numita UPD_JOB_name pentru modificarea unui job existent
în tabelul JOBS_name. Procedura va avea ca parametri codul job-ului si noua sa
denumire. Includeti o exceptie corespunzatoare situatiei în care jobul nu exista in tabel.
A2. Testati procedura, invocând-o astfel:
UPD_JOB_name(‘IT_DBA’, ‘Data Administrator’);
UPD_JOB(‘IT_WEB’, ‘Web master’);

3
SGBD

4.
A1.Creati o procedura stocata numita DEL_JOB_name care sterge un job din tabelul
JOBS_name.
A2. Procedura va avea ca parametru codul job-ului. Includeti o exceptie corespunzatoare
situatiei în care nici un job nu este sters.
A3.Testati procedura, invocând-o astfel:
DEL_JOB_name(‘IT_DBA’);
DEL_JOB_name(‘IT_WEB’);

5. Sa se declare o functie care are parametrii urmatori:


A1.p_comision de tipul coloanei commission_pct din employees;
A2.p_cod de tipul coloanei employee_id din employees
Functia intoarce o valoare de tip VARCHAR2. Daca p_comision nu este NULL atunci în
variabila p_rezultat se va memora numele salariatului care are salariul maxim printre salariatii
având comisionul respectiv. În caz contrar, în p_rezultat se va memora numele salariatului al
carui cod are valoarea data la apelarea procedurii.

Triggeri (Declansatori)
Un declansator (trigger) este un bloc PL/SQL care, asemeni procedurilor stocate, este memorat in baza
de date, dar care este executat automat de catre Oracle ca raspuns la un eveniment specificat.

Nu este apelat de catre utilizator; trigger-ul se executa implicit ori de câte ori are loc un anumit
eveniment.

Un declansator se defineste pe un tabel, vedere, schema sau baza de date.

Pot fi de urmatoarele tipuri:


• trigger-i la nivel de aplicatie: se declanseaza odata cu un anumit eveniment din aplicatie;
• trigger-i la nivel de baza de date: se declanseaza atunci când un eveniment asupra datelor (de ex,
DML, DDL) sau un eveniment sistem (logon, shutdown) apare asupra bazei de date.

Instructiunea pentru crearea trigger-ilor DML contine urmatoarele informatii:


• timpul declansarii trigger-ului în raport cu evenimentul:
o pentru tabele: BEFORE, AFTER
o pentru view-uri nemodificabile: INSTEAD OF
• evenimentul declansator: INSERT, UPDATE, DELETE
• numele tabelului
• tipul trigger-ului – precizeaza de câte ori se executa corpul acestuia; trigger-ul poate fi la
nivel de:
o instructiune (statement-level): corpul triggerului se executa o singura data pentru
evenimentul declansator. Un astfel de trigger se declanseaza chiar daca nicio linie nu este
afectata. Se foloseste acest tip de trigger atunci cand datele introduse/modificate nu
depind de datele din tabel.

4
SGBD

o linie (row-level) - FOR EACH ROW: corpul triggerului se declanseaza o data pentru
fiecare linie afectata de care evenimentul declansator. Un astfel de trigger nu se executa
daca evenimentul declansator nu afecteaza nici o linie.
• clauza WHEN – precizeaza o conditie restrictiva a carei valoare de adevar TRUE determina
executarea trigger-ului.
• corpul trigger-ului (blocul PL/SQL)

Sintaxa:
CREATE [OR REPLACE] TRIGGER denumire_trigger
eveniment1 [OR eveniment2 OR eveniment3...] [OF column]
ON denumire_obiect
[FOR EACH ROW] --daca se omite, avem trigger de tip statement-level
[WHEN (conditie) ] -- valabila doar trigger-ele de tip row-level
[DECLARE
parte_declarativa; ]
BEGIN
parte_executabila;
END;

Obs. Dacă este prezenta clauza WHEN, corpul declanșatorului va fi executat numai pentru acele rânduri
care îndeplinesc condiția specificată de clauza.

Modificarea unui declansator consta din redenumirea, recompilarea, activarea sau dezactivarea acestuia
si se realizeaza prin comenzi de forma:
ALTER TRIGGER nume_trigger ENABLE;
ALTER TRIGGER nume_trigger DISABLE;
ALTER TRIGGER nume_trigger COMPILE
RENAME TO nume_nou;
;
ALTER TRIGGER nume_trigger
Activarea si dezactivarea tuturor triggerilor asociati unui tabel se realizeaza prin comenzile:
ALTER TABLE nume_tabel
DISABLE ALL TRIGGERS;
ALTER TABLE nume_tabel
ENABLE ALL TRIGGERS;

Eliminarea unui declansator se face prin


DROP TRIGGER nume_trigger;

Exemplul 1
In acest exemplu, trigger-ul este executat inaintea oricarei operatii de UPDATE, INSERT sau DELETE
efectuata in tabelul EMPLOYEES.
CREATE OR REPLACE TRIGGER print_salary_changes
BEFORE DELETE OR INSERT OR UPDATE ON employees
FOR EACH ROW
WHEN (new.employee_id> 0)
DECLARE
sal_diff number;
5
SGBD

BEGIN
sal_diff := :new.salary - :old.salary;
dbms_output.put('Old salary: ' || :old.salary);
dbms_output.put(' New salary: ' || :new.salary);
dbms_output.put_line(' Difference ' || sal_diff);
END;
/
UPDATE employees SET salary=9000 WHERE employee_id=176;

Pseudo-variabilele :old si :new se utilizeaza in trigger-e de tip Row Level!

Obs.
• :old se referă la datele așa cum existau înainte de tranzacție.
• UPDATE si DELETE fac de obicei referire la valori :old
• Valorile :new sunt valorile datelor pe care tranzacția le creează (cum ar fi coloanele dintr-o instr.
INSERT)
• :old este nedefinit pentru instrucțiunile INSERT
• :new este nedefinit pentru instrucțiunile DELETE
• Dacă trebuie să setați o valoare de coloană într-un rând inserat prin intermediul declanșatorului,
atunci va trebui să utilizați un declanșator BEFORE INSERT pentru a accesa valorile :new.
Utilizarea unui declanșator AFTER INSERT nu vă va permite să setați valoarea inserată,
deoarece rândul va fi deja inserat în tabel (și astfel va fi :old)
• Operațiile care ar fi valabile în mod normal pe înregistrări nu sunt valabile pentru :new și :old.
De exemplu, nu pot fi atribuite, de exemplu, v_tmprec := :old; nu este corect.

Exemplul 2
CREATE OR REPLACE TRIGGER GenerateStudentID
BEFORE INSERT OR UPDATE ON students_name
FOR EACH ROW
BEGIN
SELECT student_sequence.nextval INTO :new.ID
FROM dual;
END GenerateStudentID;

INSERT INTO students_name(first_name,last_name) VALUES('Andrei', 'Petre');

Obs.
Chiar dacă nu am specificat o valoare pentru ID-ul coloanei primare (care este obligatorie),
declanșatorul o va furniza prin apelarea secventei!

Exemplul 3
CREATE TRIGGER customer_bef_upd
BEFORE UPDATE ON customer
FOR EACH ROW
WHEN (new.amount/old.amount > 1.1) --fara “:” pt “new” and “old”
BEGIN
INSERT INTO customer_audit – tabela diferita fata de tabela customer
VALUES (:old.Action_date, :old.Action, :old.Item, :old.qty, :old.qtyType,
:old.rate, :old.amount);
6
SGBD

end;

Putem folosi trei funcții booleene pentru a determina care este operația realizata (din moment ce puteți
avea mai multe operații de declanșare, uneori trebuie să determinați ce operație se execută acum):
INSERTING, UPDATING, DELETING

Exemplul 4
In acest exemplu, trigger-ul este executat inaintea unei operatii de UPDATE efectuata pe coloana
salary din tabelul EMPLOYEES. Trigger-ul nu va fi apelat daca se executa un UPDATE care implica
orice alta coloana din tabel.

CREATE OR REPLACE TRIGGER calculate_commision_pct


BEFORE INSERT OR UPDATE OF salary ON employees
FOR EACH ROW
WHEN (NEW.job_id = 'SA_REP' or NEW.job_id=’AD_ASST’)
BEGIN
IF INSERTING THEN
:NEW.commission_pct := 0 ;
ELSIF :OLD.commission_pct IS NULL THEN
:NEW.commission_pct := 0;
ELSE
:NEW.commission_pct := :OLD.commission_pct+ 0.05 ;
END IF;
END;
\
UPDATE employees SET salary=9000 WHERE employee_id=176;
(angajatul cu id 176 e SA_REP!)

Exemplul 5
Trigger DDL, declansat la rularea unei instr. DDL, cu scrierea informatiilor despre utilizator si
eveniment in tabelul AUDIT_DDL. Obs. ca obiectul pe care este setat trigger-ul e schema utilizatorului.

CREATE TABLE AUDIT_DDL (


d date,
OSUSER varchar2(255),
CURRENT_USER varchar2(255),
HOST varchar2(255),
TERMINAL varchar2(255),
owner varchar2(30),
type varchar2(30),
name varchar2(30),
sysevent varchar2(30));

create or replace trigger audit_ddl_trg after ddl on schema


begin
if (ora_sysevent='TRUNCATE')
then
null; -- nu ne intereseaza acest eveniment
else
7
SGBD

insert into audit_ddl(d,


osuser,current_user,host,terminal,owner,type,name,sysevent)
values(
sysdate,
sys_context('USERENV','OS_USER') ,
sys_context('USERENV','CURRENT_USER') ,
sys_context('USERENV','HOST') ,
sys_context('USERENV','TERMINAL') ,
ora_dict_obj_owner,
ora_dict_obj_type,
ora_dict_obj_name,
ora_sysevent
);
end if;
end;
/

create table emp_c as select * from employees;

Pentru a crea un trigger pe o baza de date:


create or replace trigger DDLTrigger
AFTER DDL ON DATABASE
BEGIN
…..

Ob. Declanșatorii row-level nu pot accesa (cu instr. SELECT) tabelele mutating sau constraining.
Tabelul mutating este un tabel pe care declanșatorul curent îl urmărește pentru o modificare. Tabelul
constraining este un tabel care este legat de un tabel urmarit prin cheie străină.
Oracle va da eroarea „ORA-04091: table .... is mutating, trigger/function may not see it”. Exista mai
multe solutii pentru rezolvarea unei astfel de situatii, una dintre ele fiind folosirea declaratiei pragma
autonomous_transaction; in sectiunea DECLARE a trigger-ului.

Exercitii
1. Sa se implementeze un declansator care nu permite introducerea de salariati în tabelul
EMP_name având salariul mai mic decât 1000.
CREATE OR REPLACE TRIGGER sal_mini_student
BEFORE INSERT ON emp_student
FOR EACH ROW
BEGIN
IF :NEW.salary is null or :NEW.salary < 1000 THEN
RAISE_APPLICATION_ERROR
(-20005,’angajatii trebuie sa aiba salariul mai mare de 1000’);
END IF;
END;
2. Tabelul JOBS stocheaza valorile minime si maxime admise ale salariilor pentru fiecare functie in
parte (JOB ID). Urmand instructiunile urmatoare rezolvati problema verificarii corectitudinii
operatiilor de adaugare sau actualizare a angajatilor, astfel incat salariul sa fie intre limitele
admise de functia pe care o detin

8
SGBD

A1.Creati o procedura care primeste doi parametri: functia si salariul. Procedura verifica
daca salariul este cuprins intre salariul minim si maxim admis pentru respectiva functie.
Cand conditia nu este indeplinita trebuie sa se arunce o exceptie.
A2.Creati un declansator care are loc inaintea unei operatii de UPDATE sau INSERT a
tabelului EMP_name. Declansatorul va trebui sa apeleze procedura de la punctul anterior.
3. Sa se creeze un trigger care asigura ca inserarea de angajati în tabelul EMP_name se poate
realiza numai în zilele lucratoare, între orele 8-18. Obs:Trigger-ul nu are legatura directa cu
datele => este un trigger la nivel de instructiune.
4. Sa se implementeze cu ajutorul unui declansator restrictia ca într-un departament pot lucra
maximum 50 de angajati.
5. Sa se creeze un trigger care sa permita ca numai salariatii având codul job-ului AD_PRES sau
AD_VP sa poata câstiga mai mult de 15000. Obs: Trigger-ul se declanseaza de un numar de ori =
nr de înregistrari inserate sau al caror câmp salary este modificat (deci are legatura cu datele din
tabel) => este un trigger la nivel de linie.

9
SGBD

Laborator 13
PL/SQL - TEME

1. Creati:
- procedura ADD_EMP - adaugă o înregistrare în tabelul EMP_PNU; utilizează o secventă
pentru generarea cheilor primare; vor fi prevăzute valori implicite pentru parametrii
nespecificati;
- functia privată VALID_JOB_ID - rezultatul acestei functii indică dacă job-ul unui angajat
corespunde unei valori existente în tabelul JOBS. FuncTia va fi utilizată în cadrul procedurii
ADD_EMP, făcând posibilă doar introducerea de înregistrări având coduri de job valide. TrataTi
eventualele excepTii.
2. 6ă se creeze o procedură stocată care pentru un anumit cod de departament (dat ca parametru)
calculează prin intermediul unor funcTii locale numărul de salariaTi care lucrează în el, suma
salariilor úi numărul managerilor salariaTilor care lucrează în departamentul respectiv.
3. a) CreaTi o funcTie numită VALID_DEPTID_pnu pentru validarea unui cod de departament
specificat ca parametru. FuncTia va întoarce o valoare booleana (TRUE dacă departamentul
există).
b) CreaTi o procedură numită ADD_EMP_pnu care adaugă un angajat în tabelul EMP_pnu.
Linia respectivă va fi adăugată în tabel doar dacă departamentul specificat este valid, altfel
utilizatorul va primi un mesaj adecvat.
4. Să se creeze un tabel DEP_EMP_PNU având câmpurile cod_dep úi cod_ang. Să se introducă
într-o variabilă de tip tablou imbricat codurile departamentelor (în care există angajaTi), iar apoi,
să se insereze aceste coduri úi codurile angajaTilor corespunzători în tabelul DEP_EMP_PNU.
Indicatie: folositi SELECT department_id BULK COLLECT INTO v_dep FROM emp; pentru a
completa tabloul imbricat cu codurile departementelor.
5. Să se citească o valoare n de la tastatura. Prin intermediul unui cursor să se regăsească angajaTii
având salariul mai mare decât n. Pentru fiecare linie regăsită de cursor, dacă angajatul are
comision, să se afiúeze numele său úi salariul.
6. Creatii tabelul erori_pnu având două coloane: cod_eroare de tip NUMBER si mesaj_eroare de
tip VARCHAR2(100). Să se scrie un bloc PL/SQL care să determine si să afiseze salariatul
angajat cel mai recent într-un departament al cărui cod este introdus de către utilizator. Pentru
orice eroare apărută, vor fi inserate codul si mesajul erorii în tabelul erori_pnu.
7. Dacă există angajati ai unui anumit departament, să se tipărească un mesaj prin care utilizatorul
este anuntat că departamentul respectiv nu poate fi sters din baza de date (încălcarea
constrângerii de integritate având codul eroare Oracle -2292).
8. Să se steargă salariatii asignati unui cod de departament inexistent în tabelul departments. Dacă
nu există nici un angajat care a îndeplinit această condiTie, să se lanseze o exceptie cu mesajul
„nici un angajat nu lucreaza in departament inexistent”. 2 variante de rezolvare: declansati
eroarea cu RAISE si cu procedura RAISE_APPLICATION_ERROR.
9. Să se steargă angajatii al căror comision reprezintă mai mult decât jumătatea diferentei de salariu
dintre seful angajatului respectiv si angajat. Dacă nu există nici un angajat care a îndeplinit
această conditie, să se lanseze o excepTie cu mesajul „nici un angajat cu comisionul specificat”.
2 variante de rezolvare: declansati eroarea cu RAISE si cu procedura
RAISE_APPLICATION_ERROR.

1
SGBD

10. Să se implementeze un declansator care nu permite introducerea de salariati în tabelul emp_name


având salariul mai mic decât 1000.
11. Să se scrie un program (bloc) PL/SQL care să determine codul úi salariul angajatului având
salariul minim în departamentul cerut de utilizator úi apoi să se introducă informaTiile găsite în
tabelul mesaje_pnu.
12. Să se creeze un bloc PL/SQL care determină:
- numele, salariul si vechimea angajatului având salariul maxim în departamentul în care salariul
mediu este minim;
- codul úi data angajării celui mai bine platit angajat din Oxford.
- numele úi salariul angajatului având cea mai mica vechime.
Dacă vreuna dintre comenzi lansează excepTia TOO_MANY_ROWS, să se introducă în tabelul
mesaje_pnu informaTii despre comanda care a lansat aceasta exceptie.
13. Să se declare un bloc în care se va crea un subbloc ce lansează o excepTie e2. Subblocul nu va
conTine handler pentru e2, în schimb un astfel de handler se va afla în bloc. Ce se întâmplă la
execuTia blocului?
14. Să se implementeze cu ajutorul unui declanúator constrângerea că valorile salariilor nu pot fi
reduse (trei variante). După testare, suprimaTi trigger-ii creaTi.
15. Să se implementeze cu ajutorul unui declanúator constrângerea că valorile salariilor nu pot fi
reduse (trei variante). După testare, suprimaTi trigger-ii creaTi.
16. Să se creeze un trigger check_sal_pnu care garantează ca, ori de câte ori un angajat nou este
introdus în tabelul EMPLOYEES sau atunci când este modificat salariul sau codul job-ului unui
angajat, salariul se încadrează între minimul úi maximul salariior corespunzătoare job-ului
respectiv. Se vor exclude angajatii AD_PRES.

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