Documente Academic
Documente Profesional
Documente Cultură
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.
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
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.
3
SGBD
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.
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:
• 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.
Varianta 1:
CASE expr1
ELSE expr4
END
5
SGBD
Varianta 2:
CASE expr1
ELSE expr6
END
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
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
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
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
4 of 4 08-Oct-17, 22:11
sgbd2017: Laborator 2 - Subinterogari http://www.disciplinele.ml/mod/page/view.php?id=1216
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.
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);
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.
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
Sintaxa:
Exemplu:
4 of 4 08-Oct-17, 22:12
sgbd2017: Laborator 2 - Operatii JOIN http://www.disciplinele.ml/mod/page/view.php?id=1214
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
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).
(+) : 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):
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.
Clauza 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 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
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?
5 of 5 08-Oct-17, 22:11
SGBD
Laborator 3
Data Definition Language (DDL)
Data Manipulation Language (DML)
EXERCITII
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).
Exemplu:
CREATE TABLE departamente
(iddept NUMBER(2),
dnume VARCHAR2(14),
loc VARCHAR2(13));
Crearea unui tabel se poate realiza folosind o subinterogare, caz in care se adauga la tabelul creat
randurile returnate:
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;
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:
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.
• 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.
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));
4
SGBD
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);
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
Daca lipseste clauza WHERE, atunci TOATE inregistrarile din tabela respectiva vor fi modificate.
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);
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';
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.
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.
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
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;
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);
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
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.
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!).
Exista si clauza WITH READ ONLY care nu permite operatii DML intr-un view.
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.
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
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
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
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);
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!
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
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.
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:
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.
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
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
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");
/* executia interogarii */
rs=stmt.executeQuery(query);
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
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
• 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.
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
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
Descrierea trigger-ilor:
SELECT description FROM user_triggers;
Exercitii
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.
.
Numele Tabelului Comentarii
-------------- ----------
10
SGBD
definitiile de constrangeri
11
SGBD
12
SGBD
13
SGBD
bile utilizatorului
14
SGBD
rul este "grantee-ul"
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 Portabilitatea: Deoarece PL/SQL deriva din ORACLE, programele pot fi portate pe toate
masinile ce suporta ORACLE si 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
[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:
/*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;
2
SGBD
Observatii:
Denumire_var := expresie ;
• 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).
4. Variabile simple
• Declararea variabilelor se face ın partea declarativa a blocurilor.
Observatii:
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
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;
/*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
Exemplu:
% SQL Developer
ACCEPT p_cod_dep PROMPT “Introduceti codul departamentului “;
DECLARE
v_cod_dep departments.department_id%TYPE := &p_cod_dep;
5
SGBD
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”).
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;
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!
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
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
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
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;
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
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;
Sintaxa:
DECLARE
nume_record tabel_referit%ROWTYPE;
Exemplu:
emp_record employees%rowtype;
1
SGBD
Exemplul 1:
Rulati intai:
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;
/
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
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:
3
SGBD
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).
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
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.
Tablouri imbricate
• 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
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
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.
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
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:
• 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.
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:
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.
• 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.
c) Incarcare (comanda FETCH ). Numarul de variabile din clauza INTO trebuie sa se potriveasca cu
lista SELECT returnata de cursor.
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
v_empno employees.employee_id%TYPE;
v_lname employees.last_name%TYPE;
BEGIN
OPEN emp_cursor ;
LOOP
END LOOP;
CLOSE emp_cursor ;
END;
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
2
SGBD
emp_rec emp_cursor%ROWTYPE;
BEGIN
LOOP
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
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;
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;
Exemplul 1
DECLARE
v_lname VARCHAR2(15) ;
BEGIN
SELECT last_name INTO v_lname
FROM employees
WHERE first_name = 'John' ;
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);
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;
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;
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.
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
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
6
SGBD
Laborator 12-13
Functii si proceduri stocate
Triggeri (Declansatori)
Subprograme stocate (create cu comanda CREATE) - odata create, procedurile si functiile sunt stocate
în baza de date de aceea ele se numesc subprograme stocate.
1
SGBD
Î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:
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.
Procedura de mai sus poate fi apelata intr-o aplicatie specificand valorile corespunzatoare parametrilor.
BEGIN
add_dept (280, 'Departament de test ' ) ;
END;
Exemplul 2:
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’);
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.
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;
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;
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;
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.
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.
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