Documente Academic
Documente Profesional
Documente Cultură
CERERI MONOTABEL
1. Analizaţi sintaxa simplificată a comenzii SELECT. Care dintre clauze sunt obligatorii?
SELECT { [ {DISTINCT | UNIQUE} | ALL] lista_campuri | *}
FROM [nume_schemă.]nume_obiect ]
[, [nume_schemă.]nume_obiect …]
[WHERE condiţie_clauza_where]
[GROUP BY expresie [, expresie …]
[HAVING condiţie_clauza_having] ]
[ORDER BY {expresie | poziţie} [, {expresie | poziţie} …] ]
2. Găsiţi eroarea din instrucţiunea următoare.
SELECT employee_id, last_name, salary * 12 salariu anual
FROM employees;
Obs: SALARIU ANUAL este un alias pentru câmpul care reprezintă salariul anual.
Dacă un alias conţine blank-uri, el va fi scris obligatoriu între ghilimele. Altfel, ghilimelele pot fi
omise. Alias-ul apare în rezultat, ca antet de coloană pentru expresia respectivă. Doar cele specificate între
ghilimele sunt case-sensitive, celelalte fiind scrise implicit cu majuscule.
Varianta 1:
SELECT employee_id, last_name, salary * 12 salariu_anual
FROM employees;
Varianta 2:
SELECT employee_id, last_name, salary * 12 " Salariu Anual "
FROM employees;
1
7. Să se afişeze codul angajatului, numele, codul job-ului, data angajării. Salvaţi instrucţiunea SQL într-un
fişier numit p1_14.sql.
Obs: Pentru salvarea ultimei comenzi SQL se utilizează comanda SAVE. Precizarea extensiei „.sql” a
fişierului nu este obligatorie.
SELECT employee_id, last_name, job_id, hire_date
FROM employees;
SAVE z:\…\ p1_14.sql
8. Reexecutaţi cererea folosind fişierul p1_14.sql.
START z:\…\ p1_14.sql
sau
@ z:\…\ p1_14.sql
9. Editaţi fişierul p1_14.sql, adăugând coloanelor câte un alias (cod, nume, cod job, data angajarii).
EDIT z:\…\ p1_14.sql
@ z:\…\ p1_14.sql
18. Să se afişeze numele şi data angajării pentru fiecare salariat care a fost angajat în 1987. Se cer 2 soluţii:
una în care se lucrează cu formatul implicit al datei şi alta prin care se formatează data.
3
Varianta1:
SELECT first_name, last_name, hire_date
FROM employees
WHERE hire_date LIKE („%87‟);
Varianta 2:
SELECT first_name, last_name, hire_date
FROM employees
WHERE TO_CHAR(hire_date, „YYYY‟)=‟1987‟;
Sunt obligatorii ghilimelele de la şirul „1987‟? Ce observaţi?
19. Să se afişeze numele şi job-ul pentru toţi angajaţii care nu au manager.
SELECT last_name, job_id
FROM employees
WHERE manager_id IS NULL;
20. Să se afişeze numele, salariul şi comisionul pentru toţi salariaţii care câştigă comisioane. Să se sorteze
datele în ordine descrescătoare a salariilor, iar pentru cei care au acelaşi salariu în ordine crescătoare a
comisioanelor.
SELECT last_name, salary, commission_pct
FROM employees
WHERE commission_pct IS NOT NULL
ORDER BY salary DESC, commission_pct ASC;
21. Să se listeze numele tuturor angajaţilor care au a treia litera din nume 'a'.
Obs: Pentru a forma măştile de caractere utilizate împreună cu operatorul LIKE cu scopul de a compara
şirurile de caractere, se utilizează:
% - reprezentând orice şir de caractere, inclusiv şirul vid;
_ (underscore) – reprezentând un singur caracter.
SELECT DISTINCT last_name
FROM employees
WHERE last_name LIKE '__a%';
4
30. Să se listeze numele tuturor angajaţilor care au 2 litere 'L' în nume şi lucrează în departamentul 30 sau
managerul lor este 123.
31. Să se afişeze numele, job-ul şi salariul pentru toţi salariaţii al căror job conţine şirul 'CLERK' sau 'REP' şi
salariul nu este egal cu 1000, 2000 sau 3000 $.
32. Să se afişeze numele, salariul şi comisionul pentru toţi angajaţii al căror salariu este mai mare decât de 5
ori valoarea comisionului (salary*commission_pct*5).
5
LABORATOR 2 - SQL
FUNCŢII SQL (single-row)
Funcţiile SQL sunt predefinite în sistemul Oracle şi pot fi utilizate în instrucţiuni SQL. Ele nu
trebuie confundate cu funcţiile definite de utilizator, scrise în PL/SQL.
Dacă o funcţie SQL este apelată cu un argument având un alt tip de date decât cel aşteptat, sistemul
converteşte implicit argumentul înainte să evalueze funcţia.
Dacă o funcţie SQL este apelată cu un argument null, atunci aceasta returnează valoarea null.
Singurele funcţii care nu urmează această regulă sunt CONCAT, NVL şi REPLACE.
Principalele funcţii SQL pot fi clasificate în următoarele categorii:
Funcţii single-row
Funcţii multiple-row (funcţii agregat)
Funcţiile single-row returnează câte o linie rezultat pentru fiecare linie a tabelului sau vizualizării
interogate. Aceste funcţii pot apărea în listele SELECT, clauzele WHERE, START WITH, CONNECT BY
şi HAVING.
2. Să se afişeze pentru fiecare angajat din departamentul 20 un şir de caractere de forma "Funcţia
salariatului {prenume} {nume} este {cod functie}". Să se afişeze prenumele cu iniţiala litera mare, iar
numele cu litere mari (Stephen KING), iar codul funcţiei să se afişeze cu litere mici.
3. Să se afişeze pentru angajatul cu numele 'HIGGINS' codul, numele şi codul departamentului. Cum se
scrie condiţia din WHERE astfel încât să existe siguranţa ca angajatul 'HIGGINS' va fi găsit oricum ar fi
fost introdus numele acestuia? Căutarea trebuie să nu fie case-sensitive, iar eventualele blank-uri care
preced sau urmează numelui trebuie ignorate.
UPPER(TRIM(last_name))='HIGGINS';
4. Să se afişeze pentru toţi angajaţii al căror nume se termină în 'n', codul, numele, lungimea numelui şi
poziţia din nume în care apare prima data litera 'a'. Asociaţi aliasuri coloanelor returnate de cerere.
SELECT employee_id, last_name, LENGTH(last_name), INSTR(UPPER(last_name), 'A')
FROM employees
WHERE SUBSTR(last_name,-1)='n';
5. Analizaţi următoarele funcţii aritmetice:
Funcţie Semnificaţie Exemplu
ROUND(1.6) = 2
Returnează valoarea rotunjită a expresiei
ROUND(1.4) = 1
până la n zecimale. Daca n este negativ sunt
ROUND (expresie [, n]) ROUND (1234.56,1) = 1234.6
rotunjite cifre din stânga virgulei. Valoarea
ROUND (1230.56, -2) = 1200
implicită pentru n este 0.
ROUND (1260.56, -2) = 1300
6. Să se afişeze detalii despre salariaţii care au lucrat un număr întreg de săptămâni până la data curentă.
MOD(ROUND(SYSDATE – hire_date), 7)=0;
7. Să se afişeze numele, salariul şi numărul de mii al salariului rotunjit la 2 zecimale pentru cei care nu au
salariul divizibil cu 1000.
8. Analizaţi următoarele operaţii pe expresii de tip dată calendaristică:
Tipul de date al
Operaţie Descriere
rezultatului
date -/+ number Date Scade/Adaugă un număr de zile dintr-o / la o dată.
date1 - date2 Number Întoarce numărul de zile dintre două date calendaristice.
date +/-
Date Scade/Adaugă un număr de ore la o / dintr-o dată calendaristică.
number/24
9. Să se afişeze data (luna, ziua, ora, minutul si secunda) de peste 10 zile.
SYSDATE+10
10. Să se afişeze numărul de zile rămase până la sfârşitul anului.
ROUND(TO_DATE(‟31-DEC-2009‟)-SYSDATE)
11. a. Să se afişeze data de peste 12 ore.
SYSDATE+12/24
b. Să se afişeze data de peste 5 minute.
SYSDATE+1/288
12. Analizaţi următoarele funcţii pentru prelucrarea datelor calendaristice:
Funcţie Semnificaţie Exemplu
SYSDATE Întoarce data şi timpul curent
Returnează numărul de luni dintre
data date1 şi data date2. Rezultatul
MONTHS_BETWEEN poate fi pozitiv sau negativ după cum ROUND(MONTHS_BETWEEN
(date1, date2) date1 este mai recentă sau nu faţă de (SYSDATE + 31, SYSDATE)) = 1
date2. Zecimalele reprezintă parţi
dintr-o luna!
Adaugă n luni la o data specificată. MONTHS_BETWEEN
ADD_MONTHS (date, n) Valoarea n trebuie să fie întreagă (ADD_MONTHS(SYSDATE, 3),
(pozitivă sau negativă). SYSDATE) = 3
NEXT_DAY('15-dec-2006','Monday')
Returnează data corespunzătoare
= '18-dec-2006'
NEXT_DAY (date, char) primei zile a săptămânii specificate
NEXT_DAY ('15-dec-2006',1)
(char) care urmează după date.
= '18-dec-2006'
13. Să se afişeze numele angajatului, data angajării şi data negocierii salariului, care a avut loc în prima zi de
Luni, după 6 luni de serviciu. Etichetaţi această coloană “Negociere”.
NEXT_DAY(ADD_MONTHS(hire_date, 6), „Monday‟)
14. Pentru fiecare angajat să se afişeze numele şi numărul de luni de la data angajării. Etichetaţi coloana
“Luni lucrate”. Să se ordoneze rezultatul după numărul de luni lucrate. Se va rotunji numărul de luni la
cel mai apropiat număr întreg.
SELECT last_name, ROUND(MONTHS_BETWEEN(SYSDATE, hire_date)) “Luni lucrate”
FROM employees
ORDER BY MONTHS_BETWEEN(SYSDATE, hire_date);
SELECT last_name, ROUND(MONTHS_BETWEEN(SYSDATE, hire_date)) “Luni lucrate”
FROM employees
ORDER BY “Luni lucrate”;
Atunci când în clauza FROM a unei comenzi SELECT apar mai multe tabele se realizează produsul
cartezian al acestora. De aceea numărul de linii rezultat creşte considerabil, fiind necesară restricţionarea
acestora cu o clauza WHERE.
Atunci când este necesară obţinerea de informaţii din mai multe tabele se utilizează condiţii de join.
Join-ul este operaţia de regăsire a datelor din două sau mai multe tabele, pe baza valorilor comune ale unor
coloane. Condiţiile de corelare utilizează de obicei coloanele cheie primară şi cheie externă.
Pentru claritatea şi eficienţa accesului la baza de date se recomandă prefixarea numelor coloanelor cu
numele tabelelor din care fac parte (tabel.coloana). De asemenea, există posibilitatea de a utiliza aliasuri pentru
tabelele din clauza FROM şi utilizarea lor în cadrul comenzii SELECT respective (alias.coloana). Această
identificare (prin 'tabel.coloana' sau 'alias.coloana') este obligatorie atunci când se face referinţă la o coloana ce
apare în mai mult de un tabel din clauza FROM.
Tipuri de join:
equijoin (se mai numeşte inner join sau simple join) - compunerea a două tabele diferite după o
condiţie ce conţine operatorul de egalitate.
SELECT last_name, department_name, location_id, e.department_id
FROM employees e, departments d
WHERE e.department_id = d.department_id;
Obs: Numele sau alias-urile tabelelor sunt obligatorii în dreptul coloanelor care au acelaşi nume în
mai multe tabele.
nonequijoin - compunerea a două relaţii tabele după o condiţie oarecare, ce NU conţine operatorul
de egalitate.
SELECT last_name, salary, grade_level
FROM employees, job_grades
WHERE salary BETWEEN lowest_sal AND highest_sal;
outerjoin - compunerea externă a două tabele diferite completând una dintre relaţii cu valori NULL
acolo unde nu există în aceasta nici un tuplu ce îndeplineşte condiţia de corelare. Relaţia completată
cu valori NULL este cea în dreptul căreia apare “(+)”. Operatorul (+) poate fi plasat în orice parte a
condiţiei de join, dar nu în ambele părţi. Full outer join = Left outer join UNION Right outer join.
SELECT last_name, department_name,location_id
FROM employees e, departments d
WHERE e.department_id(+) = d.department_id;
selfjoin - compunerea externă a unui tabel cu el însuşi după o condiţie dată.
SELECT sef.last_name, angajat.last_name
FROM employees sef, employees angajat
WHERE sef.employee_id = angajat.manager_id
ORDER BY sef.last_name;
1. Pentru fiecare angajat să se afişeze numele, codul şi numele departamentului.
SELECT last_name, e.department_id, department_name
FROM employees e, departments d
WHERE e.department_id = d.department_id;
2. Să se afişeze numele angajatului, numele departamentului pentru toţi angajaţii care câştigă comision.
3. Să se listeze numele job-urile care există în departamentul 30.
SELECT DISTINCT job_title
FROM employees e, jobs j
WHERE e.job_id = j.job_id
AND department_id = 30;
4. Să se afişeze numele, job-ul şi numele departamentului pentru toţi angajaţii care lucrează în Seattle.
SELECT last_name, job_id, department_name
FROM employees e, departments d, locations s
WHERE e.department_id = d.department_id
AND d.location_id = s.location_id
AND city = „Seattle‟;
5. Să se afişeze numele, salariul, data angajării şi numele departamentului pentru toţi programatorii care
lucrează în America.
region_name = „Americas‟
job_title = „Programmer‟
6. Să se afişeze numele salariaţilor şi numele departamentelor în care lucrează. Se vor afişa şi salariaţii care nu
lucrează într-un departament (right outher join).
SELECT last_name, department_name
FROM employees e, departments d
WHERE e.department_id = d.department_id(+);
7. Să se afişeze numele departamentelor şi numele salariaţilor care lucrează în ele. Se vor afişa şi
departamentele care nu au salariaţi (left outher join).
8. Să se afişeze numele, job-ul, numele departamentului, salariul şi grila de salarizare pentru toţi angajaţii.
9. Să se afişeze codul angajatului şi numele acestuia, împreună cu numele şi codul şefului său direct. Se vor
eticheta coloanele Ang#, Angajat, Mgr#, Manager. Să se salveze instrucţiunea într-un fişier numit p3_9.sql.
SELECT a.employee_id “Ang#”, a.last_name “Angajat”, b.employee_id “Mgr#”, b.last_name “Manager”
FROM employees a, employees b
WHERE a.manager_id = b. employee_id;
10. Să se modifice p3_9.sql pentru a afişa toţi salariaţii, inclusiv pe cei care nu au şef.
11. Să se afişeze numele salariatului şi data angajării împreună cu numele şi data angajării şefului direct pentru
salariaţii care au fost angajaţi înaintea şefilor lor. Se vor eticheta coloanele Angajat, Data_ang, Manager si
Data_mgr.
12. Pentru fiecare angajat din departamentele 20 şi 30 să afişeze numele, codul departamentului şi toţi colegii
săi (salariaţii care lucrează în acelaşi departament cu el). Se vor eticheta coloanele corespunzător.
SELECT a.last_name “Angajat”, a.department_id ”Departament”, b.last_name “Coleg”
FROM employees a, employees b
WHERE a.department_id = b.department_id
AND a.employee_id <> b.employee_id
AND a.department_id IN (20,30)
ORDER BY a.last_name;
13. Să se afişeze numele şi data angajării pentru salariaţii care au fost angajaţi după Fay.
SELECT last_name, hire_date
FROM employees
WHERE hire_date > (SELECT hire_date
FROM employees
WHERE last_name = „Fay‟);
sau
SELECT a.last_name, a.hire_date
FROM employees a, employees b
WHERE UPPER(b.last_name)=‟FAY‟ AND a.hire_date>b.hire_date;
14. Scrieţi o cerere pentru a afişa numele şi salariul pentru toţi colegii (din acelaşi departament) lui Fay. Se va
exclude Fay.
SELECT last_name, salary
FROM employees
WHERE last_name <> „Fay‟
AND department_id = (SELECT department_id
FROM employees
WHERE last_name = „Fay‟);
15. Să se afişeze codul departamentului, codul şi numele angajaţilor care lucrează în acelaşi departament cu cel
puţin un angajat al cărui nume conţine litera “T”. Să se ordoneze după codul departamentului.
SELECT employee_id, last_name, department_id
FROM employees
WHERE department_id IN (SELECT DISTINCT department_id
FROM employees
WHERE UPPER(last_name) LIKE „%T%‟)
ORDER BY department_id;
16. Să se afişeze numele şi salariul angajaţilor conduşi direct de Steven King.
SELECT last_name, salary
FROM employees
WHERE manager_id = (SELECT employee_id
FROM employees
WHERE UPPER(last_name) ='KING'
AND UPPER(first_name) ='STEVEN' );
17. Să se afişeze numele şi job-ul tuturor angajaţilor din departamentul „Sales‟.
SELECT last_name, job_id
FROM employees
WHERE department_id = (SELECT department_id
FROM departments
WHERE department_name ='Sales');
18. Să se afişeze numele angajaţilor, numărul departamentului şi job-ul tuturor salariaţilor al căror departament
este localizat în Seattle.
SELECT last_name, job_id, department_id
FROM employees
WHERE department_id IN (SELECT department_id
FROM departments
WHERE location_id = (SELECT location_id
FROM locations
WHERE city = „Seattle‟));
Rezolvaţi această problemă utilizând join-uri.
19. Să se afle dacă există angajaţi care nu lucrează în departamentul „Sales‟ şi al căror salariu şi comision
coincid cu salariul şi comisionul unui angajat din departamentul „Sales‟.
SELECT last_name, salary, commission_pct, department_id
FROM employees
WHERE (salary, commission_pct) IN (SELECT salary, commission_pct
FROM employees e, departments d
WHERE e.department_id = d.department_id
AND department_name = „Sales‟)
AND department_id <> (SELECT department_id
FROM departments
WHERE department_name = „Sales‟);
20. Scrieţi o cerere pentru a afişa numele, numele departamentului şi salariul angajaţilor care nu câştigă
comision, dar al căror manager coincide cu managerul unui angajat care câştigă comision.
SELECT last_name, department_name, salary
FROM employees e, departments d
WHERE e.department_id = d.department_id
AND e.manager_id IN (SELECT DISTINCT manager_id
FROM employees
WHERE commission_pct IS NOT NULL)
AND commission_pct IS NULL;
21. Scrieţi o cerere pentru a afişa angajaţii care câştigă mai mult decât oricare funcţionar. Sortaţi rezultatele
după salariu, în ordine descrescătoare.
SELECT last_name, salary, job_id
FROM employees
WHERE salary > (SELECT MAX(salary)
FROM employees
WHERE job_id LIKE '%CLERK')
ORDER BY salary DESC;
22. Să se afişeze codul, numele şi salariul tuturor angajaţilor care câştigă mai mult decât salariul mediu.
23. Să se afişeze pentru fiecare salariat angajat în luna martie numele său, data angajării şi numele jobului.
24. Să se afişeze pentru fiecare salariat al cărui câştig total lunar este mai mare decât 12000 numele său,
câştigul total lunar şi numele departamentului în care lucrează.
25. Să se afişeze pentru fiecare angajat codul său şi numele joburilor sale anterioare, precum şi intervalul de
timp în care a lucrat pe jobul respectiv.
26. Să se modifice cererea de la punctul 25 astfel încât să se afişeze şi numele angajatului, respectiv codul
jobului său curent.
27. Să se modifice cererea de la punctul 26 astfel încât să se afişeze şi numele jobului său curent.
28. Să se afişeze salariaţii care au acelaşi manager ca şi angajatul având codul 140.
29. Să se afişeze numele departamentelor care funcţionează în America.
LABORATOR 4 - SQL
Funcţii multiple-row (grup). Gruparea datelor.
Aceste tipuri de funcţii pot fi utilizate pentru a returna informaţia corespunzătoare fiecăruia dintre
grupurile obţinute în urma divizării liniilor tabelului cu ajutorul clauzei GROUP BY.
Pot apărea în clauzele SELECT, ORDER BY şi HAVING. Server-ul Oracle aplică aceste funcţii fiecărui
grup de linii şi returnează un singur rezultat pentru fiecare mulţime.
Exemple de funcţii grup: AVG, SUM, MAX, MIN, COUNT etc.
Tipurile de date ale argumentelor funcţiilor grup pot fi CHAR, VARCHAR2, NUMBER sau DATE.
Funcţiile AVG şi SUM, operează numai asupra valorilor numerice. Funcţiile MAX şi MIN pot opera asupra
valorilor numerice, caracter sau dată calendaristică.
Toate funcţiile grup, cu excepţia lui COUNT(*), ignoră valorile null. COUNT(expresie)
returnează numărul de linii pentru care expresia dată nu are valoarea null. Funcţia COUNT returnează un
număr mai mare sau egal cu zero şi nu întoarce niciodată valoarea null.
Când este utilizată clauza GROUP BY, server-ul sortează implicit mulţimea rezultată în ordinea
crescătoare a valorilor coloanelor după care se realizează gruparea.
Absenţa clauzei GROUP BY conduce la aplicarea funcţiei grup pe mulţimea tuturor liniilor tabelului.
În clauza GROUP BY se trec obligatoriu toate coloanele prezente în clauza SELECT, care nu sunt
argument al funcţiilor grup.
1. Să se afişeze cel mai mare salariu, cel mai mic salariu, suma şi media salariilor tuturor angajatilor. Etichetaţi
coloanele Maxim, Minim, Suma, respectiv Media. Să se rotunjească rezultatele.
SELECT MIN(salary) min, MAX(salary) max, SUM(salary) suma, ROUND(AVG(salary)) media
FROM employees;
2. Utilizând funcţia grup COUNT să se determine:
a. numărul total de angajaţi;
b. numărul de angajaţi care au manager;
c. numărul de manageri.
3. Să se afişeze diferenţa dintre cel mai mare şi cel mai mic salariu. Etichetaţi coloana “Diferenta”.
4. Să se listeze numărul de angajaţi din departamentul având codul 50.
5. Caţi angajaţi din departamentul 80 câştigă comision?
6. Să se selecteze valoarea medie şi suma salariilor pentru toţi angajaţii care sunt reprezentanţi de vânzări
(SA_MAN, SA_REP).
7. Să se selecteze data angajării primei persoane care a fost angajată de companie.
8. Să se afişeze numărul de angajaţi pentru fiecare job.
SELECT job_id, COUNT(employee_id) nr_angajati
FROM employees
GROUP BY job_id;
9. Să se afişeze minimul, maximul, suma şi media salariilor pentru fiecare departament.
10. Să se afişeze codul departamentului şi media salariilor pentru fiecare job din cadrul acestuia.
SELECT department_id, job_id, AVG(salary)
FROM employees
GROUP BY department_id, job_id;
11. a. Să se afişeze codul departamentelor pentru care salariul minim depăşeşte 5000$.
SELECT department_id, MIN(salary)
FROM employees
GROUP BY department_id
HAVING MIN(salary)>5000;
1
b. Să se modifice cererea anterioară astfel încât să se afişeze şi oraşul în care funcţionează aceste
departamente.
12. Să se obţină codul departamentelor şi numărul de angajaţi al acestora pentru departamentele care au cel
puţin 10 angajaţi.
13. Să se obţină codul departamentelor şi suma salariilor angajaţilor care lucrează în acestea, în ordine
descrescătoare după sumă. Se consideră angajaţii care au comision şi departamentele care au mai mult de 5
angajaţi.
14. Să se obţină job-ul pentru care salariul mediu este minim.
SELECT job_id
FROM employees
GROUP BY job_id
HAVING AVG(salary) = (SELECT MIN(AVG(salary))
FROM employees
GROUP BY job_id);
15. Să se afişeze cel mai mare dintre salariile medii pe departamente.
16. a. Să se afişeze codul, numele departamentului şi suma salariilor pe departamente.
SELECT d.department_id, department_name,a.suma
FROM departments d, (SELECT department_id ,SUM(salary) suma
FROM employees
GROUP BY department_id) a
WHERE d.department_id =a.department_id;
17. a. Scrieţi o cerere pentru a afişa numele departamentului, numărul de angajaţi şi salariul mediu pentru
angajaţii din acel departament. Coloanele vor fi etichetate Departament, Nr. angajati, Salariu Mediu.
SELECT department_name “Departament”,
(SELECT COUNT(employee_id)
FROM employees
WHERE department_id = d.department_id ) ” Nr. angajati”,
(SELECT AVG(salary)
FROM employees
WHERE department_id = d.department_id) ”Salariu mediu”
FROM departments d;
b. Daţi o altă metodă de rezolvare pentru problema anterioară.
18. Să se creeze o cerere prin care să se afişeze numărul total de angajaţi şi, din acest total, numărul celor care
au fost angajaţi în 1997, 1998, 1999 şi 2000. Datele vor fi afişate în forma următoare:
Total 1997 1998 1999 2000
--------------------------------------------------------------
50 10 5 25 1
SUM(DECODE(TO_CHAR(hire_date,'yyyy'),1997,1,0))
2
Operatorii ROLLUP şi CUBE
Clauza GROUP BY permite gruparea liniilor selectate după valorile expresiilor precizate în aceasta.
Pentru fiecare grup, va fi returnată o singură linie de informaţie. Clauza GROUP BY poate produce grupări
superagregat utilizând extensiile CUBE sau ROLLUP.
ROLLUP grupează liniile selectate pe baza valorilor primelor n, n - 1, …, 0 expresii din
specificaţia GROUP BY şi returnează o singură linie pentru fiecare grup. ROLLUP creează grupări prin
deplasarea într-o singură direcţie, de la dreapta la stânga, de-a lungul listei de coloane specificate în
clauza GROUP BY. Apoi, se aplică funcţia agregat acestor grupări. Dacă sunt specificate n expresii în
operatorul ROLLUP, numărul de grupări generate va fi n + 1. Liniile care se bazează pe valoarea primelor
n expresii se numesc linii obişnuite, iar celelalte se numesc linii superagregat.
GROUP BY ROLLUP (expr_1, expr_2, …, expr_n) generează n+1 tipuri de linii, corespunzătoare
următoarelor grupări:
GROUP BY (expr_1, expr_2, …, expr_n-1, expr_n)
GROUP BY (expr_1, expr_2, …, expr_n-1)
…
GROUP BY (expr_1, expr_2)
GROUP BY (expr_1)
GROUP BY () – corespunzător absenţei clauzei GROUP BY şi deci, calculului funcţiilor grup din
cerere pentru întreg tabelul.
CUBE grupează liniile selectate pe baza valorilor tuturor combinaţiilor posibile ale expresiilor
specificate şi returnează câte o linie totalizatoare pentru fiecare grup. Acest operator este folosit pentru a
produce mulţimi de rezultate care sunt utilizate în rapoarte. În vreme ce ROLLUP produce subtotalurile
doar pentru o parte dintre combinaţiile posibile, operatorul CUBE produce subtotaluri pentru toate
combinaţiile posibile de grupări specificate în clauza GROUP BY, precum şi un total general.
Dacă există n coloane sau expresii în clauza GROUP BY, vor exista 2n combinaţii posibile
superagregat.
19. Să se afişeze codurile departamentelor în care lucrează cel puţin un angajat, iar pentru fiecare dintre acestea
şi pentru fiecare manager care lucrează în departamentul respectiv să se afişeze numărul de salariaţi. De
asemenea, să se afişeze numărul de salariaţi pentru fiecare departament indiferent de manager şi numărul
total de angajaţi din companie.
4
25. Modificaţi cererea anterioară astfel încât să se afişeze numele departamentelor, titlurile job-urilor şi
valoarea medie a salariilor, pentru:
- fiecare departament şi, în cadrul său pentru fiecare job;
- fiecare departament (indiferent de job);
- fiecare job(indiferent de departament);
- întreg tabelul.
Cum intervin coloanele în obţinerea rezultatului?
Să se afişeze ‟Dept‟, dacă departamentul a intervenit în agregare şi „Job‟, dacă job-ul a intervenit în agregare.
DECODE(GROUPING(department_name), 0, „Dept‟)
26. Utilizaţi cererea de la punctul 20.
a. Eliminaţi clauza WHERE din această cerere. Analizaţi rezultatul obţinut.
b. Modificaţi cererea obţinută astfel încât să se identifice dacă o valoare null din rezultat este stocată pe
una dintre coloanele manager_id sau department_id sau este produsă de operatorul CUBE.
27. Clauza GROUPING SETS. Permite obţinerea numai a anumitor grupări superagregat. Acestea pot fi
precizate prin intermediul clauzei:
5
LABORATOR 5 SQL
I. Limbajul de control al datelor (COMMIT, SAVEPOINT, ROLLBACK)
II. Limbajul de prelucrare a datelor (LMD). INSERT, UPDATE, DELETE.
SELECT *
FROM dept_***;
SAVEPOINT a;
SAVEPOINT b;
SELECT COUNT(*)
FROM dept_***;
ROLLBACK TO b;
1
SELECT COUNT(*)
FROM dept_***;
ROLLBACK TO a;
COMMIT;
SELECT *
FROM dept_***;
1. Să se creeze tabele emp_*** şi dept_*** (dacă nu este deja creat), având aceeaşi structură şi date ca şi
tabelele employees, respectiv departments.
2. Să se selecteze toate înregistrările din cele două tabele create anterior.
3. Ştergeţi toate înregistrările din cele 2 tabele create anterior. Salvati modificarile.
DELETE FROM emp_***;
...
COMMIT;
4. Să se listeze structura tabelului employees şi să se compare cu structura tabelului emp_***. Ce observaţi?
5. Sintaxa simplificată a comenzii INSERT
- pentru inserarea unei singuri linii:
INSERT INTO nume_tabel [(col1,col2,...)]
VALUES (expresie1, expresie2, ...);
- pentru inserarea liniilor rezultat ale unei comenzi SELECT:
INSERT INTO nume_tabel [(col1,col2,...)]
{comanda_SELECT};
Observatii:
- lista de coloane (dacă este precizată) trebuie să se potrivească ca număr şi tip de date cu lista de
expresii;
- în loc de tabel (nume_tabel), insererea se mai poate face si prin intermediul unei vizualizări;
- daca se omit coloane în lista de inserare, acestea primesc valoarea NULL sau valoarea implicită.
- posibile probleme la inserare:
- lipsa de valori pentru coloane NOT NULL,
- nepotrivirea listei de coloane cu cea de expresii,
- valori duplicate ce încalcă o constrângere de unicitate,
- încălcarea vreunei constrângeri de integritate referenţială,
- încălcarea unei constrângeri de tip CHECK,
- nepotrivire de tip de date,
- valoare prea mare pentru coloana respectivă.
- dacă se foloseşte expresia DEFAULT, atunci valoarea inserată este NULL sau valoarea implicită
setată la nivel de tabel.
6. Să se exemplifice câteva din erorile care pot să apară la inserare şi să se observe mesajul returnat de sistem.
- lipsa de valori pentru coloane NOT NULL (coloana department_name este NOT NULL)
INSERT INTO dept_*** (department_id, location_id)
VALUES (200, 2000);
- nepotrivirea listei de coloane cu cea de expresii
2
INSERT INTO dept_***
VALUES (200, 2000);
INSERT INTO dept_*** (department_id, department_name,location_id)
VALUES (200, 2000);
- nepotrivire de tip de date,
INSERT INTO dept_*** (department_id, location_id)
VALUES (‘D23’, 2000);
- valoare prea mare pentru coloană
INSERT INTO dept_*** (department_id, location_id)
VALUES (15000, 2000);
7. Copiaţi în tabelul emp_*** salariaţii (din tabelul employees) al căror comision depăşeşte 25% din salariu.
8. Creaţi tabele emp1_***, emp2_*** şi emp3_*** cu aceeaşi structură ca tabelul employees. Copiaţi din
tabelul employees:
- în tabelul emp1_*** salariaţii care au salariul mai mic decât 6000;
- în tabelul emp2_*** salariaţii care au salariul cuprins între 6000 şi 10000;
- în tabelul emp3_*** salariaţii care au salariul mai mare decât 10000.
Verificaţi rezultatele, apoi ştergeţi toate înregistrările din aceste tabele.
Obs. Clauza ALL determină evaluarea tuturor condiţiilor din clauzele WHEN. Pentru cele a căror valoare
este TRUE, se inserează înregistrarea specificată în opţiunea INTO corespunzătoare.
INSERT ALL
WHEN salary < =6000 THEN
INTO emp1_***
WHEN salary > = 6000 AND salary <= 10000 THEN
INTO emp2_***
ELSE
INTO emp3_***
SELECT * FROM employees;
3
Obs. Clauza FIRST determină inserarea corespunzătoare primei clauze WHEN a cărei condiţie este evaluată
TRUE. Toate celelalte clauze WHEN sunt ignorate.
10. Ştergeţi toate înregistrările din tabelele emp_*** şi dept_***. Inseraţi în aceste tabele toate înregistrările
corespunzătoare din employees, respectiv departments. Permanentizaţi modificările.
13. Eliminaţi angajaţii care nu aparţin unui departament valid. Anulaţi modificările.
UPDATE emp_***
SET salary = salary * 1.05;
ROLLBACK;
16. Schimbaţi jobul tuturor salariaţilor din departamentul 80 care au comision în 'SA_REP'. Anulaţi
modificările.
17. Să se promoveze Douglas Grant la manager în departamentul 20, având o creştere de salariu cu 1000$.
18. Să se modifice jobul şi departamentul angajatului având codul 114, astfel încât să fie la fel cu cele ale
angajatului având codul 205.
19. Schimbaţi salariul şi comisionul celui mai prost plătit salariat din firmă, astfel încât să fie egale cu
salariul si comisionul directorului.
UPDATE emp_***
SET (salary, commission_pct) = (SELECT salary, commission_pct
FROM emp_***
4
WHERE manager_id IS NULL)
WHERE salary = (SELECT MIN(salary)
FROM emp_***);
ROLLBACK;
20. Pentru fiecare departament să se mărească salariul celor care au fost angajaţi primii astfel încât să devină
media salariilor din companie.
21. Să se modifice valoarea emailului pentru angajaţii care câştigă cel mai mult în departamentul în care
lucrează astfel încât acesta să devină iniţiala numelui concatenată cu “_” concatenat cu prenumele.
Anulaţi modificările.
5
Limbajul de definire a datelor (DDL). CREATE, ALTER, DROP
Definirea tabelelor
CREATE TABLE [schema.]nume_tabel (
nume_coloana tip_de_date [DEFAULT1 expr], ...);
1
Modificarea tabelelor
Constrângeri
2
ObservaŃie:
Constrângerile de tip CHECK se pot implementa la nivel de coloană doar dacă nu referă o altă coloană a
tabelului.
- adaugă constrângeri
ALTER TABLE nume_tabel
ADD [CONSTRAINT nume_constr] tip_constr (coloana);
- elimină constrângeri
ALTER TABLE nume_tabel
3
DROP [CONSTRAINT nume_constr] tip_constr (coloana);
- activare/dezactivare constrângere
ALTER TABLE nume_tabel
MODIFY CONSTRAINT nume_constr ENABLE|DISABLE;
sau
ALTER TABLE nume_tabel
ENABLE| DISABLE nume_constr;
19. InseraŃi o nouă înregistrare în salariat_*** de forma:
cod_dep
cod nume prenume data_n functia sef data_ang email salariu
11-JUN-
2 N2 P2 economist 1 Sysdate E2 2000 10
1960
Ce observaŃi? IntroduceŃi înregistrarea dar specificând valoarea NULL pentru coloana sef.
20. ÎncercaŃi să adăugaŃi o constrângere de cheie externă pe cod_dep din salariat_***. Ce observaŃi?
21. InseraŃi o nouă înregistrare în departament_***. Apoi adăugaŃi constrângerea de cheie externă definită
anterior.
22. InseraŃi noi înregistrări în salariat_***, respectiv în departament_***. Care trebuie să fie ordinea de
inserare?
cod_dep
cod nume prenume data_n functia sef data_ang email salariu
11-JUN- 20
3 N3 P3 jurist 2 Sysdate E3 2500
1967
Definirea vizualizărilor
Sintaxa simplificată a comenzii CREATE VIEW este:
CREATE [OR REPLACE] [FORCE | NOFORCE] VIEW nume_view [(alias, alias, ..)]
AS subcerere
[WITH CHECK OPTION [CONSTRAINT nume_constr]]
[WITH READ ONLY [CONSTRAINT nume_constr]];
- FORCE permite crearea vizualizarea înainte de a defini tabelele de bază;
- subcererea poate fi oricât de complexă dar nu poate conŃine clauza ORDER BY;
- WITH CHECK OPTION permite inserarea şi modificarea prin intermediul vizualizării numai a
liniilor ce sunt accesibile vizualizării; dacă lipseşte numele constrângerii atunci sistemul asociază
un nume implicit de tip SYS_Cn acestei constrângeri;
- WITH READ ONLY asigură că prin intermediul vizualizării nu se pot executa operaŃii LMD.
Eliminarea unei vizualizări se face prin comanda DROP VIEW :
DROP VIEW nume_viz;
1. Să se creeze vizualizarea v_emp_*** care să conŃină codul şi numele salariaŃilor din tabelul emp_***. Să
se afişeze conŃinutul acesteia. Să se insereze o nouă înregistrare în această vizualizare. Ce observaŃi? Să
se şteargă vizualizarea v_emp_***.
2. Să se creeze vizualizarea v_emp_*** care să conŃină codul, numele, emailul, data angajării, salariul şi
codul jobului salariaŃilor din tabelul emp_***. Să se analizeze structura şi conŃinutul vizualizării. Să se
insereze o nouă înregistrare în această vizualizare. Să se verifice că noua înregistrare a fost inserată şi în
tabelul de bază.
DESC v_emp_***
5
INSERT INTO v_emp_***
VALUES (400,’N1’,’E1’,SYSDATE,5000,’SA_REP’);
d) AdăugaŃi tabelului emp_*** constrângerea de cheie externă care referă tabelul dept_***, apoi
verificaŃi ce coloane din vizualizarea v_emp_dept_*** sunt actualizabile.
e) RecreaŃi vizualizarea v_emp_dept_***, apoi verificaŃi ce coloane sunt actualizabile.
f) InseraŃi o linie prin intermediul acestei vizualizări.
Obs. Tabelul ale cărui coloane sunt actualizabile este protejat prin cheie.
g) Ce efect are o operaŃie de ştergere prin intermediul vizualizării v_emp_dept_***? ComentaŃi.
7. a) Să se creeze vizualizarea v_emp30_*** care să conŃină numele, emailul, data angajării, salariul,
codul jobului şi codul departamentului celor care lucrează în departamentul 30. În această
vizualizare nu se va permite modificarea sau inserarea liniilor ce nu sunt accesibile ei. DaŃi un nume
constrângerii.
6
c) Să se încerce prin intermediul vizualizării inserarea unui angajat în departamentul 10 şi a unui angajat
în departamentul 30.
d) Să se încerce prin intermediul vizualizării modificarea departamentului unui angajat.
UPDATE v_emp30_***
SET department_id =20
WHERE employee_id = 11;
8. Să se creeze o vizualizare (v_dept_***) asupra tabelului dept_*** să nu permită efectuarea nici unei
operaŃii LMD. TestaŃi operaŃiile de inserare, modificare şi ştergere asupra acestei vizualizări.
Obs: Coloana TEXT este de tip LONG. În cazul selectării unei coloane de tip LONG trebuie utilizată
comanda SET LONG n pentru a seta numărul de caractere afişate.
Definirea secvenŃelor
Sintaxa comenzii CREATE SEQUENCE este:
CREATE SEQUENCE nume_secvenŃă
[INCREMENT BY n]
[START WITH valoare_start]
[ {MAXVALUE valoare_maximă | NOMAXVALUE} ]
[ {MINVALUE valoare_minimă | NOMINVALUE} ]
[ {CYCLE | NOCYCLE} ]
[ {CACHE n | NOCACHE} ];
Ştergerea secvenŃelor se realizează cu ajutorul comenzii DROP SEQUENCE.
DROP SEQUENCE nume_secv;
10. Să se creeze o secvenŃă care are pasul de incrementare 10 şi începe de la 10, are ca valoare maximă
10000 şi nu ciclează.
7
UPDATE emp_***
SET employee_id = sec_emp***.NEXTVAL;
ROLLBACK;
12. Să se introducă un nou salariat în tabelul emp_*** folosindu-se pentru codul salariatului secvenŃa creată.
13. Să se afişeze valoarea curentă a secvenŃei.
ExerciŃiu
a) CreaŃi o secvenŃă pentru generarea codurilor de departamente, seq_dept_***. SecvenŃa va începe de
la 200, va creşte cu 10 la fiecare pas şi va avea valoarea maximă 20000, nu va cicla.
b) Să se selecteze informaŃii despre secvenŃele utilizatorului curent (nume, valoare minimă, maximă,
de incrementare, ultimul număr generat). Se va utiliza vizualizarea user_sequences.
c) Să se insereze o înregistrare nouă în DEPT_*** utilizând secvenŃa creată.
d) Să se selecteze valoarea curentă a secvenŃei.
e) Să se şteargă secvenŃa.
Definirea indecşilor
Sintaxa comenzii CREATE INDEX:
CREATE [UNIQUE] INDEX nume_index
ON tabel (coloana1 [, coloana2…]);
Modificarea unui index se face prin comanda ALTER INDEX.
Eliminarea unui index se face prin comanda: DROP INDEX nume_index;
14. Să se creeze un index neunic, emp_last_name_idx_***, asupra coloanei last_name din tabelul
emp_***.
15. Să se creeze indecşi unici asupra codului angajatului (employee_id) şi asupra combinaŃiei last_name,
first_name, hire_date.
16. CreaŃi un index neunic asupra coloanei department_id din emp_*** pentru a eficientiza joinurile
dintre acest tabel şi dept_***.
Definirea sinonimelor
Comanda pentru crearea sinonimelor este:
CREATE [PUBLIC] SYNONYM nume_sinonim
FOR obiect;
Eliminarea sinonimelor se face prin comanda DROP SYNONYM nume_sinonim;
17. CreaŃi un sinonim public se_*** pentru tabelul emp_***.
18. CreaŃi un sinonim pentru vizualizarea v_dept_***.
19. Utilizând sinonimele create anterior, afişaŃi informaŃii depre salariŃi şi despre departamente.
8
Limbajul de interogare al datelor (DQL). SELECT
CERERI MONOTABEL
1. AnalizaŃi sintaxa simplificată a comenzii SELECT. Care dintre clauze sunt obligatorii?
SELECT { [ {DISTINCT | UNIQUE} | ALL] lista_campuri | *}
FROM [nume_schemă.]nume_obiect ]
[, [nume_schemă.]nume_obiect …]
[WHERE condiŃie_clauza_where]
[GROUP BY expresie [, expresie …]
[HAVING condiŃie_clauza_having] ]
[ORDER BY {expresie | poziŃie} [, {expresie | poziŃie} …] ]
9
Obs: Operatorul de concatenare este “||”. Şirurile de caractere se specifică între apostrofuri (NU
ghilimele, caz în care ar fi interpretate ca alias-uri).
SELECT last_name|| ' ' || first_name " Nume si prenume "
FROM employees;
11. Să se listeze numele şi salariul angajaŃilor care câştigă mai mult de 10000 $.
SELECT last_name, salary
FROM employees
WHERE salary > 10000;
12. Să se modifice cererea anterioară astfel încât să afişeze numele şi salariul pentru toŃi angajaŃii al căror
salariu este cuprins între 5000$ şi10000$.
Obs: Pentru testarea apartenenŃei la un domeniu de valori se poate utiliza operatorul
[NOT] BETWEEN valoare1 AND valoare2
SELECT last_name, salary
FROM employees
WHERE salary BETWEEN 5000 AND 10000;
13. Să se creeze o cerere pentru a afişa numele angajatului şi numărul departamentului pentru angajatul 104.
14. Să se afişeze numele şi salariul pentru toŃi angajaŃii din departamentele 10 sau 30, în ordine alfabetică a
numelor.
Obs: ApartenenŃa la o mulŃime finită de valori se poate testa prin intermediul operatorului IN, urmat de
lista valorilor între paranteze şi separate prin virgule:
expresie IN (valoare_1, valoare_2, …, valoare_n)
15. Să listeze numele şi salariile angajaŃilor care câştigă mai mult de 10000 $ şi lucrează în departamentul
10 sau 30. Se vor eticheta coloanele drept Angajat si Salariu lunar.
16. Care este data curentă?
Obs: Pseudocoloana care returnează data curentă este SYSDATE. Pentru completarea sintaxei obligatorii
a comenzii SELECT, se utilizează tabelul DUAL:
SELECT SYSDATE
FROM dual;
Datele calendaristice pot fi formatate cu ajutorul funcŃiei TO_CHAR(data, format), unde formatul poate
fi alcătuit dintr-o combinaŃie a următoarelor elemente:
Element SemnificaŃie
D Numărul zilei din săptămână (duminică=1;
luni=2; …sâmbătă=6).
DD Numărul zilei din lună.
DDD Numărul zilei din an.
DY Numele zilei din săptămână, printr-o
abreviere de 3 litere (MON, THU etc.)
DAY Numele zilei din săptămână, scris în
întregime.
MM Numărul lunii din an.
MON Numele lunii din an, printr-o abreviere de 3
litere (JAN, FEB etc.)
MONTH Numele lunii din an, scris în întregime.
Y Ultima cifră din an
YY, YYY, YYYY Ultimele 2, 3, respectiv 4 cifre din an.
YEAR Anul, scris în litere (ex: two thousand
four).
HH12, HH24 Orele din zi, între 0-12, respectiv 0-24.
10
MI Minutele din oră.
SS Secundele din minut.
SSSSS Secundele trecute de la miezul nopŃii.
17. Să se afişeze numele şi data angajării pentru fiecare salariat care a fost angajat în 1987. Se cer 2 soluŃii:
una în care se lucrează cu formatul implicit al datei şi alta prin care se formatează data.
Varianta1:
SELECT first_name, last_name, hire_date
FROM employees
WHERE hire_date LIKE (‘%87’);
Varianta 2:
SELECT first_name, last_name, hire_date
FROM employees
WHERE TO_CHAR(hire_date, ‘YYYY’)=’1987’;
Sunt obligatorii ghilimelele de la şirul ‘1987’? Ce observaŃi?
18. Să se afişeze numele şi job-ul pentru toŃi angajaŃii care nu au manager.
SELECT last_name, job_id
FROM employees
WHERE manager_id IS NULL;
19. Să se afişeze numele, salariul şi comisionul pentru toŃi salariaŃii care câştigă comisioane. Să se sorteze
datele în ordine descrescătoare a salariilor, iar pentru cei care au acelaşi salariu în ordine crescătoare a
comisioanelor.
SELECT last_name, salary, commission_pct
FROM employees
WHERE commission_pct IS NOT NULL
ORDER BY salary DESC, commission_pct ASC;
20. Să se listeze numele tuturor angajaŃilor care au a treia litera din nume 'a'.
Obs: Pentru a forma măştile de caractere utilizate împreună cu operatorul LIKE cu scopul de a compara
şirurile de caractere, se utilizează:
% - reprezentând orice şir de caractere, inclusiv şirul vid;
_ (underscore) – reprezentând un singur caracter.
SELECT DISTINCT last_name
FROM employees
WHERE last_name LIKE '__a%';
2. Să se afişeze pentru fiecare angajat din departamentul 20 un şir de caractere de forma "FuncŃia
salariatului {prenume} {nume} este {cod functie}". Să se afişeze prenumele cu iniŃiala litera mare, iar
numele cu litere mari (Stephen KING), iar codul funcŃiei să se afişeze cu litere mici.
3. Să se afişeze pentru angajatul cu numele 'HIGGINS' codul, numele şi codul departamentului. Cum se
scrie condiŃia din WHERE astfel încât să existe siguranŃa ca angajatul 'HIGGINS' va fi găsit oricum ar fi
fost introdus numele acestuia? Căutarea trebuie să nu fie case-sensitive, iar eventualele blank-uri care
preced sau urmează numelui trebuie ignorate.
UPPER(TRIM(last_name))='HIGGINS';
4. Să se afişeze pentru toŃi angajaŃii al căror nume se termină în 'n', codul, numele, lungimea numelui şi
poziŃia din nume în care apare prima data litera 'a'. AsociaŃi aliasuri coloanelor returnate de cerere.
SELECT employee_id, last_name, LENGTH(last_name), INSTR(UPPER(last_name), 'A')
FROM employees
WHERE SUBSTR(last_name,-1)='n';
5. AnalizaŃi următoarele funcŃii aritmetice:
FuncŃie SemnificaŃie Exemplu
ROUND(1.6) = 2
Returnează valoarea rotunjită a expresiei
ROUND(1.4) = 1
până la n zecimale. Daca n este negativ sunt
ROUND (expresie [, n]) ROUND (1234.56,1) = 1234.6
rotunjite cifre din stânga virgulei. Valoarea
ROUND (1230.56, -2) = 1200
implicită pentru n este 0.
ROUND (1260.56, -2) = 1300
6. Să se afişeze detalii despre salariaŃii care au lucrat un număr întreg de săptămâni până la data curentă.
MOD(ROUND(SYSDATE – hire_date), 7)=0;
7. Să se afişeze numele, salariul şi numărul de mii al salariului rotunjit la 2 zecimale pentru cei care nu au
salariul divizibil cu 1000.
8. AnalizaŃi următoarele operaŃii pe expresii de tip dată calendaristică:
Tipul de date al
OperaŃie Descriere
rezultatului
date -/+ number Date Scade/Adaugă un număr de zile dintr-o / la o dată.
date1 - date2 Number Întoarce numărul de zile dintre două date calendaristice.
date +/-
Date Scade/Adaugă un număr de ore la o / dintr-o dată calendaristică.
number/24
9. Să se afişeze data (luna, ziua, ora, minutul si secunda) de peste 10 zile.
13
SYSDATE+10
10. Să se afişeze numărul de zile rămase până la sfârşitul anului.
ROUND(TO_DATE(’31-DEC-2009’)-SYSDATE)
11. a. Să se afişeze data de peste 12 ore.
SYSDATE+12/24
b. Să se afişeze data de peste 5 minute.
SYSDATE+1/288
12. AnalizaŃi următoarele funcŃii pentru prelucrarea datelor calendaristice:
FuncŃie SemnificaŃie Exemplu
SYSDATE Întoarce data şi timpul curent
Returnează numărul de luni dintre
data date1 şi data date2. Rezultatul
MONTHS_BETWEEN poate fi pozitiv sau negativ după cum ROUND(MONTHS_BETWEEN
(date1, date2) date1 este mai recentă sau nu faŃă de (SYSDATE + 31, SYSDATE)) = 1
date2. Zecimalele reprezintă parŃi
dintr-o luna!
Adaugă n luni la o data specificată. MONTHS_BETWEEN
ADD_MONTHS (date, n) Valoarea n trebuie să fie întreagă (ADD_MONTHS(SYSDATE, 3),
(pozitivă sau negativă). SYSDATE) = 3
NEXT_DAY('15-dec-2006','Monday')
Returnează data corespunzătoare
= '18-dec-2006'
NEXT_DAY (date, char) primei zile a săptămânii specificate
NEXT_DAY ('15-dec-2006',1)
(char) care urmează după date.
= '18-dec-2006'
13. Să se afişeze numele angajatului, data angajării şi data negocierii salariului, care a avut loc în prima zi de
Luni, după 6 luni de serviciu. EtichetaŃi această coloană “Negociere”.
NEXT_DAY(ADD_MONTHS(hire_date, 6), ‘Monday’)
14. Pentru fiecare angajat să se afişeze numele şi numărul de luni de la data angajării. EtichetaŃi coloana
“Luni lucrate”. Să se ordoneze rezultatul după numărul de luni lucrate. Se va rotunji numărul de luni la
cel mai apropiat număr întreg.
SELECT last_name, ROUND(MONTHS_BETWEEN(SYSDATE, hire_date)) “Luni lucrate”
FROM employees
ORDER BY MONTHS_BETWEEN(SYSDATE, hire_date);
16
- dacă lucrează de mai mult de 200 de luni atunci salariul va fi mărit cu 20%;
- dacă lucrează de mai mult de 150 de luni, dar mai puŃin de 200 de luni, atunci salariul va fi mărit cu
15%;
- dacă lucrează de mai mult de 100 de luni, dar mai puŃin de 150 de luni, atunci salariul va fi mărit cu
10%;
- altfel, salariul va fi mărit cu 5%.
Tipuri de join:
• equijoin (se mai numeşte inner join sau simple join) - compunerea a două tabele diferite după o
condiŃie ce conŃine operatorul de egalitate.
SELECT last_name, department_name, location_id, e.department_id
FROM employees e, departments d
WHERE e.department_id = d.department_id;
Obs: Numele sau alias-urile tabelelor sunt obligatorii în dreptul coloanelor care au acelaşi nume
în mai multe tabele.
• nonequijoin - compunerea a două relaŃii tabele după o condiŃie oarecare, ce NU conŃine
operatorul de egalitate.
SELECT last_name, salary, grade_level
FROM employees, job_grades
WHERE salary BETWEEN lowest_sal AND highest_sal;
• outerjoin - compunerea externă a două tabele diferite completând una dintre relaŃii cu valori
NULL acolo unde nu există în aceasta nici un tuplu ce îndeplineşte condiŃia de corelare. RelaŃia
completată cu valori NULL este cea în dreptul căreia apare “(+)”. Operatorul (+) poate fi plasat
în orice parte a condiŃiei de join, dar nu în ambele părŃi. Full outer join = Left outer join UNION
Right outer join.
SELECT last_name, department_name,location_id
FROM employees e, departments d
WHERE e.department_id(+) = d.department_id;
• selfjoin - compunerea externă a unui tabel cu el însuşi după o condiŃie dată.
SELECT sef.last_name, angajat.last_name
FROM employees sef, employees angajat
WHERE sef.employee_id = angajat.manager_id
ORDER BY sef.last_name;
1. Pentru fiecare angajat să se afişeze numele, codul şi numele departamentului.
SELECT last_name, e.department_id, department_name
FROM employees e, departments d
WHERE e.department_id = d.department_id;
2. Să se afişeze numele angajatului, numele departamentului pentru toŃi angajaŃii care câştigă comision.
3. Să se listeze numele job-urile care există în departamentul 30.
SELECT DISTINCT job_title
FROM employees e, jobs j
WHERE e.job_id = j.job_id
AND department_id = 30;
4. Să se afişeze numele, job-ul şi numele departamentului pentru toŃi angajaŃii care lucrează în Seattle.
5. Să se afişeze numele, salariul, data angajării şi numele departamentului pentru toŃi programatorii care
lucrează în America.
region_name = ‘Americas’
17
job_title = ‘Programmer’
6. Să se afişeze numele salariaŃilor şi numele departamentelor în care lucrează. Se vor afişa şi salariaŃii care
nu lucrează într-un departament (right outher join).
SELECT last_name, department_name
FROM employees e, departments d
WHERE e.department_id = d.department_id(+);
7. Să se afişeze numele departamentelor şi numele salariaŃilor care lucrează în ele. Se vor afişa şi
departamentele care nu au salariaŃi (left outher join).
8. Să se afişeze numele, job-ul, numele departamentului, salariul şi grila de salarizare pentru toŃi angajaŃii.
9. Să se afişeze codul angajatului şi numele acestuia, împreună cu numele şi codul şefului său direct. Se vor
eticheta coloanele Ang#, Angajat, Mgr#, Manager. Să se salveze instrucŃiunea într-un fişier numit
p3_9.sql.
SELECT a.employee_id “Ang#”, a.last_name “Angajat”, b.employee_id “Mgr#”, b.last_name
“Manager”
FROM employees a, employees b
WHERE a.manager_id = b. employee_id;
10. Să se modifice p3_9.sql pentru a afişa toŃi salariaŃii, inclusiv pe cei care nu au şef.
11. Să se afişeze numele salariatului şi data angajării împreună cu numele şi data angajării şefului direct
pentru salariaŃii care au fost angajaŃi înaintea şefilor lor. Se vor eticheta coloanele Angajat, Data_ang,
Manager si Data_mgr.
12. Pentru fiecare angajat din departamentele 20 şi 30 să afişeze numele, codul departamentului şi toŃi
colegii săi (salariaŃii care lucrează în acelaşi departament cu el). Se vor eticheta coloanele corespunzător.
13. Să se afişeze numele şi data angajării pentru salariaŃii care au fost angajaŃi după Fay.
SELECT last_name, hire_date
FROM employees
WHERE hire_date > (SELECT hire_date
FROM employees
WHERE last_name = ‘Fay’);
sau
SELECT a.last_name, a.hire_date
FROM employees a, employees b
WHERE UPPER(b.last_name)=’FAY’ AND a.hire_date>b.hire_date;
14. ScrieŃi o cerere pentru a afişa numele şi salariul pentru toŃi colegii (din acelaşi departament) lui Fay. Se
va exclude Fay.
15. Să se afişeze codul departamentului, codul şi numele angajaŃilor care lucrează în acelaşi departament cu
cel puŃin un angajat al cărui nume conŃine litera “T”. Să se ordoneze după codul departamentului.
SELECT employee_id, last_name, department_id
FROM employees
WHERE department_id IN (SELECT DISTINCT department_id
FROM employees
WHERE UPPER(last_name) LIKE ‘%T%’)
ORDER BY department_id;
16. Să se afişeze numele şi salariul angajaŃilor conduşi direct de Steven King.
SELECT last_name, salary
FROM employees
WHERE manager_id = (SELECT employee_id
FROM employees
18
WHERE UPPER(last_name) ='KING'
AND UPPER(first_name) ='STEVEN' );
17. Să se afişeze numele şi job-ul tuturor angajaŃilor din departamentul ‘Sales’.
18. Să se afişeze numele angajaŃilor, numărul departamentului şi job-ul tuturor salariaŃilor al căror
departament este localizat în Seattle.
SELECT last_name, job_id, department_id
FROM employees
WHERE department_id IN (SELECT department_id
FROM departments
WHERE location_id = (SELECT location_id
FROM locations
WHERE city = ‘Seattle’));
RezolvaŃi această problemă utilizând join-uri.
19. Să se afle dacă există angajaŃi care nu lucrează în departamentul ‘Sales’ şi al căror salariu şi comision
coincid cu salariul şi comisionul unui angajat din departamentul ‘Sales’.
SELECT last_name, salary, commission_pct, department_id
FROM employees
WHERE (salary, commission_pct) IN (SELECT salary, commission_pct
FROM employees e, departments d
WHERE e.department_id = d.department_id
AND department_name = ‘Sales’)
AND department_id <> (SELECT department_id
FROM departments
WHERE department_name = ‘Sales’);
20. ScrieŃi o cerere pentru a afişa numele, numele departamentului şi salariul angajaŃilor care nu câştigă
comision, dar al căror manager coincide cu managerul unui angajat care câştigă comision.
21. ScrieŃi o cerere pentru a afişa angajaŃii care câştigă mai mult decât oricare funcŃionar. SortaŃi rezultatele
după salariu, în ordine descrescătoare.
SELECT last_name, salary, job_id
FROM employees
WHERE salary > (SELECT MAX(salary)
FROM employees
WHERE job_id LIKE '%CLERK')
ORDER BY salary DESC;
22. Să se afişeze codul, numele şi salariul tuturor angajaŃilor care câştigă mai mult decât salariul mediu.
23. Să se afişeze pentru fiecare salariat angajat în luna martie numele său, data angajării şi numele jobului.
24. Să se afişeze pentru fiecare salariat al cărui câştig total lunar este mai mare decât 12000 numele său,
câştigul total lunar şi numele departamentului în care lucrează.
25. Să se afişeze pentru fiecare angajat codul său şi numele joburilor sale anterioare, precum şi intervalul de
timp în care a lucrat pe jobul respectiv.
26. Să se modifice cererea de la punctul 25 astfel încât să se afişeze şi numele angajatului, respectiv codul
jobului său curent.
27. Să se modifice cererea de la punctul 26 astfel încât să se afişeze şi numele jobului său curent.
28. Să se afişeze salariaŃii care au acelaşi manager ca şi angajatul având codul 140.
29. Să se afişeze numele departamentelor care funcŃionează în America.
19
FuncŃii multiple-row (grup). Gruparea datelor.
Aceste tipuri de funcŃii pot fi utilizate pentru a returna informaŃia corespunzătoare fiecăruia dintre
grupurile obŃinute în urma divizării liniilor tabelului cu ajutorul clauzei GROUP BY.
Pot apărea în clauzele SELECT, ORDER BY şi HAVING. Server-ul Oracle aplică aceste funcŃii
fiecărui grup de linii şi returnează un singur rezultat pentru fiecare mulŃime.
Exemple de funcŃii grup: AVG, SUM, MAX, MIN, COUNT etc.
Tipurile de date ale argumentelor funcŃiilor grup pot fi CHAR, VARCHAR2, NUMBER sau DATE.
FuncŃiile AVG şi SUM, operează numai asupra valorilor numerice. FuncŃiile MAX şi MIN pot opera asupra
valorilor numerice, caracter sau dată calendaristică.
Toate funcŃiile grup, cu excepŃia lui COUNT(*), ignoră valorile null. COUNT(expresie)
returnează numărul de linii pentru care expresia dată nu are valoarea null. FuncŃia COUNT returnează
un număr mai mare sau egal cu zero şi nu întoarce niciodată valoarea null.
Când este utilizată clauza GROUP BY, server-ul sortează implicit mulŃimea rezultată în
ordinea crescătoare a valorilor coloanelor după care se realizează gruparea.
AbsenŃa clauzei GROUP BY conduce la aplicarea funcŃiei grup pe mulŃimea tuturor liniilor
tabelului.
În clauza GROUP BY se trec obligatoriu toate coloanele prezente în clauza SELECT, care nu
sunt argument al funcŃiilor grup.
1. Să se afişeze cel mai mare salariu, cel mai mic salariu, suma şi media salariilor tuturor angajatilor.
EtichetaŃi coloanele Maxim, Minim, Suma, respectiv Media. Să se rotunjească rezultatele.
SELECT MIN(salary) min, MAX(salary) max, SUM(salary) suma, ROUND(AVG(salary)) media
FROM employees;
2. Utilizând funcŃia grup COUNT să se determine:
a. numărul total de angajaŃi;
b. numărul de angajaŃi care au manager;
c. numărul de manageri.
3. Să se afişeze diferenŃa dintre cel mai mare şi cel mai mic salariu. EtichetaŃi coloana “Diferenta”.
4. Să se listeze numărul de angajaŃi din departamentul având codul 50.
5. CaŃi angajaŃi din departamentul 80 câştigă comision?
6. Să se selecteze valoarea medie şi suma salariilor pentru toŃi angajaŃii care sunt reprezentanŃi de vânzări
(SA_MAN, SA_REP).
7. Să se selecteze data angajării primei persoane care a fost angajată de companie.
8. Să se afişeze numărul de angajaŃi pentru fiecare job.
SELECT job_id, COUNT(employee_id) nr_angajati
FROM employees
GROUP BY job_id;
9. Să se afişeze minimul, maximul, suma şi media salariilor pentru fiecare departament.
10. Să se afişeze codul departamentului şi media salariilor pentru fiecare job din cadrul acestuia.
SELECT department_id, job_id, AVG(salary)
FROM employees
GROUP BY department_id, job_id;
11. a. Să se afişeze codul departamentelor pentru care salariul minim depăşeşte 5000$.
SELECT department_id, MIN(salary)
FROM employees
GROUP BY department_id
HAVING MIN(salary)>5000;
20
b. Să se modifice cererea anterioară astfel încât să se afişeze şi oraşul în care funcŃionează aceste
departamente.
12. Să se obŃină codul departamentelor şi numărul de angajaŃi al acestora pentru departamentele care au cel
puŃin 10 angajaŃi.
13. Să se obŃină codul departamentelor şi suma salariilor angajaŃilor care lucrează în acestea, în ordine
descrescătoare după sumă. Se consideră angajaŃii care au comision şi departamentele care au mai mult
de 5 angajaŃi.
14. Să se obŃină job-ul pentru care salariul mediu este minim.
SELECT job_id
FROM employees
GROUP BY job_id
HAVING AVG(salary) = (SELECT MIN(AVG(salary))
FROM employees
GROUP BY job_id);
15. Să se afişeze cel mai mare dintre salariile medii pe departamente.
16. a. Să se afişeze codul, numele departamentului şi suma salariilor pe departamente.
SELECT d.department_id, department_name,a.suma
FROM departments d, (SELECT department_id ,SUM(salary) suma
FROM employees
GROUP BY department_id) a
WHERE d.department_id =a.department_id;
17. a. ScrieŃi o cerere pentru a afişa numele departamentului, numărul de angajaŃi şi salariul mediu pentru
angajaŃii din acel departament. Coloanele vor fi etichetate Departament, Nr. angajati, Salariu Mediu.
SELECT department_name “Departament”,
(SELECT COUNT(employee_id)
FROM employees
WHERE department_id = d.department_id ) ” Nr. angajati”,
(SELECT AVG(salary)
FROM employees
WHERE department_id = d.department_id) ”Salariu mediu”
FROM departments d;
b. DaŃi o altă metodă de rezolvare pentru problema anterioară.
18. Să se creeze o cerere prin care să se afişeze numărul total de angajaŃi şi, din acest total, numărul celor
care au fost angajaŃi în 1997, 1998, 1999 şi 2000. Datele vor fi afişate în forma următoare:
Total 1997 1998 1999 2000
--------------------------------------------------------------
50 10 5 25 1
SUM(DECODE(TO_CHAR(hire_date,'yyyy'),1997,1,0))
21
Operatorii ROLLUP şi CUBE
Clauza GROUP BY permite gruparea liniilor selectate după valorile expresiilor precizate în
aceasta. Pentru fiecare grup, va fi returnată o singură linie de informaŃie. Clauza GROUP BY poate
produce grupări superagregat utilizând extensiile CUBE sau ROLLUP.
ROLLUP grupează liniile selectate pe baza valorilor primelor n, n - 1, …, 0 expresii din
specificaŃia GROUP BY şi returnează o singură linie pentru fiecare grup. ROLLUP creează grupări
prin deplasarea într-o singură direcŃie, de la dreapta la stânga, de-a lungul listei de coloane
specificate în clauza GROUP BY. Apoi, se aplică funcŃia agregat acestor grupări. Dacă sunt
specificate n expresii în operatorul ROLLUP, numărul de grupări generate va fi n + 1. Liniile care se
bazează pe valoarea primelor n expresii se numesc linii obişnuite, iar celelalte se numesc linii
superagregat.
GROUP BY ROLLUP (expr_1, expr_2, …, expr_n) generează n+1 tipuri de linii,
corespunzătoare următoarelor grupări:
• GROUP BY (expr_1, expr_2, …, expr_n-1, expr_n)
• GROUP BY (expr_1, expr_2, …, expr_n-1)
• …
• GROUP BY (expr_1, expr_2)
• GROUP BY (expr_1)
• GROUP BY () – corespunzător absenŃei clauzei GROUP BY şi deci, calculului funcŃiilor
grup din cerere pentru întreg tabelul.
CUBE grupează liniile selectate pe baza valorilor tuturor combinaŃiilor posibile ale expresiilor
specificate şi returnează câte o linie totalizatoare pentru fiecare grup. Acest operator este folosit pentru a
produce mulŃimi de rezultate care sunt utilizate în rapoarte. În vreme ce ROLLUP produce subtotalurile
doar pentru o parte dintre combinaŃiile posibile, operatorul CUBE produce subtotaluri pentru toate
combinaŃiile posibile de grupări specificate în clauza GROUP BY, precum şi un total general.
Dacă există n coloane sau expresii în clauza GROUP BY, vor exista 2n combinaŃii posibile
superagregat.
19. Să se afişeze codurile departamentelor în care lucrează cel puŃin un angajat, iar pentru fiecare dintre
acestea şi pentru fiecare manager care lucrează în departamentul respectiv să se afişeze numărul de
salariaŃi. De asemenea, să se afişeze numărul de salariaŃi pentru fiecare departament indiferent de
manager şi numărul total de angajaŃi din companie.
22
-----------------------------------------------------------------------
13
20. Să se afişeze codurile departamentelor în care lucrează cel puŃin un angajat, iar pentru fiecare dintre
acestea şi pentru fiecare manager care lucrează în departamentul respectiv să se afişeze numărul de
salariaŃi. De asemenea, să se afişeze numărul de salariaŃi pentru fiecare departament indiferent de
manager, numărul de angajaŃi subordonaŃi unui manager indiferent de departament şi numărul total de
angajaŃi din companie.
25. ModificaŃi cererea anterioară astfel încât să se afişeze numele departamentelor, titlurile job-urilor şi
valoarea medie a salariilor, pentru:
- fiecare departament şi, în cadrul său pentru fiecare job;
- fiecare departament (indiferent de job);
- fiecare job(indiferent de departament);
- întreg tabelul.
Cum intervin coloanele în obŃinerea rezultatului?
Să se afişeze ’Dept’, dacă departamentul a intervenit în agregare şi ‘Job’, dacă job-ul a intervenit în
agregare.
DECODE(GROUPING(department_name), 0, ‘Dept’)
26. UtilizaŃi cererea de la punctul 20.
a. EliminaŃi clauza WHERE din această cerere. AnalizaŃi rezultatul obŃinut.
b. ModificaŃi cererea obŃinută astfel încât să se identifice dacă o valoare null din rezultat este stocată pe
una dintre coloanele manager_id sau department_id sau este produsă de operatorul CUBE.
27. Clauza GROUPING SETS. Permite obŃinerea numai a anumitor grupări superagregat. Acestea pot fi
precizate prin intermediul clauzei:
24
ObservaŃii:
- sistemul realizează ROLLBACK implicit dacă se închide anormal (defecŃiune hardware sau software,
pană de curent etc.);
- nici o comanda LDD (CREATE, ALTER; DROP) nu poate fi anulată.
1. Ce efect are următoarea secvenŃă de instrucŃiuni?
CREATE TABLE dept_***
AS SELECT * FROM departmets;
SELECT *
FROM dept_***;
SAVEPOINT a;
SAVEPOINT b;
SELECT COUNT(*)
FROM dept_***;
ROLLBACK TO b;
SELECT COUNT(*)
FROM dept_***;
ROLLBACK TO a;
COMMIT;
SELECT *
FROM dept_***;
8. CreaŃi tabele emp1_***, emp2_*** şi emp3_*** cu aceeaşi structură ca tabelul employees. InseraŃi,
utilizând o singură comandă INSERT, informaŃii din tabelul employees:
- în tabelul emp1_*** salariaŃii care au salariul mai mic decât 6000;
- în tabelul emp2_*** salariaŃii care au salariul cuprins între 6000 şi 10000;
- în tabelul emp3_*** salariaŃii care au salariul mai mare decât 10000.
VerificaŃi rezultatele, apoi ştergeŃi toate înregistrările din aceste tabele.
Obs. Clauza ALL a comenzii INSERT determină evaluarea tuturor condiŃiilor din clauzele WHEN. Pentru
cele a căror valoare este TRUE, se inserează înregistrarea specificată în opŃiunea INTO corespunzătoare.
9. Să se creeze tabelul emp0_*** cu aceeaşi structură ca tabelul employees. InseraŃi, utilizând o singură
comandă INSERT, informaŃii din tabelul employees:
- în tabelul emp0_*** salariaŃii care lucrează în departamentul 80;
- în tabelul emp1_*** salariaŃii care au salariul mai mic decât 6000 (care nu se regăsesc în tabelul
emp0_***);
- în tabelul emp2_*** salariaŃii care au salariul cuprins între 6000 şi 10000 (care nu se regăsesc în
tabelele emp0_*** şi emp1_***);
- în tabelul emp3_*** salariaŃii care au salariul mai mare decât 10000 (care nu se regăsesc în tabelele
emp0_***, emp1_*** şi emp2_***).
Obs.
26
Clauza FIRST a comenzii INSERT determină inserarea corespunzătoare primei clauze WHEN a cărei
condiŃie este evaluată TRUE. Toate celelalte clauze WHEN sunt ignorate.
10. Sintaxa simplificată a comenzii DELETE
DELETE FROM nume_tabel
[WHERE conditie];
11. ŞtergeŃi toate înregistrările din tabelele emp_*** şi dept_***. InseraŃi în aceste tabele toate înregistrările
corespunzătoare din employees, respectiv departments. PermanentizaŃi tranzacŃia.
UPDATE emp_***
SET salary = salary * 1.05;
ROLLBACK;
17. SchimbaŃi jobul tuturor salariaŃilor din departamentul 80 care au comision în 'SA_REP'. AnulaŃi
modificările.
18. Să se modifice jobul şi departamentul angajatului având codul 114, astfel încât să fie la fel cu cele ale
angajatului având codul 205.
19. SchimbaŃi salariul şi comisionul celui mai prost plătit salariat din firmă, astfel încât să fie egale cu
salariul si comisionul directorului.
20. Pentru fiecare departament să se mărească salariul celor care au fost angajaŃi primii astfel încât să devină
media salariilor din companie.
21. Să se modifice valoarea emailului pentru angajaŃii care câştigă cel mai mult în departamentul în care
lucrează astfel încât acesta să devină iniŃiala numelui concatenată cu prenumele. Dacă nu are prenume
atunci în loc de acesta apare caracterul ‘.’. AnulaŃi modificările.
27
LABORATOR 6 SQL - LDD
Limbajul de definire a datelor (CREATE, ALTER, DROP)
Crearea tabelelor
CREATE TABLE [schema.]nume_tabel (
nume_coloana tip_de_date [DEFAULT1 expr], ...);
CREATE TABLE nume_tabel [(col1, col2...)]
AS subcerere;
1. Creaţi tabelul salariat_*** având următoarea structură:
Nume Caracteristici Tip
cod_ang NOT NULL NUMBER(4)
nume VARCHAR2(25)
prenume VARCHAR2(25)
functia VARCHAR2(20)
sef NUMBER(4)
Valoare implicită data
data_angajarii DATE
curentă
varsta NUMBER(2)
email CHAR(50)
salariu Valoare implicită 0 NUMBER(9,2)
1
Modificarea tabelelor
Constrângeri
17. Ştergeţi tabelul salariat_***, iar apoi recreaţi-l implementând toate constrângerile la nivel de
tabel.
Observaţie: Constrângerea de tip NOT NULL se poate declara doar la nivel de coloană.
3
Adăugarea constrângerilor ulterior creării tabelului, eliminarea, activarea sau dezactivarea
constrângerilor (ALTER TABLE)
- adaugă constrângeri
ALTER TABLE nume_tabel
ADD [CONSTRAINT nume_constr] tip_constr (coloana);
- elimină constrângeri
ALTER TABLE nume_tabel
DROP [CONSTRAINT nume_constr] tip_constr (coloana);
- activare/dezactivare constrângere
ALTER TABLE nume_tabel
MODIFY CONSTRAINT nume_constr ENABLE|DISABLE;
sau
ALTER TABLE nume_tabel
ENABLE| DISABLE nume_constr;
19. Inseraţi o nouă înregistrare în salariat_*** de forma:
cod nume prenume data_n functia sef data_ang email salariu cod_dep
11-JUN-
2 N2 P2 economist 1 Sysdate E2 2000 10
1960
Ce observaţi? Introduceţi înregistrarea dar specificând valoarea NULL pentru coloana sef.
20. Încercaţi să adăugaţi o constrângere de cheie externă pe cod_dep din salariat_***. Ce
observaţi?
21. Inseraţi o nouă înregistrare în departament_***. Apoi adăugaţi constrângerea de cheie externă
definită anterior.
cod_dep nume loc
10 Economic Bucuresti
22. Inseraţi noi înregistrări în salariat_***, respectiv în departament_***. Care trebuie să fie
ordinea de inserare?
cod nume prenume data_n functia sef data_ang email salariu cod_dep
11-JUN-
3 N3 P3 jurist 2 Sysdate E3 2500 20
1967
5
LABORATOR 7 SQL - LDD
Vizualizări. Secvenţe. Indecşi. Sinonime.
Definirea vizualizărilor
Vizualizările sunt tabele virtuale care sunt construite pe baza unor tabele sau vizualizări,
denumite tabele de bază. Ele nu conţin date ci sunt ca nişte imagini logice asupra datelor din tabelele
de bază. Sunt definite de o cerere SQL, de aceea mai sunt denumite şi cereri stocate.
Avantajele utilizării vizualizărilor:
- restricţionarea accesului la date;
- simplificarea unor cereri complexe;
- prezentarea de diferite imagini asupra datelor.
Vizualizările se pot fi simple sau complexe. Asupra vizualizărilor simple se pot realiza operaţii
LMD. Asupra vizualizărilor complexe nu sunt posibile operaţii LMD în toate cazurile decât dacă sunt
definiţi declanşatori de tip INSTEAD OF.
Caracteristici Simple Complexe
Număr de tabele de baza Un singur tabel Unul sau mai multe tabele
Conţine funcţii Nu Da
Conţine grupări de date Nu Da
1. Să se creeze vizualizarea v_emp_*** care să conţină codul şi numele salariaţilor din tabelul emp_***.
Să se afişeze conţinutul acesteia. Să se insereze o nouă înregistrare în această vizualizare. Ce
observaţi? Să se şteargă vizualizarea v_emp_***.
2. Să se creeze vizualizarea v_emp_*** care să conţină codul, numele, emailul, data angajării, salariul şi
codul jobului salariaţilor din tabelul emp_***. Să se analizeze structura şi conţinutul vizualizării. Să
se insereze o nouă înregistrare în această vizualizare. Să se verifice că noua înregistrare a fost inserată
şi în tabelul de bază.
Observaţie: Trebuie introduse neapărat în vizualizare coloanele care au constrângerea NOT NULL în
tabelul de bază (altfel, chiar dacă tipul vizualizării permite operaţii LMD, acestea nu vor fi posibile
din cauza nerespectării constrângerilor NOT NULL).
DESC v_emp_***
4. Să se şteargă angajatul având codul 400 din vizualizarea creată anterior. Ce efect va avea această
acţiune asupra tabelului de bază?
d) Adăugaţi tabelului emp_*** constrângerea de cheie externă care referă tabelul dept_***, apoi
verificaţi ce coloane din vizualizarea v_emp_dept_*** sunt actualizabile.
7. a) Să se creeze vizualizarea v_emp30_*** care să conţină numele, emailul, data angajării, salariul,
codul jobului şi codul departamentului celor care lucrează în departamentul 30. În această
vizualizare nu se va permite modificarea sau inserarea liniilor ce nu sunt accesibile ei. Daţi un nume
constrângerii.
CREATE VIEW v_emp30_*** AS
SELECT employee_id, last_name, email, hire_date, salary, job_id,
department_id
FROM emp_***
WHERE department_id=30
WITH CHECK OPTION CONSTRAINT ck_option1_***;
DESCRIBE v_emp30_***
UPDATE v_emp30_***
SET department_id =20
WHERE employee_id = 11;
8. Să se creeze o vizualizare (v_dept_***) asupra tabelului dept_*** să nu permită efectuarea nici unei
operaţii LMD. Testaţi operaţiile de inserare, modificare şi ştergere asupra acestei vizualizări.
Obs: Coloana TEXT este de tip LONG. În cazul selectării unei coloane de tip LONG trebuie utilizată
comanda SET LONG n pentru a seta numărul de caractere afişate.
Definirea secvenţelor
O secvenţă este un obiect al bazei de date ce permite generarea de numere întregi unice cu scopul de a
fi folosiţi ca valori pentru cheia primară sau coloane numerice unice. Secvenţele sunt independente de
tabele.
Sintaxa comenzii CREATE SEQUENCE este:
CREATE SEQUENCE nume_secvenţă
[INCREMENT BY n]
[START WITH valoare_start]
[ {MAXVALUE valoare_maximă | NOMAXVALUE} ]
[ {MINVALUE valoare_minimă | NOMINVALUE} ]
[ {CYCLE | NOCYCLE} ]
[ {CACHE n | NOCACHE} ];
- INCREMENT BY specifică diferenţa dintre valorile succesive ale secvenţei (valoare implicită 1).
- START WITH specifică primul număr care va fi generat de secvenţă (valoare implicită 1).
- MAXVALUE, MINVALUE precizează valoarea maximă, respectiv minimă pe care o poate genera
secvenţa. Opţiunile NOMAXVALUE, NOMINVALUE sunt implicite. NOMAXVALUE specifică
valoarea maximă de 1027 pentru o secvenţă crescătoare şi -1 pentru o secvenţă descrescătoare.
NOMINVALUE specifică valoarea minimă 1 pentru o secvenţă crescătoare şi -1026 pentru o secvenţă
descrescătoare.
- CYCLE şi NOCYCLE specifică dacă secvenţa continuă să genereze numere după obţinerea valorii
maxime sau minime. NOCYCLE este opţiunea implicită.
- CACHE n precizează numărul de valori pe care server-ul Oracle le prealocă şi le păstrează în
memorie. În mod implicit, acest număr de valori este 20. Opţiunea CACHE pemite accesul mai rapid la
valorile secvenţei care sunt păstrate în memorie. Aceste valori sunt generate la prima referinţă asupra
secvenţei. Fiecare valoare din secvenţă se furnizează din secvenţa memorată. După utilizarea ultimei
valori prealocate secvenţei, următoarea solicitare a unei valori determină încărcarea unui alt set de
numere în memorie. Pentru a nu fi prealocate şi reţinute în memorie astfel de valori, se utilizează
opţiunea NOCACHE.
Pseudocoloanele NEXTVAL şi CURRVAL permit utilizarea secvenţelor.
- nume_secv.NEXTVAL returnează următoarea valoare a secvenţei, o valoare unică la fiecare
referire. Trebuie aplicată cel puţin o dată înainte de a folosi CURRVAL;
- nume_secv.CURRVAL returnează valoarea curentă a secvenţei.
Pseudocoloanele NEXTVAL şi CURRVAL se pot utiliza în:
- lista SELECT a comenzilor ce nu fac parte din subcereri;
- lista SELECT a unei cereri ce apare într-un INSERT;
- clauza VALUES a comenzii INSERT;
- clauza SET a comenzii UPDATE.
Pseudocoloanele NEXTVAL şi CURRVAL nu se pot utiliza:
- în lista SELECT a unei vizualizări;
- într-o comandă SELECT ce conţine DISTINCT, GROUP BY, HAVING sau ORDER BY;
- într-o subcerere în comenzile SELECT, UPDATE, DELETE;
- în clauza DEFAULT a comenzilor CREATE TABLE sau ALTER TABLE.
Ştergerea secvenţelor se realizează cu ajutorul comenzii DROP SEQUENCE.
DROP SEQUENCE nume_secv;
10. Să se creeze o secvenţă care are pasul de incrementare 10 şi începe de la 10, are ca valoare maximă
10000 şi nu ciclează.
CREATE SEQUENCE sec_***
INCREMENT BY 10
START WITH 10
MAXVALUE 10000
NOCYCLE;
11. Să se modifice toate liniile din tabelul emp_***, regenerând codul angajaţilor astfel încât să utilizeze
secvenţa sec_emp***. Să se anuleze modificările.
UPDATE emp_***
SET employee_id = sec_emp***.NEXTVAL;
ROLLBACK;
12. Să se introducă un nou salariat în tabelul emp_*** folosindu-se pentru codul salariatului secvenţa
creată.
INSERT INTO emp_*** (employee_id,last_name,email,hire_date,job_id)
VALUES(sec_emp***.NEXTVAL,'x','x',sysdate,'x');
Definirea indecşilor
Un index este un obiect al unei scheme utilizator care este utilizat de server-ul Oracle pentru a mări
performanţele unui anumit tip de cereri asupra unui tabel.
Indecşii:
- evită scanarea completă a unui tabel la efectuarea unei cereri;
- reduc operaţiile de citire/scriere de pe disc utilizând o cale mai rapidă de acces la date şi anume
pointeri la liniile tabelului care corespund unor anumite valori ale unei chei (coloane);
- sunt independenţi de tabelele pe care le indexează, în sensul că dacă sunt şterşi nu afectează
conţinutul tabelelor sau comportamentul altor indecşi;
- sunt menţinuţi şi utilizaţi automat de către server-ul Oracle;
- sunt şterşi odată cu eliminarea tabelului asociat.
Indecşii pot fi creaţi :
- automat: la definirea unei constrângeri PRIMARY KEY sau UNIQUE;
- manual: cu ajutorul comenzii CREATE INDEX.
Se creează un index atunci când:
- o coloană conţine un domeniu mare de valori;
- o coloană conţine un număr mare de valori null;
- una sau mai multe coloane sunt folosite des în clauza WHERE sau în condiţii de join în programele
de aplicaţii;
- tabelul este mare şi de obicei cererile obţin mai puţin de 2%-4% din liniile tabelului;
- tabelul nu este modificat frecvent.
Sintaxa comenzii CREATE INDEX:
CREATE [UNIQUE] INDEX nume_index
ON tabel (coloana1 [, coloana2…]);
Modificarea unui index se face prin comanda ALTER INDEX.
Eliminarea unui index se face prin comanda: DROP INDEX nume_index;
14. Să se creeze un index neunic, emp_last_name_idx_***, asupra coloanei last_name din tabelul
emp_***.
15. Să se creeze indecşi unici asupra codului angajatului (employee_id) şi asupra combinaţiei last_name,
first_name, hire_date.
16. Creaţi un index neunic asupra coloanei department_id din emp_*** pentru a eficientiza joinurile
dintre acest tabel şi dept_***.
Definirea sinonimelor
Pentru a simplifica accesul la obiecte se pot asocia sinonime acestora.
Crearea unui sinonim este utilă pentru a evita referirea unui obiect ce aparţine altui utilizator
prefixându-l cu numele utilizatorului şi pentru a scurta numele unor obiecte cu numele prea lung.
Comanda pentru crearea sinonimelor este:
CREATE [PUBLIC] SYNONYM nume_sinonim
FOR obiect;
Eliminarea sinonimelor se face prin comanda DROP SYNONYM nume_sinonim;
17. Creaţi un sinonim public se_*** pentru tabelul emp_***.
18. Creaţi un sinonim pentru vizualizarea v_dept_***.
19. Utilizând sinonimele create anterior, afişaţi informaţii depre salariţi şi despre departamente.
SELECT table_name
FROM user_tables
ORDER BY table_name;
2. Definiţiile şi numele constrângerilor:
SELECT view_name
FROM user_views;
5. Informaţii referitoare la secvenţe:
SELECT index_name
FROM user_ind_columns;
Operatori pe mulţimi
Operatorii pe mulţimi combină rezultatele obţinute din două sau mai multe interogări. Cererile care
conţin operatori pe mulţimi se numesc cereri compuse.
Există patru operatori pe mulţimi: UNION, UNION ALL, INTERSECT şi MINUS.
Operatorul UNION returnează toate liniile selectate de două cereri, eliminând duplicatele. Acest
operator nu ignoră valorile null şi are precedenţă mai mică decât operatorul IN.
Operatorul UNION ALL returnează toate liniile selectate de două cereri, fără a elimina duplicatele.
Precizările făcute asupra operatorului UNION sunt valabile şi în cazul operatorului UNION ALL. În
cererile asupra cărora se aplică UNION ALL nu poate fi utilizat cuvântul cheie DISTINCT.
Operatorul INTERSECT returnează toate liniile comune cererilor asupra cărora se aplică. Acest
operator nu ignoră valorile null.
Operatorul MINUS determină liniile returnate de prima cerere care nu apar în rezultatul celei de-a doua
cereri. Pentru ca operatorul MINUS să funcţioneze, este necesar ca toate coloanele din clauza WHERE
să se afle şi în clauza SELECT.
4. Să se creeze o cerere prin care să se afişeze numărul total de angajaţi şi, din acest total, numărul celor care
au fost angajaţi în 1997.
SELECT COUNT(*)|| ' nr_total ' numar
FROM employees
UNION
SELECT COUNT(*)|| ' nr_1980 ' numar_1997
FROM employees
WHERE TO_CHAR(hire_date,'YYYY')=1997;
5. Utilizând operatorul UNION, să se listeze codul salariaţilor, codul şi numele departamentelor.
SELECT employee_id, department_id, TO_CHAR(NULL) nume
FROM employees
UNION
SELECT TO_NUMBER(NULL), department_id, department_name
FROM departments;
6. Să se afişeze reuniunea cu duplicate, respectiv fără duplicate a următoarelor mulţimi:
- codul, codul jobului şi codul departamentului salariaţilor din tabelul employees;
- codul, codul jobului şi codul departamentului salariaţilor din tabelul job_history.
Ordonaţi rezultatul după codul angajatului.
Observaţie: Clauza ORDER BY trebuie să apară la final.
7. Să se afişeze numele departamentelor şi numele angajaţilor. Se vor afişa şi departamenntele în care nu
lucrează nimeni, respectiv şi angajaţii care nu lucrează în nici un departament (full outer join).
Utilizaţi operatorul UNION. Ce rezultat s-ar obţine dacă am utiliza operatorul UNION ALL?
8. Să se obţină codul, codul jobului şi salariul pentru toţi angajaţii, incluzând:
- angajaţii curenţi;
- angajaţii care au avut şi alte joburi; pentru aceştia valoarea salariului va fi null.
Ordonaţi rezultatul după codul salariatului.
9. Să se obţină, folosind operatorul INTERSECT, angajaţii care au salariul < 3000 şi al căror nume conţine
litera a pe poziţia 3.
SELECT employee_id, last_name
FROM employees
WHERE salary<3000
INTERSECT
SELECT employee_id, last_name
FROM employees
WHERE UPPER(last_name) LIKE '__A%';
10. Să se obţină codul, codul jobului şi codul departamentului angajaţilor care în trecut au mai lucrat pe acelaşi
job şi în acelaşi departament ca în prezent. Utilizaţi operatorul INTERSECT.
11. Modificaţi cererea anterioară astfel încât să obţineţi numele angajaţilor care îndeplinesc condiţia impusă.
12. Să se afişeze codurile departamentelor care nu au angajaţi, implementând operatorul MINUS.
SELECT department_id
FROM departments
MINUS
SELECT DISTINCT department_id
FROM employees;
15. a. Să se obţină codurile locaţiilor în care nu există departamente. Utilizaţi operatorul MINUS.
b. Daţi o altă metodă de rezolvare.
Limbajul de definire a datelor (DDL). CREATE, ALTER, DROP
Definirea tabelelor
CREATE TABLE [schema.]nume_tabel (
nume_coloana tip_de_date [DEFAULT1 expr], ...);
1
Modificarea tabelelor
Constrângeri
2
ObservaŃie:
Constrângerile de tip CHECK se pot implementa la nivel de coloană doar dacă nu referă o altă coloană a
tabelului.
- adaugă constrângeri
ALTER TABLE nume_tabel
ADD [CONSTRAINT nume_constr] tip_constr (coloana);
- elimină constrângeri
ALTER TABLE nume_tabel
3
DROP [CONSTRAINT nume_constr] tip_constr (coloana);
- activare/dezactivare constrângere
ALTER TABLE nume_tabel
MODIFY CONSTRAINT nume_constr ENABLE|DISABLE;
sau
ALTER TABLE nume_tabel
ENABLE| DISABLE nume_constr;
19. InseraŃi o nouă înregistrare în salariat_*** de forma:
cod_dep
cod nume prenume data_n functia sef data_ang email salariu
11-JUN-
2 N2 P2 economist 1 Sysdate E2 2000 10
1960
Ce observaŃi? IntroduceŃi înregistrarea dar specificând valoarea NULL pentru coloana sef.
20. ÎncercaŃi să adăugaŃi o constrângere de cheie externă pe cod_dep din salariat_***. Ce observaŃi?
21. InseraŃi o nouă înregistrare în departament_***. Apoi adăugaŃi constrângerea de cheie externă definită
anterior.
22. InseraŃi noi înregistrări în salariat_***, respectiv în departament_***. Care trebuie să fie ordinea de
inserare?
cod_dep
cod nume prenume data_n functia sef data_ang email salariu
11-JUN- 20
3 N3 P3 jurist 2 Sysdate E3 2500
1967
Definirea vizualizărilor
Sintaxa simplificată a comenzii CREATE VIEW este:
CREATE [OR REPLACE] [FORCE | NOFORCE] VIEW nume_view [(alias, alias, ..)]
AS subcerere
[WITH CHECK OPTION [CONSTRAINT nume_constr]]
[WITH READ ONLY [CONSTRAINT nume_constr]];
- FORCE permite crearea vizualizarea înainte de a defini tabelele de bază;
- subcererea poate fi oricât de complexă dar nu poate conŃine clauza ORDER BY;
- WITH CHECK OPTION permite inserarea şi modificarea prin intermediul vizualizării numai a
liniilor ce sunt accesibile vizualizării; dacă lipseşte numele constrângerii atunci sistemul asociază
un nume implicit de tip SYS_Cn acestei constrângeri;
- WITH READ ONLY asigură că prin intermediul vizualizării nu se pot executa operaŃii LMD.
Eliminarea unei vizualizări se face prin comanda DROP VIEW :
DROP VIEW nume_viz;
1. Să se creeze vizualizarea v_emp_*** care să conŃină codul şi numele salariaŃilor din tabelul emp_***. Să
se afişeze conŃinutul acesteia. Să se insereze o nouă înregistrare în această vizualizare. Ce observaŃi? Să
se şteargă vizualizarea v_emp_***.
2. Să se creeze vizualizarea v_emp_*** care să conŃină codul, numele, emailul, data angajării, salariul şi
codul jobului salariaŃilor din tabelul emp_***. Să se analizeze structura şi conŃinutul vizualizării. Să se
insereze o nouă înregistrare în această vizualizare. Să se verifice că noua înregistrare a fost inserată şi în
tabelul de bază.
DESC v_emp_***
5
INSERT INTO v_emp_***
VALUES (400,’N1’,’E1’,SYSDATE,5000,’SA_REP’);
d) AdăugaŃi tabelului emp_*** constrângerea de cheie externă care referă tabelul dept_***, apoi
verificaŃi ce coloane din vizualizarea v_emp_dept_*** sunt actualizabile.
e) RecreaŃi vizualizarea v_emp_dept_***, apoi verificaŃi ce coloane sunt actualizabile.
f) InseraŃi o linie prin intermediul acestei vizualizări.
Obs. Tabelul ale cărui coloane sunt actualizabile este protejat prin cheie.
g) Ce efect are o operaŃie de ştergere prin intermediul vizualizării v_emp_dept_***? ComentaŃi.
7. a) Să se creeze vizualizarea v_emp30_*** care să conŃină numele, emailul, data angajării, salariul,
codul jobului şi codul departamentului celor care lucrează în departamentul 30. În această
vizualizare nu se va permite modificarea sau inserarea liniilor ce nu sunt accesibile ei. DaŃi un nume
constrângerii.
6
c) Să se încerce prin intermediul vizualizării inserarea unui angajat în departamentul 10 şi a unui angajat
în departamentul 30.
d) Să se încerce prin intermediul vizualizării modificarea departamentului unui angajat.
UPDATE v_emp30_***
SET department_id =20
WHERE employee_id = 11;
8. Să se creeze o vizualizare (v_dept_***) asupra tabelului dept_*** să nu permită efectuarea nici unei
operaŃii LMD. TestaŃi operaŃiile de inserare, modificare şi ştergere asupra acestei vizualizări.
Obs: Coloana TEXT este de tip LONG. În cazul selectării unei coloane de tip LONG trebuie utilizată
comanda SET LONG n pentru a seta numărul de caractere afişate.
Definirea secvenŃelor
Sintaxa comenzii CREATE SEQUENCE este:
CREATE SEQUENCE nume_secvenŃă
[INCREMENT BY n]
[START WITH valoare_start]
[ {MAXVALUE valoare_maximă | NOMAXVALUE} ]
[ {MINVALUE valoare_minimă | NOMINVALUE} ]
[ {CYCLE | NOCYCLE} ]
[ {CACHE n | NOCACHE} ];
Ştergerea secvenŃelor se realizează cu ajutorul comenzii DROP SEQUENCE.
DROP SEQUENCE nume_secv;
10. Să se creeze o secvenŃă care are pasul de incrementare 10 şi începe de la 10, are ca valoare maximă
10000 şi nu ciclează.
7
UPDATE emp_***
SET employee_id = sec_emp***.NEXTVAL;
ROLLBACK;
12. Să se introducă un nou salariat în tabelul emp_*** folosindu-se pentru codul salariatului secvenŃa creată.
13. Să se afişeze valoarea curentă a secvenŃei.
ExerciŃiu
a) CreaŃi o secvenŃă pentru generarea codurilor de departamente, seq_dept_***. SecvenŃa va începe de
la 200, va creşte cu 10 la fiecare pas şi va avea valoarea maximă 20000, nu va cicla.
b) Să se selecteze informaŃii despre secvenŃele utilizatorului curent (nume, valoare minimă, maximă,
de incrementare, ultimul număr generat). Se va utiliza vizualizarea user_sequences.
c) Să se insereze o înregistrare nouă în DEPT_*** utilizând secvenŃa creată.
d) Să se selecteze valoarea curentă a secvenŃei.
e) Să se şteargă secvenŃa.
Definirea indecşilor
Sintaxa comenzii CREATE INDEX:
CREATE [UNIQUE] INDEX nume_index
ON tabel (coloana1 [, coloana2…]);
Modificarea unui index se face prin comanda ALTER INDEX.
Eliminarea unui index se face prin comanda: DROP INDEX nume_index;
14. Să se creeze un index neunic, emp_last_name_idx_***, asupra coloanei last_name din tabelul
emp_***.
15. Să se creeze indecşi unici asupra codului angajatului (employee_id) şi asupra combinaŃiei last_name,
first_name, hire_date.
16. CreaŃi un index neunic asupra coloanei department_id din emp_*** pentru a eficientiza joinurile
dintre acest tabel şi dept_***.
Definirea sinonimelor
Comanda pentru crearea sinonimelor este:
CREATE [PUBLIC] SYNONYM nume_sinonim
FOR obiect;
Eliminarea sinonimelor se face prin comanda DROP SYNONYM nume_sinonim;
17. CreaŃi un sinonim public se_*** pentru tabelul emp_***.
18. CreaŃi un sinonim pentru vizualizarea v_dept_***.
19. Utilizând sinonimele create anterior, afişaŃi informaŃii depre salariŃi şi despre departamente.
8
Limbajul de interogare al datelor (DQL). SELECT
CERERI MONOTABEL
1. AnalizaŃi sintaxa simplificată a comenzii SELECT. Care dintre clauze sunt obligatorii?
SELECT { [ {DISTINCT | UNIQUE} | ALL] lista_campuri | *}
FROM [nume_schemă.]nume_obiect ]
[, [nume_schemă.]nume_obiect …]
[WHERE condiŃie_clauza_where]
[GROUP BY expresie [, expresie …]
[HAVING condiŃie_clauza_having] ]
[ORDER BY {expresie | poziŃie} [, {expresie | poziŃie} …] ]
9
Obs: Operatorul de concatenare este “||”. Şirurile de caractere se specifică între apostrofuri (NU
ghilimele, caz în care ar fi interpretate ca alias-uri).
SELECT last_name|| ' ' || first_name " Nume si prenume "
FROM employees;
11. Să se listeze numele şi salariul angajaŃilor care câştigă mai mult de 10000 $.
SELECT last_name, salary
FROM employees
WHERE salary > 10000;
12. Să se modifice cererea anterioară astfel încât să afişeze numele şi salariul pentru toŃi angajaŃii al căror
salariu este cuprins între 5000$ şi10000$.
Obs: Pentru testarea apartenenŃei la un domeniu de valori se poate utiliza operatorul
[NOT] BETWEEN valoare1 AND valoare2
SELECT last_name, salary
FROM employees
WHERE salary BETWEEN 5000 AND 10000;
13. Să se creeze o cerere pentru a afişa numele angajatului şi numărul departamentului pentru angajatul 104.
14. Să se afişeze numele şi salariul pentru toŃi angajaŃii din departamentele 10 sau 30, în ordine alfabetică a
numelor.
Obs: ApartenenŃa la o mulŃime finită de valori se poate testa prin intermediul operatorului IN, urmat de
lista valorilor între paranteze şi separate prin virgule:
expresie IN (valoare_1, valoare_2, …, valoare_n)
15. Să listeze numele şi salariile angajaŃilor care câştigă mai mult de 10000 $ şi lucrează în departamentul
10 sau 30. Se vor eticheta coloanele drept Angajat si Salariu lunar.
16. Care este data curentă?
Obs: Pseudocoloana care returnează data curentă este SYSDATE. Pentru completarea sintaxei obligatorii
a comenzii SELECT, se utilizează tabelul DUAL:
SELECT SYSDATE
FROM dual;
Datele calendaristice pot fi formatate cu ajutorul funcŃiei TO_CHAR(data, format), unde formatul poate
fi alcătuit dintr-o combinaŃie a următoarelor elemente:
Element SemnificaŃie
D Numărul zilei din săptămână (duminică=1;
luni=2; …sâmbătă=6).
DD Numărul zilei din lună.
DDD Numărul zilei din an.
DY Numele zilei din săptămână, printr-o
abreviere de 3 litere (MON, THU etc.)
DAY Numele zilei din săptămână, scris în
întregime.
MM Numărul lunii din an.
MON Numele lunii din an, printr-o abreviere de 3
litere (JAN, FEB etc.)
MONTH Numele lunii din an, scris în întregime.
Y Ultima cifră din an
YY, YYY, YYYY Ultimele 2, 3, respectiv 4 cifre din an.
YEAR Anul, scris în litere (ex: two thousand
four).
HH12, HH24 Orele din zi, între 0-12, respectiv 0-24.
10
MI Minutele din oră.
SS Secundele din minut.
SSSSS Secundele trecute de la miezul nopŃii.
17. Să se afişeze numele şi data angajării pentru fiecare salariat care a fost angajat în 1987. Se cer 2 soluŃii:
una în care se lucrează cu formatul implicit al datei şi alta prin care se formatează data.
Varianta1:
SELECT first_name, last_name, hire_date
FROM employees
WHERE hire_date LIKE (‘%87’);
Varianta 2:
SELECT first_name, last_name, hire_date
FROM employees
WHERE TO_CHAR(hire_date, ‘YYYY’)=’1987’;
Sunt obligatorii ghilimelele de la şirul ‘1987’? Ce observaŃi?
18. Să se afişeze numele şi job-ul pentru toŃi angajaŃii care nu au manager.
SELECT last_name, job_id
FROM employees
WHERE manager_id IS NULL;
19. Să se afişeze numele, salariul şi comisionul pentru toŃi salariaŃii care câştigă comisioane. Să se sorteze
datele în ordine descrescătoare a salariilor, iar pentru cei care au acelaşi salariu în ordine crescătoare a
comisioanelor.
SELECT last_name, salary, commission_pct
FROM employees
WHERE commission_pct IS NOT NULL
ORDER BY salary DESC, commission_pct ASC;
20. Să se listeze numele tuturor angajaŃilor care au a treia litera din nume 'a'.
Obs: Pentru a forma măştile de caractere utilizate împreună cu operatorul LIKE cu scopul de a compara
şirurile de caractere, se utilizează:
% - reprezentând orice şir de caractere, inclusiv şirul vid;
_ (underscore) – reprezentând un singur caracter.
SELECT DISTINCT last_name
FROM employees
WHERE last_name LIKE '__a%';
2. Să se afişeze pentru fiecare angajat din departamentul 20 un şir de caractere de forma "FuncŃia
salariatului {prenume} {nume} este {cod functie}". Să se afişeze prenumele cu iniŃiala litera mare, iar
numele cu litere mari (Stephen KING), iar codul funcŃiei să se afişeze cu litere mici.
3. Să se afişeze pentru angajatul cu numele 'HIGGINS' codul, numele şi codul departamentului. Cum se
scrie condiŃia din WHERE astfel încât să existe siguranŃa ca angajatul 'HIGGINS' va fi găsit oricum ar fi
fost introdus numele acestuia? Căutarea trebuie să nu fie case-sensitive, iar eventualele blank-uri care
preced sau urmează numelui trebuie ignorate.
UPPER(TRIM(last_name))='HIGGINS';
4. Să se afişeze pentru toŃi angajaŃii al căror nume se termină în 'n', codul, numele, lungimea numelui şi
poziŃia din nume în care apare prima data litera 'a'. AsociaŃi aliasuri coloanelor returnate de cerere.
SELECT employee_id, last_name, LENGTH(last_name), INSTR(UPPER(last_name), 'A')
FROM employees
WHERE SUBSTR(last_name,-1)='n';
5. AnalizaŃi următoarele funcŃii aritmetice:
FuncŃie SemnificaŃie Exemplu
ROUND(1.6) = 2
Returnează valoarea rotunjită a expresiei
ROUND(1.4) = 1
până la n zecimale. Daca n este negativ sunt
ROUND (expresie [, n]) ROUND (1234.56,1) = 1234.6
rotunjite cifre din stânga virgulei. Valoarea
ROUND (1230.56, -2) = 1200
implicită pentru n este 0.
ROUND (1260.56, -2) = 1300
6. Să se afişeze detalii despre salariaŃii care au lucrat un număr întreg de săptămâni până la data curentă.
MOD(ROUND(SYSDATE – hire_date), 7)=0;
7. Să se afişeze numele, salariul şi numărul de mii al salariului rotunjit la 2 zecimale pentru cei care nu au
salariul divizibil cu 1000.
8. AnalizaŃi următoarele operaŃii pe expresii de tip dată calendaristică:
Tipul de date al
OperaŃie Descriere
rezultatului
date -/+ number Date Scade/Adaugă un număr de zile dintr-o / la o dată.
date1 - date2 Number Întoarce numărul de zile dintre două date calendaristice.
date +/-
Date Scade/Adaugă un număr de ore la o / dintr-o dată calendaristică.
number/24
9. Să se afişeze data (luna, ziua, ora, minutul si secunda) de peste 10 zile.
13
SYSDATE+10
10. Să se afişeze numărul de zile rămase până la sfârşitul anului.
ROUND(TO_DATE(’31-DEC-2009’)-SYSDATE)
11. a. Să se afişeze data de peste 12 ore.
SYSDATE+12/24
b. Să se afişeze data de peste 5 minute.
SYSDATE+1/288
12. AnalizaŃi următoarele funcŃii pentru prelucrarea datelor calendaristice:
FuncŃie SemnificaŃie Exemplu
SYSDATE Întoarce data şi timpul curent
Returnează numărul de luni dintre
data date1 şi data date2. Rezultatul
MONTHS_BETWEEN poate fi pozitiv sau negativ după cum ROUND(MONTHS_BETWEEN
(date1, date2) date1 este mai recentă sau nu faŃă de (SYSDATE + 31, SYSDATE)) = 1
date2. Zecimalele reprezintă parŃi
dintr-o luna!
Adaugă n luni la o data specificată. MONTHS_BETWEEN
ADD_MONTHS (date, n) Valoarea n trebuie să fie întreagă (ADD_MONTHS(SYSDATE, 3),
(pozitivă sau negativă). SYSDATE) = 3
NEXT_DAY('15-dec-2006','Monday')
Returnează data corespunzătoare
= '18-dec-2006'
NEXT_DAY (date, char) primei zile a săptămânii specificate
NEXT_DAY ('15-dec-2006',1)
(char) care urmează după date.
= '18-dec-2006'
13. Să se afişeze numele angajatului, data angajării şi data negocierii salariului, care a avut loc în prima zi de
Luni, după 6 luni de serviciu. EtichetaŃi această coloană “Negociere”.
NEXT_DAY(ADD_MONTHS(hire_date, 6), ‘Monday’)
14. Pentru fiecare angajat să se afişeze numele şi numărul de luni de la data angajării. EtichetaŃi coloana
“Luni lucrate”. Să se ordoneze rezultatul după numărul de luni lucrate. Se va rotunji numărul de luni la
cel mai apropiat număr întreg.
SELECT last_name, ROUND(MONTHS_BETWEEN(SYSDATE, hire_date)) “Luni lucrate”
FROM employees
ORDER BY MONTHS_BETWEEN(SYSDATE, hire_date);
16
- dacă lucrează de mai mult de 200 de luni atunci salariul va fi mărit cu 20%;
- dacă lucrează de mai mult de 150 de luni, dar mai puŃin de 200 de luni, atunci salariul va fi mărit cu
15%;
- dacă lucrează de mai mult de 100 de luni, dar mai puŃin de 150 de luni, atunci salariul va fi mărit cu
10%;
- altfel, salariul va fi mărit cu 5%.
Tipuri de join:
• equijoin (se mai numeşte inner join sau simple join) - compunerea a două tabele diferite după o
condiŃie ce conŃine operatorul de egalitate.
SELECT last_name, department_name, location_id, e.department_id
FROM employees e, departments d
WHERE e.department_id = d.department_id;
Obs: Numele sau alias-urile tabelelor sunt obligatorii în dreptul coloanelor care au acelaşi nume
în mai multe tabele.
• nonequijoin - compunerea a două relaŃii tabele după o condiŃie oarecare, ce NU conŃine
operatorul de egalitate.
SELECT last_name, salary, grade_level
FROM employees, job_grades
WHERE salary BETWEEN lowest_sal AND highest_sal;
• outerjoin - compunerea externă a două tabele diferite completând una dintre relaŃii cu valori
NULL acolo unde nu există în aceasta nici un tuplu ce îndeplineşte condiŃia de corelare. RelaŃia
completată cu valori NULL este cea în dreptul căreia apare “(+)”. Operatorul (+) poate fi plasat
în orice parte a condiŃiei de join, dar nu în ambele părŃi. Full outer join = Left outer join UNION
Right outer join.
SELECT last_name, department_name,location_id
FROM employees e, departments d
WHERE e.department_id(+) = d.department_id;
• selfjoin - compunerea externă a unui tabel cu el însuşi după o condiŃie dată.
SELECT sef.last_name, angajat.last_name
FROM employees sef, employees angajat
WHERE sef.employee_id = angajat.manager_id
ORDER BY sef.last_name;
1. Pentru fiecare angajat să se afişeze numele, codul şi numele departamentului.
SELECT last_name, e.department_id, department_name
FROM employees e, departments d
WHERE e.department_id = d.department_id;
2. Să se afişeze numele angajatului, numele departamentului pentru toŃi angajaŃii care câştigă comision.
3. Să se listeze numele job-urile care există în departamentul 30.
SELECT DISTINCT job_title
FROM employees e, jobs j
WHERE e.job_id = j.job_id
AND department_id = 30;
4. Să se afişeze numele, job-ul şi numele departamentului pentru toŃi angajaŃii care lucrează în Seattle.
5. Să se afişeze numele, salariul, data angajării şi numele departamentului pentru toŃi programatorii care
lucrează în America.
region_name = ‘Americas’
17
job_title = ‘Programmer’
6. Să se afişeze numele salariaŃilor şi numele departamentelor în care lucrează. Se vor afişa şi salariaŃii care
nu lucrează într-un departament (right outher join).
SELECT last_name, department_name
FROM employees e, departments d
WHERE e.department_id = d.department_id(+);
7. Să se afişeze numele departamentelor şi numele salariaŃilor care lucrează în ele. Se vor afişa şi
departamentele care nu au salariaŃi (left outher join).
8. Să se afişeze numele, job-ul, numele departamentului, salariul şi grila de salarizare pentru toŃi angajaŃii.
9. Să se afişeze codul angajatului şi numele acestuia, împreună cu numele şi codul şefului său direct. Se vor
eticheta coloanele Ang#, Angajat, Mgr#, Manager. Să se salveze instrucŃiunea într-un fişier numit
p3_9.sql.
SELECT a.employee_id “Ang#”, a.last_name “Angajat”, b.employee_id “Mgr#”, b.last_name
“Manager”
FROM employees a, employees b
WHERE a.manager_id = b. employee_id;
10. Să se modifice p3_9.sql pentru a afişa toŃi salariaŃii, inclusiv pe cei care nu au şef.
11. Să se afişeze numele salariatului şi data angajării împreună cu numele şi data angajării şefului direct
pentru salariaŃii care au fost angajaŃi înaintea şefilor lor. Se vor eticheta coloanele Angajat, Data_ang,
Manager si Data_mgr.
12. Pentru fiecare angajat din departamentele 20 şi 30 să afişeze numele, codul departamentului şi toŃi
colegii săi (salariaŃii care lucrează în acelaşi departament cu el). Se vor eticheta coloanele corespunzător.
13. Să se afişeze numele şi data angajării pentru salariaŃii care au fost angajaŃi după Fay.
SELECT last_name, hire_date
FROM employees
WHERE hire_date > (SELECT hire_date
FROM employees
WHERE last_name = ‘Fay’);
sau
SELECT a.last_name, a.hire_date
FROM employees a, employees b
WHERE UPPER(b.last_name)=’FAY’ AND a.hire_date>b.hire_date;
14. ScrieŃi o cerere pentru a afişa numele şi salariul pentru toŃi colegii (din acelaşi departament) lui Fay. Se
va exclude Fay.
15. Să se afişeze codul departamentului, codul şi numele angajaŃilor care lucrează în acelaşi departament cu
cel puŃin un angajat al cărui nume conŃine litera “T”. Să se ordoneze după codul departamentului.
SELECT employee_id, last_name, department_id
FROM employees
WHERE department_id IN (SELECT DISTINCT department_id
FROM employees
WHERE UPPER(last_name) LIKE ‘%T%’)
ORDER BY department_id;
16. Să se afişeze numele şi salariul angajaŃilor conduşi direct de Steven King.
SELECT last_name, salary
FROM employees
WHERE manager_id = (SELECT employee_id
FROM employees
18
WHERE UPPER(last_name) ='KING'
AND UPPER(first_name) ='STEVEN' );
17. Să se afişeze numele şi job-ul tuturor angajaŃilor din departamentul ‘Sales’.
18. Să se afişeze numele angajaŃilor, numărul departamentului şi job-ul tuturor salariaŃilor al căror
departament este localizat în Seattle.
SELECT last_name, job_id, department_id
FROM employees
WHERE department_id IN (SELECT department_id
FROM departments
WHERE location_id = (SELECT location_id
FROM locations
WHERE city = ‘Seattle’));
RezolvaŃi această problemă utilizând join-uri.
19. Să se afle dacă există angajaŃi care nu lucrează în departamentul ‘Sales’ şi al căror salariu şi comision
coincid cu salariul şi comisionul unui angajat din departamentul ‘Sales’.
SELECT last_name, salary, commission_pct, department_id
FROM employees
WHERE (salary, commission_pct) IN (SELECT salary, commission_pct
FROM employees e, departments d
WHERE e.department_id = d.department_id
AND department_name = ‘Sales’)
AND department_id <> (SELECT department_id
FROM departments
WHERE department_name = ‘Sales’);
20. ScrieŃi o cerere pentru a afişa numele, numele departamentului şi salariul angajaŃilor care nu câştigă
comision, dar al căror manager coincide cu managerul unui angajat care câştigă comision.
21. ScrieŃi o cerere pentru a afişa angajaŃii care câştigă mai mult decât oricare funcŃionar. SortaŃi rezultatele
după salariu, în ordine descrescătoare.
SELECT last_name, salary, job_id
FROM employees
WHERE salary > (SELECT MAX(salary)
FROM employees
WHERE job_id LIKE '%CLERK')
ORDER BY salary DESC;
22. Să se afişeze codul, numele şi salariul tuturor angajaŃilor care câştigă mai mult decât salariul mediu.
23. Să se afişeze pentru fiecare salariat angajat în luna martie numele său, data angajării şi numele jobului.
24. Să se afişeze pentru fiecare salariat al cărui câştig total lunar este mai mare decât 12000 numele său,
câştigul total lunar şi numele departamentului în care lucrează.
25. Să se afişeze pentru fiecare angajat codul său şi numele joburilor sale anterioare, precum şi intervalul de
timp în care a lucrat pe jobul respectiv.
26. Să se modifice cererea de la punctul 25 astfel încât să se afişeze şi numele angajatului, respectiv codul
jobului său curent.
27. Să se modifice cererea de la punctul 26 astfel încât să se afişeze şi numele jobului său curent.
28. Să se afişeze salariaŃii care au acelaşi manager ca şi angajatul având codul 140.
29. Să se afişeze numele departamentelor care funcŃionează în America.
19
FuncŃii multiple-row (grup). Gruparea datelor.
Aceste tipuri de funcŃii pot fi utilizate pentru a returna informaŃia corespunzătoare fiecăruia dintre
grupurile obŃinute în urma divizării liniilor tabelului cu ajutorul clauzei GROUP BY.
Pot apărea în clauzele SELECT, ORDER BY şi HAVING. Server-ul Oracle aplică aceste funcŃii
fiecărui grup de linii şi returnează un singur rezultat pentru fiecare mulŃime.
Exemple de funcŃii grup: AVG, SUM, MAX, MIN, COUNT etc.
Tipurile de date ale argumentelor funcŃiilor grup pot fi CHAR, VARCHAR2, NUMBER sau DATE.
FuncŃiile AVG şi SUM, operează numai asupra valorilor numerice. FuncŃiile MAX şi MIN pot opera asupra
valorilor numerice, caracter sau dată calendaristică.
Toate funcŃiile grup, cu excepŃia lui COUNT(*), ignoră valorile null. COUNT(expresie)
returnează numărul de linii pentru care expresia dată nu are valoarea null. FuncŃia COUNT returnează
un număr mai mare sau egal cu zero şi nu întoarce niciodată valoarea null.
Când este utilizată clauza GROUP BY, server-ul sortează implicit mulŃimea rezultată în
ordinea crescătoare a valorilor coloanelor după care se realizează gruparea.
AbsenŃa clauzei GROUP BY conduce la aplicarea funcŃiei grup pe mulŃimea tuturor liniilor
tabelului.
În clauza GROUP BY se trec obligatoriu toate coloanele prezente în clauza SELECT, care nu
sunt argument al funcŃiilor grup.
1. Să se afişeze cel mai mare salariu, cel mai mic salariu, suma şi media salariilor tuturor angajatilor.
EtichetaŃi coloanele Maxim, Minim, Suma, respectiv Media. Să se rotunjească rezultatele.
SELECT MIN(salary) min, MAX(salary) max, SUM(salary) suma, ROUND(AVG(salary)) media
FROM employees;
2. Utilizând funcŃia grup COUNT să se determine:
a. numărul total de angajaŃi;
b. numărul de angajaŃi care au manager;
c. numărul de manageri.
3. Să se afişeze diferenŃa dintre cel mai mare şi cel mai mic salariu. EtichetaŃi coloana “Diferenta”.
4. Să se listeze numărul de angajaŃi din departamentul având codul 50.
5. CaŃi angajaŃi din departamentul 80 câştigă comision?
6. Să se selecteze valoarea medie şi suma salariilor pentru toŃi angajaŃii care sunt reprezentanŃi de vânzări
(SA_MAN, SA_REP).
7. Să se selecteze data angajării primei persoane care a fost angajată de companie.
8. Să se afişeze numărul de angajaŃi pentru fiecare job.
SELECT job_id, COUNT(employee_id) nr_angajati
FROM employees
GROUP BY job_id;
9. Să se afişeze minimul, maximul, suma şi media salariilor pentru fiecare departament.
10. Să se afişeze codul departamentului şi media salariilor pentru fiecare job din cadrul acestuia.
SELECT department_id, job_id, AVG(salary)
FROM employees
GROUP BY department_id, job_id;
11. a. Să se afişeze codul departamentelor pentru care salariul minim depăşeşte 5000$.
SELECT department_id, MIN(salary)
FROM employees
GROUP BY department_id
HAVING MIN(salary)>5000;
20
b. Să se modifice cererea anterioară astfel încât să se afişeze şi oraşul în care funcŃionează aceste
departamente.
12. Să se obŃină codul departamentelor şi numărul de angajaŃi al acestora pentru departamentele care au cel
puŃin 10 angajaŃi.
13. Să se obŃină codul departamentelor şi suma salariilor angajaŃilor care lucrează în acestea, în ordine
descrescătoare după sumă. Se consideră angajaŃii care au comision şi departamentele care au mai mult
de 5 angajaŃi.
14. Să se obŃină job-ul pentru care salariul mediu este minim.
SELECT job_id
FROM employees
GROUP BY job_id
HAVING AVG(salary) = (SELECT MIN(AVG(salary))
FROM employees
GROUP BY job_id);
15. Să se afişeze cel mai mare dintre salariile medii pe departamente.
16. a. Să se afişeze codul, numele departamentului şi suma salariilor pe departamente.
SELECT d.department_id, department_name,a.suma
FROM departments d, (SELECT department_id ,SUM(salary) suma
FROM employees
GROUP BY department_id) a
WHERE d.department_id =a.department_id;
17. a. ScrieŃi o cerere pentru a afişa numele departamentului, numărul de angajaŃi şi salariul mediu pentru
angajaŃii din acel departament. Coloanele vor fi etichetate Departament, Nr. angajati, Salariu Mediu.
SELECT department_name “Departament”,
(SELECT COUNT(employee_id)
FROM employees
WHERE department_id = d.department_id ) ” Nr. angajati”,
(SELECT AVG(salary)
FROM employees
WHERE department_id = d.department_id) ”Salariu mediu”
FROM departments d;
b. DaŃi o altă metodă de rezolvare pentru problema anterioară.
18. Să se creeze o cerere prin care să se afişeze numărul total de angajaŃi şi, din acest total, numărul celor
care au fost angajaŃi în 1997, 1998, 1999 şi 2000. Datele vor fi afişate în forma următoare:
Total 1997 1998 1999 2000
--------------------------------------------------------------
50 10 5 25 1
SUM(DECODE(TO_CHAR(hire_date,'yyyy'),1997,1,0))
21
Operatorii ROLLUP şi CUBE
Clauza GROUP BY permite gruparea liniilor selectate după valorile expresiilor precizate în
aceasta. Pentru fiecare grup, va fi returnată o singură linie de informaŃie. Clauza GROUP BY poate
produce grupări superagregat utilizând extensiile CUBE sau ROLLUP.
ROLLUP grupează liniile selectate pe baza valorilor primelor n, n - 1, …, 0 expresii din
specificaŃia GROUP BY şi returnează o singură linie pentru fiecare grup. ROLLUP creează grupări
prin deplasarea într-o singură direcŃie, de la dreapta la stânga, de-a lungul listei de coloane
specificate în clauza GROUP BY. Apoi, se aplică funcŃia agregat acestor grupări. Dacă sunt
specificate n expresii în operatorul ROLLUP, numărul de grupări generate va fi n + 1. Liniile care se
bazează pe valoarea primelor n expresii se numesc linii obişnuite, iar celelalte se numesc linii
superagregat.
GROUP BY ROLLUP (expr_1, expr_2, …, expr_n) generează n+1 tipuri de linii,
corespunzătoare următoarelor grupări:
• GROUP BY (expr_1, expr_2, …, expr_n-1, expr_n)
• GROUP BY (expr_1, expr_2, …, expr_n-1)
• …
• GROUP BY (expr_1, expr_2)
• GROUP BY (expr_1)
• GROUP BY () – corespunzător absenŃei clauzei GROUP BY şi deci, calculului funcŃiilor
grup din cerere pentru întreg tabelul.
CUBE grupează liniile selectate pe baza valorilor tuturor combinaŃiilor posibile ale expresiilor
specificate şi returnează câte o linie totalizatoare pentru fiecare grup. Acest operator este folosit pentru a
produce mulŃimi de rezultate care sunt utilizate în rapoarte. În vreme ce ROLLUP produce subtotalurile
doar pentru o parte dintre combinaŃiile posibile, operatorul CUBE produce subtotaluri pentru toate
combinaŃiile posibile de grupări specificate în clauza GROUP BY, precum şi un total general.
Dacă există n coloane sau expresii în clauza GROUP BY, vor exista 2n combinaŃii posibile
superagregat.
19. Să se afişeze codurile departamentelor în care lucrează cel puŃin un angajat, iar pentru fiecare dintre
acestea şi pentru fiecare manager care lucrează în departamentul respectiv să se afişeze numărul de
salariaŃi. De asemenea, să se afişeze numărul de salariaŃi pentru fiecare departament indiferent de
manager şi numărul total de angajaŃi din companie.
22
-----------------------------------------------------------------------
13
20. Să se afişeze codurile departamentelor în care lucrează cel puŃin un angajat, iar pentru fiecare dintre
acestea şi pentru fiecare manager care lucrează în departamentul respectiv să se afişeze numărul de
salariaŃi. De asemenea, să se afişeze numărul de salariaŃi pentru fiecare departament indiferent de
manager, numărul de angajaŃi subordonaŃi unui manager indiferent de departament şi numărul total de
angajaŃi din companie.
25. ModificaŃi cererea anterioară astfel încât să se afişeze numele departamentelor, titlurile job-urilor şi
valoarea medie a salariilor, pentru:
- fiecare departament şi, în cadrul său pentru fiecare job;
- fiecare departament (indiferent de job);
- fiecare job(indiferent de departament);
- întreg tabelul.
Cum intervin coloanele în obŃinerea rezultatului?
Să se afişeze ’Dept’, dacă departamentul a intervenit în agregare şi ‘Job’, dacă job-ul a intervenit în
agregare.
DECODE(GROUPING(department_name), 0, ‘Dept’)
26. UtilizaŃi cererea de la punctul 20.
a. EliminaŃi clauza WHERE din această cerere. AnalizaŃi rezultatul obŃinut.
b. ModificaŃi cererea obŃinută astfel încât să se identifice dacă o valoare null din rezultat este stocată pe
una dintre coloanele manager_id sau department_id sau este produsă de operatorul CUBE.
27. Clauza GROUPING SETS. Permite obŃinerea numai a anumitor grupări superagregat. Acestea pot fi
precizate prin intermediul clauzei:
24
ObservaŃii:
- sistemul realizează ROLLBACK implicit dacă se închide anormal (defecŃiune hardware sau software,
pană de curent etc.);
- nici o comanda LDD (CREATE, ALTER; DROP) nu poate fi anulată.
1. Ce efect are următoarea secvenŃă de instrucŃiuni?
CREATE TABLE dept_***
AS SELECT * FROM departmets;
SELECT *
FROM dept_***;
SAVEPOINT a;
SAVEPOINT b;
SELECT COUNT(*)
FROM dept_***;
ROLLBACK TO b;
SELECT COUNT(*)
FROM dept_***;
ROLLBACK TO a;
COMMIT;
SELECT *
FROM dept_***;
8. CreaŃi tabele emp1_***, emp2_*** şi emp3_*** cu aceeaşi structură ca tabelul employees. InseraŃi,
utilizând o singură comandă INSERT, informaŃii din tabelul employees:
- în tabelul emp1_*** salariaŃii care au salariul mai mic decât 6000;
- în tabelul emp2_*** salariaŃii care au salariul cuprins între 6000 şi 10000;
- în tabelul emp3_*** salariaŃii care au salariul mai mare decât 10000.
VerificaŃi rezultatele, apoi ştergeŃi toate înregistrările din aceste tabele.
Obs. Clauza ALL a comenzii INSERT determină evaluarea tuturor condiŃiilor din clauzele WHEN. Pentru
cele a căror valoare este TRUE, se inserează înregistrarea specificată în opŃiunea INTO corespunzătoare.
9. Să se creeze tabelul emp0_*** cu aceeaşi structură ca tabelul employees. InseraŃi, utilizând o singură
comandă INSERT, informaŃii din tabelul employees:
- în tabelul emp0_*** salariaŃii care lucrează în departamentul 80;
- în tabelul emp1_*** salariaŃii care au salariul mai mic decât 6000 (care nu se regăsesc în tabelul
emp0_***);
- în tabelul emp2_*** salariaŃii care au salariul cuprins între 6000 şi 10000 (care nu se regăsesc în
tabelele emp0_*** şi emp1_***);
- în tabelul emp3_*** salariaŃii care au salariul mai mare decât 10000 (care nu se regăsesc în tabelele
emp0_***, emp1_*** şi emp2_***).
Obs.
26
Clauza FIRST a comenzii INSERT determină inserarea corespunzătoare primei clauze WHEN a cărei
condiŃie este evaluată TRUE. Toate celelalte clauze WHEN sunt ignorate.
10. Sintaxa simplificată a comenzii DELETE
DELETE FROM nume_tabel
[WHERE conditie];
11. ŞtergeŃi toate înregistrările din tabelele emp_*** şi dept_***. InseraŃi în aceste tabele toate înregistrările
corespunzătoare din employees, respectiv departments. PermanentizaŃi tranzacŃia.
UPDATE emp_***
SET salary = salary * 1.05;
ROLLBACK;
17. SchimbaŃi jobul tuturor salariaŃilor din departamentul 80 care au comision în 'SA_REP'. AnulaŃi
modificările.
18. Să se modifice jobul şi departamentul angajatului având codul 114, astfel încât să fie la fel cu cele ale
angajatului având codul 205.
19. SchimbaŃi salariul şi comisionul celui mai prost plătit salariat din firmă, astfel încât să fie egale cu
salariul si comisionul directorului.
20. Pentru fiecare departament să se mărească salariul celor care au fost angajaŃi primii astfel încât să devină
media salariilor din companie.
21. Să se modifice valoarea emailului pentru angajaŃii care câştigă cel mai mult în departamentul în care
lucrează astfel încât acesta să devină iniŃiala numelui concatenată cu prenumele. Dacă nu are prenume
atunci în loc de acesta apare caracterul ‘.’. AnulaŃi modificările.
27