laborator bd combinat

97
1 LABORATOR 1 SQL 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; 3. Să se listeze structura tabelelor din schema HR (EMPLOYEES, DEPARTMENTS, JOB_HISTORY, JOBS, LOCATIONS, COUNTRIES, REGIONS), observând tipurile de date ale coloanelor. Obs: Se va utiliza comanda SQL*Plus DESCRIBE nume_tabel 4. Să se listeze conţinutul tabelelor din schema considerată, afişând valorile tuturor câmpurilor. Obs: Se va utiliza comanda SQL SELECT * FROM nume_tabel; 5. Să se obţină încă o dată rezultatul cererii precedente, fără a rescrie cererea. Obs: Ultima comandă SQL lansată de către client este păstrată în buffer -ul SQL. Pentru rularea acesteia se utilizează “/” sau RUN. 6. Listaţi structura tabelului EMPLOYEES şi apoi daţi comanda RUN (sau “/”). Ce observaţi? Comenzile SQL*Plus sunt păstrate în buffer? DESC employees RUN

Upload: mugurciup

Post on 15-Jun-2015

722 views

Category:

Documents


9 download

DESCRIPTION

Cele 8 laboratoare de la baze de date

TRANSCRIPT

Page 1: Laborator BD combinat

1

LABORATOR 1 SQL 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;

3. Să se listeze structura tabelelor din schema HR (EMPLOYEES, DEPARTMENTS, JOB_HISTORY,

JOBS, LOCATIONS, COUNTRIES, REGIONS), observând tipurile de date ale coloanelor.

Obs: Se va utiliza comanda SQL*Plus

DESCRIBE nume_tabel

4. Să se listeze conţinutul tabelelor din schema considerată, afişând valorile tuturor câmpurilor.

Obs: Se va utiliza comanda SQL

SELECT * FROM nume_tabel;

5. Să se obţină încă o dată rezultatul cererii precedente, fără a rescrie cererea.

Obs: Ultima comandă SQL lansată de către client este păstrată în buffer-ul SQL.

Pentru rularea acesteia se utilizează “/” sau RUN.

6. Listaţi structura tabelului EMPLOYEES şi apoi daţi comanda RUN (sau “/”). Ce observaţi? Comenzile

SQL*Plus sunt păstrate în buffer?

DESC employees

RUN

Page 2: Laborator BD combinat

2

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

Cererea se modifică astfel:

SELECT employee_id cod, last_name nume, job_id " cod job ", hire_date " data angajarii "

FROM employees;

@ z:\…\ p1_14.sql

10. Să se listeze, cu şi fără duplicate, codurile job-urilor din tabelul EMPLOYEES.

SELECT job_id FROM employees;

SELECT DISTINCT job_id FROM employees;

SELECT UNIQUE job_id FROM employees;

Obs. DISTINCT = UNIQUE

11. Să se afişeze numele concatenat cu prenumele, separate prin spaţiu. Etichetaţi coloana “Nume si

prenume”.

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;

12. Să se listeze numele şi salariul angajaţilor care câştigă mai mult de 10000 $.

SELECT last_name, salary

FROM employees

WHERE salary > 10000;

13. 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;

14. Să se creeze o cerere pentru a afişa numele angajatului şi numărul departamentului pentru angajatul 104.

Page 3: Laborator BD combinat

3

SELECT last_name, department_id

FROM employees

WHERE employee_id =104;

15. 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)

SELECT last_name, salary

FROM employees

WHERE department_id IN (10, 30)

ORDER BY last_name;

16. 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.

17. 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.

MI Minutele din oră.

SS Secundele din minut.

SSSSS Secundele trecute de la miezul nopţii.

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.

Page 4: Laborator BD combinat

4

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%';

22. Folosind data curentă să se afişeze următoarele informaţii: - numele zilei, numărul zilei din săptămână, numărul zilei din luna, respectiv numărul zilei din an; - numărul lunii din an, numele lunii cu abreviere la 3 caractere, respectiv numele complet al lunii; - ora curentă (ora, minute, secunde).

23. Să se listeze numele departamentelor care funcţionează în locaţia având codul 1700 şi al căror manager este cunoscut.

24. Să se afişeze codurile departamentelor în care lucrează salariaţi.

25. Să se afişeze numele şi prenumele salariaţilor angajaţi în luna mai 1987.

26. Să se listeze codurile angajaţilor care au avut şi alte joburi faţă de cel prezent. Să se ordoneze rezultatul descrescător după codul angajatului.

27. Să se afişeze numele şi data angajării pentru cei care lucrează în departamentul 80 şi au fost angajaţi în luna martie a anului 1997.

28. Să se afişeze numele joburilor care permit un salariu cuprins între 8300$ şi 14000$.

29. Care este grila de salarizare pentru un salariu de 10000$?

Page 5: Laborator BD combinat

5

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).

Page 6: Laborator BD combinat

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.

1. Analizaţi următoarele funcţii pentru prelucrarea şirurilor de caractere:

Funcţie Semnificaţie Exemplu

LOWER (expresie) Converteşte un şir de caractere

la minuscule. LOWER ('AbCdE') = 'abcde'

UPPER (expresie) Converteşte un şir de caractere

la majuscule. UPPER ('AbCdE') = 'ABCDE'

INITCAP (expresie)

Converteşte un şir de caractere

la un şir care începe cu

majusculă şi continuă cu

minuscule.

INITCAP ('AbCdE') = 'Abcde'

SUBSTR (expresie, m[, n])

Extrage din expresia de tip şir

de caractere, n caractere

începând cu poziţia m. Dacă

lipseşte argumentul n, atunci

extrage toate caracterele până la

sfârşitul şirului. Dacă m este

negativ numărătoarea poziţiilor

începe de la sfârşitul şirului de

caractere spre început.

SUBSTR ('AbCdE', 2, 2) = 'bC'

SUBSTR ('AbCdE', 2) = 'bCdE'

SUBSTR ('AbCdE', -3,2) = 'Cd'

SUBSTR ('AbCdE', -3) = 'CdE'

LENGTH (expresie) Returnează numărul de

caractere al expresiei. LENGTH ('AbCdE') = 5

INSTR (expresie, expr1[, m][, n])

Returnează poziţia la care se

găseşte a n-a ocurentă a

expresiei 'expr1' în cadrul

expresiei 'expresie', căutarea

începând de la poziţia m. Daca

m sau n lipsesc, valorile

implicite sunt 1 pentru ambele.

INSTR (LOWER('AbC aBcDe'), 'ab', 5, 2)

= 0

INSTR (LOWER('AbCdE aBcDe'), 'ab', 5)

= 7

LTRIM (expresie[, expr1]) sau

RTRIM (expresie[, expr1])

Reversul funcţiilor LPAD,

RPAD. Trunchează expresia

RTRIM ('abcdeXXXX', 'X')

= 'abcde'

Page 7: Laborator BD combinat

caracter la stânga sau la dreapta

prin eliminarea succesivă a

caracterelor din expresia expr1.

Implicit, daca lipseşte, expr1

este ' ' un spaţiu.

LTRIM (' abcde') = 'abcde'

TRIM (LEADING | TRAILING |

BOTH caractere_trim FROM

expresie)

Permite eliminarea caracterelor

specificate (caractere_trim) de

la începutul (leading) , sfârşitul

(trailing) sau din ambele părţi,

dintr-o expresie caracter data.

TRIM (LEADING 'X' FROM

'XXXabcdeXXX') = 'abcdeXXX'

TRIM (TRAILING 'X' FROM

'XXXabcdeXXX') = 'XXXabcde'

TRIM ( BOTH 'X' FROM

'XXXabcdeXXX') = 'abcde'

TRIM (' abcde ') = 'abcde'

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 (expresie [, n])

Returnează valoarea rotunjită a expresiei

până la n zecimale. Daca n este negativ sunt

rotunjite cifre din stânga virgulei. Valoarea

implicită pentru n este 0.

ROUND(1.6) = 2

ROUND(1.4) = 1

ROUND (1234.56,1) = 1234.6

ROUND (1230.56, -2) = 1200

ROUND (1260.56, -2) = 1300

MOD (m,n) Returnează restul împărţirii lui m la n. MOD (11, 4) = MOD (11, -4) = 3

MOD(-11, 4) = MOD (-11, -4) = -3

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.

Page 8: Laborator BD combinat

8. Analizaţi următoarele operaţii pe expresii de tip dată calendaristică:

Operaţie Tipul de date al

rezultatului Descriere

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 +/-

number/24 Date Scade/Adaugă un număr de ore la o / dintr-o dată calendaristică.

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

MONTHS_BETWEEN

(date1, date2)

Returnează numărul de luni dintre

data date1 şi data date2. Rezultatul

poate fi pozitiv sau negativ după cum

date1 este mai recentă sau nu faţă de

date2. Zecimalele reprezintă parţi

dintr-o luna!

ROUND(MONTHS_BETWEEN

(SYSDATE + 31, SYSDATE)) = 1

ADD_MONTHS (date, n)

Adaugă n luni la o data specificată.

Valoarea n trebuie să fie întreagă

(pozitivă sau negativă).

MONTHS_BETWEEN

(ADD_MONTHS(SYSDATE, 3),

SYSDATE) = 3

NEXT_DAY (date, char)

Returnează data corespunzătoare

primei zile a săptămânii specificate

(char) care urmează după date.

NEXT_DAY('15-dec-2006','Monday')

= '18-dec-2006'

NEXT_DAY ('15-dec-2006',1)

= '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);

Page 9: Laborator BD combinat

SELECT last_name, ROUND(MONTHS_BETWEEN(SYSDATE, hire_date)) “Luni lucrate”

FROM employees

ORDER BY “Luni lucrate”;

SELECT last_name, ROUND(MONTHS_BETWEEN(SYSDATE, hire_date)) “Luni lucrate”

FROM employees

ORDER BY 2;

15. Analizaţi următoarele funcţii de conversie:

Obs. Conversiile implicite asigurate de server-ul Oracle sunt:

de la VARCHAR2 sau CHAR la NUMBER;

de la VARCHAR2 sau CHAR la DATE;

de la NUMBER la VARCHAR2 sau CHAR;

de la DATE la VARCHAR2 sau CHAR.

SELECT last_name

FROM employees

WHERE TO_CHAR(hire_date,'yyyy')=1994;

SELECT last_name

FROM employees

WHERE hire_date='07-JUN-1994';

SELECT employee_id||' '||last_name||' '||hire_date

FROM employees

WHERE department_id=10;

Conversiile explicite se realizează cu ajutorul funcţiilor de tip TO_{tip}

Funcţie Semnificaţie Exemplu

TO_CHAR

(expr_number_sau

_date[, format][,

nlsparameters])

Converteşte o valoare de tip numeric sau dată

calendaristică, la un şir de caractere conform cu

formatul specificat sau cu setările naţionale

specificate (NLS - National Language Support).

Daca formatul sau parametrii lipsesc se

utilizează formatul şi parametrii impliciţi.

Formatul este case sensitive.

TO_CHAR('3') = ' 3'

TO_CHAR(-12) = '-12'

TO_CHAR(sysdate, 'DDMMYYYY')

= ' 09122004'

TO_CHAR (sysdate + 365 * 57,

'ddmmyyyy') = ' 25112061'

TO_NUMBER

(expr_char[,

format][,

nlsparameters])

Converteşte o valoare de tip şir de caractere la o

valoare numerică conform cu formatul

specificat. Dacă formatul sau parametrii lipsesc

se utilizează formatul şi parametrii impliciţi.

TO_NUMBER ('-12.22', 'S99.99')

= -12.22

TO_DATE

(expr_char[,

format][,

nlsparameters])

Converteşte o valoare de tip şir de caractere la o

valoare de tip dată calendaristică în

conformitate cu formatul specificat. Dacă

formatul sau parametrii lipsesc se utilizează

formatul şi parametrii impliciţi.

TO_DATE ('15-feb-2006','dd-mon-

yyyy')

16. Să se afişeze numele şi prenumele pentru toţi angajaţii care s-au angajat în luna mai.

Page 10: Laborator BD combinat

17. Analizaţi următoarele funcţii SQL:

Funcţie Semnificaţie Exemplu

NVL (expr1, expr2)

Returnează expr1 dacă aceasta nu este

NULL, expr2 în caz contrar. Cele 2 expresii

trebuie să aibă acelaşi tip sau expr2 să

permită conversia implicită la tipul

expresiei expr1.

NVL(NULL, 1) = 1

NVL(2, 1) = 2

NVL('c', 1) = 'c' -- face conversie

NVL(1, 'c') -- eroare

--nu face conversie

NVL2 (expr1, expr2, expr3) Dacă expr1 este nenulă atunci returnează

expr2, altfel Returnează expr3

NVL2 (1, 2, 3) = 2

NVL2 (NULL, 2, 3) = 3

18. Să se afişeze numele angajaţilor şi comisionul. Dacă un angajat nu câştigă comision, să se scrie “Fara

comision”. Etichetaţi coloana “Comision”.

NVL(TO_CHAR(commission_pct), „Fara comision‟)

19. Să se listeze numele, salariul şi comisionul tuturor angajaţilor al căror venit lunar depăşeşte 10000$.

salary * NVL(commission_pct, 0) venit_lunar

20. Analizaţi expresia CASE şi funcţia DECODE:

Funcţie/Expresie Semnificaţie Exemplu

CASE expr WHEN expr_bool1

THEN return_expr1

[WHEN expr_bool2 THEN

return_expr2

...

WHEN expr_booln THEN

return_exprn ]

[ELSE return_expr]

END

În funcţie de valoarea unei expresii

returnează valoarea primei perechi

WHEN .. THEN care se potriveşte sau

dacă nu se potriveşte nici una expresia

din ELSE. Nu se poate specifica NULL

pentru toate expresiile de returnat.

(return_expri). Toate expresiile trebuie

sa aibă acelaşi tip de date

DECODE (expr, expr_cautare1,

expr_rezultat1,

[expr_cautare2, expr_rezultat2,

..

expr_cautaren, expr_rezultatn, ]

[rezultat_implicit])

Decodifică valoarea expresiei. Dacă

valoarea expresiei este expr_cautarei

atunci e returnată expr_rezultati. Dacă

nu se potriveşte nici o expresie de

căutare atunci e returnat

rezultat_implicit.

DECODE (1, 1, 2, 3) = 2

DECODE (2, 1, 2, 3) = 3

DECODE (3, 1, 2, 3) = 3

21. Să se afişeze numele, codul funcţiei, salariul şi o coloana care să arate salariul după mărire. Se ştie că

pentru IT_PROG are loc o mărire de 10%, pentru ST_CLERK 15%, iar pentru SA_REP o mărire de

20%. Pentru ceilalţi angajaţi nu se acordă mărire. Să se denumească coloana "Salariu revizuit".

SELECT last_name, job_id, salary,

DECODE(job_id,

„IT_PROG‟, salary*1.1,

‟ST_CLERK‟, salary*1.15,

„SA_REP‟, salary*1.2,

salary ) “salariu revizuit”

FROM employees;

SELECT last_name, job_id, salary,

CASE job_id WHEN „IT_PROG‟ THEN salary* 1.1

Page 11: Laborator BD combinat

WHEN ‟ST_CLERK‟ THEN salary*1.15

WHEN „SA_REP‟ THEN salary*1.2

ELSE salary

END “salariu revizuit”

FROM employees;

SELECT last_name, job_id, salary,

CASE WHEN job_id= „IT_PROG‟ THEN salary* 1.1

WHEN job_id=‟ST_CLERK‟ THEN salary*1.15

WHEN job_id =„SA_REP‟ THEN salary*1.2

ELSE salary

END “salariu revizuit”

FROM employees;

22. Să se afişeze numele salariatului şi codul departamentului în care acesta lucrează. Dacă există salariaţi

care nu au un cod de departament asociat, atunci pe coloana id_depratment să se afişeze:

a. textul “fara departament”;

b. valoarea zero.

23. a. Să se afişeze numele angajaţilor care nu au manager.

b. Să se afişeze numele angajaţilor şi codul managerilor lor. Pentru angajaţii care nu au manager să apară

textul “nu are sef”.

24. Să se afişeze numele salariatului şi:

- venitul anual dacă are comision;

- salariul dacă nu are comision.

Se va utiliza funcţia NVL2.

25. Să se afişeze numele salariatului, salariul şi salariul revizuit astfel:

- 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%.

Page 12: Laborator BD combinat

LABORATOR 3 - SQL

CERERI MULTITABEL, SUBCERERI

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;

Page 13: Laborator BD combinat

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

Page 14: Laborator BD combinat

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.

Page 15: Laborator BD combinat

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.

Page 16: Laborator BD combinat

1

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;

Page 17: Laborator BD combinat

2

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;

b. Daţi o altă metodă de rezolvare a acestei probleme.

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))

Page 18: Laborator BD combinat

3

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.

SELECT department_id, manager_id, COUNT(employee_id)

FROM employees

WHERE manager_id IS NOT NULL AND department_id IS NOT NULL

GROUP BY ROLLUP (department_id, manager_id);

department_id manager_id COUNT(employee_id)

---------------------------------------------------------------------

10 7782 1

10 7839 1

10 2

-----------------------------------------------------------------------

20 7566 2

20 7788 1

20 7839 1

20 7902 1

20 5

-----------------------------------------------------------------------

30 7698 5

30 7839 1

30 6

-----------------------------------------------------------------------

13

Page 19: Laborator BD combinat

4

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.

SELECT department_id, manager_id, COUNT(employee_id)

FROM employees

WHERE manager_id IS NOT NULL AND department_id IS NOT NULL

GROUP BY CUBE (department_id, manager_id);

department_id manager_id COUNT(employee_id)

---------------------------------------------------------------------

10 7782 1

10 7839 1

10 2

-----------------------------------------------------------------------

20 7566 2

20 7788 1

20 7839 1

20 7902 1

20 5

-----------------------------------------------------------------------

30 7698 5

30 7839 1

30 6

-----------------------------------------------------------------------

7566 2

7698 5

7782 1

7788 1

7839 3

7902 1

----------------------------------------------------------------------

13

21. Pentru fiecare departament, job, respectiv an al angajării să se afişeze numărul de salariaţi. De asemenea se

va afişa numărul de angajaţi:

- pentru fiecare departament şi job, indiferent de anul angajării;

- pentru fiecare departament, indiferent de job şi de anul angajării;

- la nivel de companie.

22. Să se afişeze suma alocată pentru plata salariilor pe joburi (codul jobului), în cadrul departamentului (codul

departamentului). De asemenea, să se afişeze valoarea totală necesară pentru plata salariilor la nivel de

departament, valoarea totală necesară pentru plata salariilor la nivel de job, indiferent de departament şi

valoarea totală necesară pentru plata salariilor la nivel de companie.

23. Funcţia GROUPING(expresie) întoarce: - valoarea 0, dacă expresia a fost utilizată pentru calculul valorii agregat

- valoarea 1, dacă expresia nu a fost utilizată.

24. 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); - întreg tabelul.

De asemenea, să se afişeze şi o coloană care indică intervenţia coloanelor department_name şi job_title în obţinerea

rezultatului.

Page 20: Laborator BD combinat

5

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:

GROUP BY GROUPING SETS ((expr_11, expr_12, …, expr_1n), (expr_21, expr_22, …expr_2m), …)

28. Să se afişeze numele departamentelor, numele job-urilor, codurile managerilor angajaţilor, maximul şi suma

salariilor pentru:

- fiecare departament şi, în cadrul său, fiecare job;

- fiecare job şi, în cadrul său, pentru fiecare manager;

- întreg tabelul.

GROUPING SETS ((department_name, job_title), (job_title, e.manager_id), ());

Page 21: Laborator BD combinat

1

LABORATOR 5 SQL

I. Limbajul de control al datelor (COMMIT, SAVEPOINT, ROLLBACK)

II. Limbajul de prelucrare a datelor (LMD). INSERT, UPDATE, DELETE.

I. Limbajul de control al datelor (COMMIT, SAVEPOINT, ROLLBACK)

Comanda COMMIT permanentizează modificările care au fost realizate de tranzacţia curentă (o

tranzacţie este un set de comenzi DML - INSERT, UPDATE, DELETE sau MERGE); comanda suprimă

toate punctele intermediare definite în tranzacţie şi eliberează blocările tranzacţiei.

Observaţie:

Sistemul realizează un commit implicit:

- la închiderea normală a unui client Oracle (de exemplu SQL*Plus),

- după fiecare comandă LDD (CREATE, ALTER, DROP).

Comanda SAVEPOINT marchează un punct intermediar în procesarea tranzacţiei. În acest mod este

posibilă împărţirea tranzacţiei în subtranzacţii.

Comanda SAVEPOINT are sintaxa:

SAVEPOINT nume_pct_intermediar;

Comanda ROLLBACK permite renunţarea la modificările efectuate; aceasta determină încheierea

tranzacţiei, anularea modificărilor asupra datelor şi restaurarea stării lor precedente.

Comanda ROLLBACK are sintaxa:-

ROLLBACK [TO SAVEPOINT nume_punct_salvare];

Observaţie:

- sistemul realizează un rollback implicit dacă sistemul 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 departments;

SELECT *

FROM dept_***;

SAVEPOINT a;

DELETE FROM dept_***;

INSERT INTO dept_***

VALUES (300,’Economic’,100,1000);

INSERT INTO dept_***

VALUES (350,’Cercetare’,200,2000);

SAVEPOINT b;

INSERT INTO dept_***

VALUES (400,’Juritic’,150,3000);

SELECT COUNT(*)

FROM dept_***;

ROLLBACK TO b;

Page 22: Laborator BD combinat

2

SELECT COUNT(*)

FROM dept_***;

ROLLBACK TO a;

INSERT INTO dept_***

VALUES (500,’Contabilitate’,175,1500);

COMMIT;

SELECT *

FROM dept_***;

II. Limbajul de prelucrare a datelor (LMD). INSERT, UPDATE, DELETE, MERGE.

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

Page 23: Laborator BD combinat

3

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.

CREATE TABLE emp1_***

AS SELECT * FROM employees WHERE 1=0;

CREATE TABLE emp2_***

AS SELECT * FROM employees WHERE 1=0;

CREATE TABLE emp3_***

AS SELECT * FROM employees WHERE 1=0;

INSERT ALL

WHEN salary < =6000 THEN

INTO emp1_***

WHEN salary > = 6000 AND salary <= 10000 THEN

INTO emp2_***

ELSE

INTO emp3_***

SELECT * FROM employees;

DELETE FROM emp1_***;

DELETE FROM emp2_***;

DELETE FROM emp3_***;

COMMIT;

9. Să se creeze tabelul emp0_*** cu aceeaşi structură ca tabelul employees. Copiaţi 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;

- î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.

Dacă un salariat se încadrează în tabelul emp0_*** atunci acesta nu va mai fi inserat şi în alt tabel

(tabelul corespunzător salariului său).

Page 24: Laborator BD combinat

4

Obs. Clauza FIRST determină inserarea corespunzătoare primei clauze WHEN a cărei condiţie este evaluată

TRUE. Toate celelalte clauze WHEN sunt ignorate.

Sintaxa simplificată a comenzii DELETE

DELETE FROM nume_tabel

[WHERE conditie];

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.

11. Ştergeţi angajaţii care nu au comision. Anulaţi modificările.

DELETE FROM emp_***

WHERE commission_pct IS NULL;

ROLLBACK;

12. Eliminaţi departamentele care nu au nici un angajat. Anulaţi modificările.

13. Eliminaţi angajaţii care nu aparţin unui departament valid. Anulaţi modificările.

14. Sintaxa simplificată a comenzii UPDATE:

UPDATE nume_tabel [alias]

SET col1 = expr1[, col2=expr2]

[WHERE conditie];

sau

UPDATE nume_tabel [alias]

SET (col1,col2,...) = (subcerere)

[WHERE conditie];

Observatii:

- de obicei pentru identificarea unei linii se foloseşte o condiţie ce implică cheia primară;

- dacă nu apare clauza WHERE atunci sunt afectate toate liniile tabelului specificat.

15. Măriţi salariul tuturor angajaţilor din tabelul emp_*** cu 5%. 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_***

Page 25: Laborator BD combinat

5

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.

Page 26: Laborator BD combinat

1

Limbajul de definire a datelor (DDL). CREATE, ALTER , DROP

Definirea tabelelor CREATE TABLE [schema.]nume_tabel (

nume_coloana tip_de_date [DEFAULT 1 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)

data_angajarii Valoare implicită data curentă

DATE

varsta NUMBER(2) email CHAR(50) salariu Valoare implicită 0 NUMBER(9,2)

CREATE TABLE salariat_*** ( cod_ang NUMBER(4) NOT NULL, nume VARCHAR2(25), prenume VARCHAR2(25), functia VARCHAR2(20), sef NUMBER(4), data_angajarii DATE DEFAULT SYSDATE, varsta NUMBER(2), email CHAR(50), salariu NUMBER(9,2) DEFAULT 0);

2. AfişaŃi structura tabelului creat anterior.

3. Se dau următoarele valori:

COD _ANG NUME PRENUME FUNCTIA SEF DATA_ANG VARSTA EMAIL SALARIU 1 ..... ..... director null ........ 30 ..... 5500 2 ..... ..... functionar 1 ......... 25 ..... 0 3 ..... ...... economist 1 ......... 45 ..... 3000 4 ..... .... functionar 1 ......... 35 ...... 1000

4. InseraŃi în tabelul salariat_*** prima înregistrare din tabelul de mai sus fără să precizaŃi lista de coloane în comanda INSERT.

5. InseraŃi a doua înregistrare folosind o listă de coloane din care excludeŃi data_angajarii şi salariul care au valori implicite. ObservaŃi apoi rezultatul.

6. InseraŃi înregistrările 3 şi 4.

7. CreaŃi tabelul functionar_*** care să conŃină funcŃionarii din tabelul salariat_*** , având următoarele coloane: codul, numele, salariul anual şi data angajării. VerificaŃi cum a fost creat tabelul şi ce date conŃine.

Page 27: Laborator BD combinat

2

Modificarea tabelelor

8. AdăugaŃi o nouă coloană tabelului salariat_*** care să conŃină data naşterii.

ALTER TABLE salariat_*** ADD (datan DATE); 9. ModificaŃi dimensiunea coloanei nume la 30 si pe cea a salariului la 12 cu 3 zecimale. ALTER TABLE salariat_*** MODIFY (nume VARCHAR2(30), salariu NUMBER(12,3)); 10. ModificaŃi tipul coloanei email la VARCHAR2. 11. ModificaŃi valoarea implicită a coloanei data_angajarii la data sistemului + o zi. 12. EliminaŃi coloana varsta din tabelul salariat_***. ALTER TABLE salariat_*** DROP COLUMN varsta;

Redenumirea şi eliminarea tabelelor

RENAME nume_tabel TO nume_nou; DROP TABLE nume_tabel;

13. RedenumiŃi tabelul functionar_*** cu funct_*** .

14. RecreaŃi tabelul functionar_*** utilizând tabelul funct_*** ..

15. EliminaŃi tabelul funct_***.

Constrângeri

Adăugarea constrângerilor la crearea tabelului (CREATE TABLE)

CREATE TABLE [schema.]nume_tabel (

nume_coloana tip_de_date [DEFAULT expr]

[constrangere_de_coloana], ...

..[constrangere la nivel de tabel])

16. ŞtergeŃi şi apoi creaŃi din nou tabelul salariat_*** cu următoarea structură.

NUME TIP CONSTRÂNGERE cod_ang NUMBER(4) Cheie primară nume VARCHAR2(25) NOT NULL prenume VARCHAR2(25) data_nasterii DATE data_nasterii<data_angajarii functia VARCHAR2(9) NOT NULL

sef NUMBER(4) Referă ca şi cheie externă cod_ang din acelaşi tabel

data_angajarii DATE email VARCHAR2(20) unic salariu NUMBER(12,3) > 0 cod_dept NUMBER(4) CombinaŃia NUME + PRENUME să fie unică

Page 28: Laborator BD combinat

3

ObservaŃie: Constrângerile de tip CHECK se pot implementa la nivel de coloană doar dacă nu referă o altă coloană a

tabelului.

DROP TABLE salariat_***; CREATE TABLE salariat_*** ( cod_ang NUMBER(4) PRIMARY KEY, nume VARCHAR2(25) NOT NULL, prenume VARCHAR2(25), data_nasterii DATE, functia VARCHAR2(9) NOT NULL, sef NUMBER(4) REFERENCES salariat_*** (cod_ang), data_angajarii DATE DEFAULT SYSDATE, email VARCHAR2(20) UNIQUE, salariu NUMBER(9,2) CHECK (salariu > 0), cod_dep NUMBER(4), CONSTRAINT const_c_*** CHECK (data_angajarii > data _nasterii), CONSTRAINT const_u_*** UNIQUE (nume,prenume,data_na sterii));

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ă.

DROP TABLE salariat_***; CREATE TABLE salariat_*** ( cod_ang NUMBER(4), nume VARCHAR2(25) NOT NULL, prenume VARCHAR2(25), data_nasterii DATE, functia VARCHAR2(9) NOT NULL, sef NUMBER(4), data_angajarii DATE DEFAULT SYSDATE, email VARCHAR2(20), salariu NUMBER(9,2), cod_dep NUMBER(4), CONSTRAINT ccp_*** PRIMARY KEY (cod_ang), CONSTRAINT cce_*** FOREIGN KEY (sef) REFERENCES sal ariat_*** (cod_ang), CONSTRAINT cu1_*** UNIQUE (email), CONSTRAINT cc1_*** CHECK (data_angajarii > data_nas terii), CONSTRAINT cc2_***CHECK (salariu > 0), CONSTRAINT cu2_*** UNIQUE (nume,prenume,data_naster ii));

18. CreaŃi tabelul departament_*** care să aibă următoarea structură.

NUME TIP CONSTRÂNGERI COD_DEP NUMBER(4) Cheie primară NUME VARCHAR2(20) Not null ORAS VARCHAR2(25)

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

Page 29: Laborator BD combinat

4

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

2 N2 P2 11-JUN-1960

economist 1 Sysdate E2 2000 10

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?

ALTER TABLE salariat_*** ADD CONSTRAINT cce2_*** FOREIGN KEY (cod_dep) REFER ENCES departament_*** (cod_dep); 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 nume prenume data_n functia sef data_ang email salariu cod_dep

3 N3 P3 11-JUN-1967

jurist 2 Sysdate E3 2500 20

23. ŞtergeŃi departamentul 20 din tabelul departament_***. Ce observaŃi?

24. ŞtergeŃi constrângerea cce2_***. RecreaŃi această constrângere adăugând opŃiunea ON DELETE CASCADE.

25. ŞtergeŃi departamentul 20 din tabelul departament_***. Ce observaŃi în tabelul salariat_***? AnulaŃi modificările.

26. ŞtergeŃi constrângerea cce2_***. RecreaŃi această constrângere adăugând opŃiunea ON DELETE SET NULL.

27. ÎncercaŃi să ştergeŃi departamentul 10 din tabelul departament_***. Ce observaŃi? Consultarea dicŃionarului datelor

InformaŃii despre tabelele create se găsesc în vizualizările :

• USER_TABLES – informaŃii complete despre tabelele utilizatorului curent.

cod_dep nume loc 10 Economic Bucuresti

cod_dep nume loc 20 Juritic Constanta

Page 30: Laborator BD combinat

5

• ALL_TABLES – informaŃii complete despre tabelele tuturor utilizatorilor. • COLS – informaŃii despre coloane. • TAB – informaŃii de bază despre tabelele existente în schema utilizatorului curent.

InformaŃii despre constrângeri găsim în :

• USER_CONSTRAINTS – informaŃii despre constrângerile definite de utilizatorul curent; • ALL_CONSTRAINTS – informaŃii despre cosntrângerile definite de toŃi utilizatorii.

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_***.

CREATE VIEW v_emp_*** (cod, nume) AS SELECT employee_id, last_name FROM emp_***; INSERT INTO v_emp_*** VALUES (400,’N1’); DROP VIEW 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ă.

CREATE VIEW v_emp_*** AS SELECT employee_id, last_name, email, hire_date, s alary,job_id FROM emp_***; DESC v_emp_*** SELECT * FROM v_emp_***;

Page 31: Laborator BD combinat

6

INSERT INTO v_emp_*** VALUES (400,’N1’,’E1’,SYSDATE,5000,’SA_REP’); SELECT employee_id, last_name, email, hire_date, sa lary, job_id FROM emp_***;

3. Să se mărească cu 1000 salariul angajatului având codul 400 din vizualizarea creată anterior. Ce efect va avea această acŃiune asupra tabelului de bază?

4. Să se şteargă angajatul având codul 400 din vizualizarea creată anterior. Ce efect va avea această acŃiune asupra tabelului de bază?

5. a) Să se creeze vizualizarea v_emp_dept_*** care să conŃină employee_id, last_name, hire_date, job_id, department_id din tabelul emp_*** şi coloana department_name din tabelul dept_***. b) Să încerce inserarea înregistrării (500, 'N2', 'E2',SYSDATE,’SA_REP’,30, 'Administrativ') în vizualizarea creată anterior.

c) Care dintre coloanele vizualizării v_emp_dept_*** sunt actualizabile?

SELECT column_name, updatable FROM user_updatable_columns WHERE UPPER(table_name) = UPPER('v_emp_dept_***'); 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. 6. Să se creeze vizualizarea v_dept_*** care să conŃine codul şi numele departamentului, numărul de

angajaŃi din departamentul respectiv şi suma alocată pentru plata salariilor. Această vizualizare permite actualizări?

CREATE VIEW v_dept_*** (cod, nume, nr_angajati, val _salarii) AS SELECT e.department_id, department_name, COUNT(*) nr_angajati, SUM(salary) val_salarii FROM emp_*** e, dept_*** d WHERE e.department_id = d.department_id GROUP BY e.department_id, department_name; 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, s alary, job_id, department_id FROM emp_*** WHERE department_id=30 WITH CHECK OPTION CONSTRAINT ck_option1_***;

b) Să se listeze structura şi conŃinutul vizualizării v_emp30_***.

Page 32: Laborator BD combinat

7

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.

CREATE VIEW v_dept_*** AS SELECT * FROM dept_*** WITH READ ONLY; 9. Să se consulte informaŃii despre vizualizarea v_dept_***. FolosiŃi vizualizarea dicŃionarului datelor USER_VIEWS (coloanele VIEW_NAME şi TEXT). 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. SET LONG 200 SELECT view_name, text FROM user_views WHERE UPPER(view_name)=UPPER(’v_dept_***’);

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ă. 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.

Page 33: Laborator BD combinat

8

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. SELECT sec_***.CURRVAL valoare FROM DUAL; 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.

Page 34: Laborator BD combinat

9

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} …] ]

2. Să se listeze structura tabelelor din schema HR (EMPLOYEES, DEPARTMENTS, JOB_HISTORY, JOBS, LOCATIONS, COUNTRIES, REGIONS), observând tipurile de date ale coloanelor.

Obs: Se va utiliza comanda SQL*Plus

DESCRIBE nume_tabel

3. Să se listeze conŃinutul tabelelor din schema considerată, afişând valorile tuturor câmpurilor.

Obs: Se va utiliza comanda SQL

SELECT * FROM nume_tabel;

4. Să se obŃină încă o dată rezultatul cererii precedente, fără a rescrie cererea.

Obs: Ultima comandă SQL lansată de către client este păstrată în buffer-ul SQL.

Pentru rularea acesteia se utilizează “/” sau RUN.

5. ListaŃi structura tabelului EMPLOYEES şi apoi daŃi comanda RUN (sau “/”). Ce observaŃi? Comenzile SQL*Plus sunt păstrate în buffer?

DESC employees RUN

6. 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

7. ReexecutaŃi cererea folosind fişierul p1_14.sql. START z:\…\ p1_14.sql

sau @ z:\…\ p1_14.sql

8. 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

9. Să se listeze, cu şi fără duplicate, codurile job-urilor din tabelul EMPLOYEES.

Obs. DISTINCT = UNIQUE

10. Să se afişeze numele concatenat cu prenumele, separate prin spaŃiu. EtichetaŃi coloana “Nume si prenume”.

Page 35: Laborator BD combinat

10

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.

Page 36: Laborator BD combinat

11

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%';

21. Folosind data curentă să se afişeze următoarele informaŃii: - numele zilei, numărul zilei din săptămână, numărul zilei din luna, respectiv numărul zilei din an; - numărul lunii din an, numele lunii cu abreviere la 3 caractere, respectiv numele complet al lunii; - ora curentă (ora, minute, secunde).

22. Să se listeze numele departamentelor care funcŃionează în locaŃia având codul 1700 şi al căror manager este cunoscut.

23. Să se afişeze codurile departamentelor în care lucrează salariaŃi.

24. Să se afişeze numele şi prenumele salariaŃilor angajaŃi în luna mai 1987.

25. Să se listeze codurile angajaŃilor care au avut şi alte joburi faŃă de cel prezent. Să se ordoneze rezultatul descrescător după codul angajatului.

26. Să se afişeze numele şi data angajării pentru cei care lucrează în departamentul 80 şi au fost angajaŃi în luna martie a anului 1997.

27. Să se afişeze numele joburilor care permit un salariu cuprins între 8300$ şi 14000$.

Page 37: Laborator BD combinat

12

28. Care este grila de salarizare pentru un salariu de 10000$?

29. Să se listeze numele tuturor angajaŃilor care au 2 litere 'L' în nume şi lucrează în departamentul 30 sau managerul lor este 123.

30. 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 $.

31. 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).

FUNCłII SQL (single-row) 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.

1. AnalizaŃi următoarele funcŃii pentru prelucrarea şirurilor de caractere:

FuncŃie SemnificaŃie Exemplu

LOWER (expresie) Converteşte un şir de caractere la minuscule.

LOWER ('AbCdE') = 'abcde'

UPPER (expresie) Converteşte un şir de caractere la majuscule.

UPPER ('AbCdE') = 'ABCDE'

INITCAP (expresie)

Converteşte un şir de caractere la un şir care începe cu majusculă şi continuă cu minuscule.

INITCAP ('AbCdE') = 'Abcde'

SUBSTR (expresie, m[, n])

Extrage din expresia de tip şir de caractere, n caractere începând cu poziŃia m. Dacă lipseşte argumentul n, atunci extrage toate caracterele până la sfârşitul şirului. Dacă m este negativ numărătoarea poziŃiilor începe de la sfârşitul şirului de caractere spre început.

SUBSTR ('AbCdE', 2, 2) = 'bC' SUBSTR ('AbCdE', 2) = 'bCdE' SUBSTR ('AbCdE', -3,2) = 'Cd' SUBSTR ('AbCdE', -3) = 'CdE'

LENGTH (expresie) Returnează numărul de caractere al expresiei.

LENGTH ('AbCdE') = 5

INSTR (expresie, expr1[, m][, n])

Returnează poziŃia la care se găseşte a n-a ocurentă a expresiei 'expr1' în cadrul expresiei 'expresie', căutarea începând de la poziŃia m. Daca m sau n lipsesc, valorile implicite sunt 1 pentru ambele.

INSTR (LOWER('AbC aBcDe'), 'ab', 5, 2) = 0 INSTR (LOWER('AbCdE aBcDe'), 'ab', 5) = 7

LTRIM (expresie[, expr1]) sau RTRIM (expresie[, expr1])

Reversul funcŃiilor LPAD, RPAD. Trunchează expresia caracter la stânga sau la dreapta prin eliminarea succesivă a caracterelor din expresia expr1. Implicit, daca lipseşte, expr1

RTRIM ('abcdeXXXX', 'X') = 'abcde' LTRIM (' abcde') = 'abcde'

Page 38: Laborator BD combinat

13

este ' ' un spaŃiu.

TRIM (LEADING | TRAILING | BOTH caractere_trim FROM expresie)

Permite eliminarea caracterelor specificate (caractere_trim) de la începutul (leading) , sfârşitul (trailing) sau din ambele părŃi, dintr-o expresie caracter data.

TRIM (LEADING 'X' FROM 'XXXabcdeXXX') = 'abcdeXXX'

TRIM (TRAILING 'X' FROM 'XXXabcdeXXX') = 'XXXabcde'

TRIM ( BOTH 'X' FROM 'XXXabcdeXXX') = 'abcde'

TRIM (' abcde ') = 'abcde'

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 (expresie [, n])

Returnează valoarea rotunjită a expresiei până la n zecimale. Daca n este negativ sunt rotunjite cifre din stânga virgulei. Valoarea implicită pentru n este 0.

ROUND(1.6) = 2 ROUND(1.4) = 1 ROUND (1234.56,1) = 1234.6 ROUND (1230.56, -2) = 1200 ROUND (1260.56, -2) = 1300

MOD (m,n) Returnează restul împărŃirii lui m la n. MOD (11, 4) = MOD (11, -4) = 3 MOD(-11, 4) = MOD (-11, -4) = -3

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ă:

OperaŃie Tipul de date al rezultatului

Descriere

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 +/- number/24

Date Scade/Adaugă un număr de ore la o / dintr-o dată calendaristică.

9. Să se afişeze data (luna, ziua, ora, minutul si secunda) de peste 10 zile.

Page 39: Laborator BD combinat

14

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

MONTHS_BETWEEN (date1, date2)

Returnează numărul de luni dintre data date1 şi data date2. Rezultatul poate fi pozitiv sau negativ după cum date1 este mai recentă sau nu faŃă de date2. Zecimalele reprezintă parŃi dintr-o luna!

ROUND(MONTHS_BETWEEN (SYSDATE + 31, SYSDATE)) = 1

ADD_MONTHS (date, n) Adaugă n luni la o data specificată. Valoarea n trebuie să fie întreagă (pozitivă sau negativă).

MONTHS_BETWEEN (ADD_MONTHS(SYSDATE, 3), SYSDATE) = 3

NEXT_DAY (date, char) Returnează data corespunzătoare primei zile a săptămânii specificate (char) care urmează după date.

NEXT_DAY('15-dec-2006','Monday') = '18-dec-2006' NEXT_DAY ('15-dec-2006',1) = '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”; SELECT last_name, ROUND(MONTHS_BETWEEN(SYSDATE, hire_date)) “Luni lucrate” FROM employees

ORDER BY 2;

15. AnalizaŃi următoarele funcŃii de conversie:

Obs. Conversiile implicite asigurate de server-ul Oracle sunt: •••• de la VARCHAR2 sau CHAR la NUMBER; •••• de la VARCHAR2 sau CHAR la DATE; •••• de la NUMBER la VARCHAR2 sau CHAR; •••• de la DATE la VARCHAR2 sau CHAR.

Page 40: Laborator BD combinat

15

SELECT last_name FROM employees WHERE TO_CHAR(hire_date,'yyyy')=1994;

SELECT last_name FROM employees WHERE hire_date='07-JUN-1994';

SELECT employee_id||' '||last_name||' '||hire_date FROM employees WHERE department_id=10;

Conversiile explicite se realizează cu ajutorul funcŃiilor de tip TO_{tip}

FuncŃie SemnificaŃie Exemplu

TO_CHAR (expr_number_sau_date[, format][, nlsparameters])

Converteşte o valoare de tip numeric sau dată calendaristică, la un şir de caractere conform cu formatul specificat sau cu setările naŃionale specificate (NLS - National Language Support). Daca formatul sau parametrii lipsesc se utilizează formatul şi parametrii impliciŃi. Formatul este case sensitive.

TO_CHAR('3') = ' 3' TO_CHAR(-12) = '-12' TO_CHAR(sysdate, 'DDMMYYYY')

= ' 09122004' TO_CHAR (sysdate + 365 * 57, 'ddmmyyyy') = ' 25112061'

TO_NUMBER (expr_char[, format][, nlsparameters])

Converteşte o valoare de tip şir de caractere la o valoare numerică conform cu formatul specificat. Dacă formatul sau parametrii lipsesc se utilizează formatul şi parametrii impliciŃi.

TO_NUMBER ('-12.22', 'S99.99') = -12.22

TO_DATE (expr_char[, format][, nlsparameters])

Converteşte o valoare de tip şir de caractere la o valoare de tip dată calendaristică în conformitate cu formatul specificat. Dacă formatul sau parametrii lipsesc se utilizează formatul şi parametrii impliciŃi.

TO_DATE ('15-feb-2006','dd-mon-yyyy')

16. Să se afişeze numele şi prenumele pentru toŃi angajaŃii care s-au angajat în luna mai.

17. AnalizaŃi următoarele funcŃii SQL :

FuncŃie SemnificaŃie Exemplu

NVL (expr1, expr2)

Returnează expr1 dacă aceasta nu este NULL, expr2 în caz contrar. Cele 2 expresii trebuie să aibă acelaşi tip sau expr2 să permită conversia implicită la tipul expresiei expr1.

NVL(NULL, 1) = 1 NVL(2, 1) = 2 NVL('c', 1) = 'c' -- face conversie NVL(1, 'c') -- eroare --nu face conversie

NVL2 (expr1, expr2, expr3) Dacă expr1 este nenulă atunci returnează expr2, altfel Returnează expr3

NVL2 (1, 2, 3) = 2 NVL2 (NULL, 2, 3) = 3

18. Să se afişeze numele angajaŃilor şi comisionul. Dacă un angajat nu câştigă comision, să se scrie “Fara comision”. EtichetaŃi coloana “Comision”.

NVL(TO_CHAR(commission_pct), ‘Fara comision’)

19. Să se listeze numele, salariul şi comisionul tuturor angajaŃilor al căror venit lunar depăşeşte 10000$.

salary * NVL(commission_pct, 0) venit_lunar

20. AnalizaŃi expresia CASE şi funcŃia DECODE:

FuncŃie/Expresie SemnificaŃie Exemplu CASE expr WHEN expr_bool1 THEN return_expr1

În funcŃie de valoarea unei expresii returnează valoarea primei perechi

Page 41: Laborator BD combinat

16

[WHEN expr_bool2 THEN return_expr2 ... WHEN expr_booln THEN return_exprn ] [ELSE return_expr] END

WHEN .. THEN care se potriveşte sau dacă nu se potriveşte nici una expresia din ELSE. Nu se poate specifica NULL pentru toate expresiile de returnat. (return_expri). Toate expresiile trebuie sa aibă acelaşi tip de date

DECODE (expr, expr_cautare1, expr_rezultat1, [expr_cautare2, expr_rezultat2, .. expr_cautaren, expr_rezultatn, ] [rezultat_implicit])

Decodifică valoarea expresiei. Dacă valoarea expresiei este expr_cautarei atunci e returnată expr_rezultati. Dacă nu se potriveşte nici o expresie de căutare atunci e returnat rezultat_implicit.

DECODE (1, 1, 2, 3) = 2 DECODE (2, 1, 2, 3) = 3 DECODE (3, 1, 2, 3) = 3

21. Să se afişeze numele, codul funcŃiei, salariul şi o coloana care să arate salariul după mărire. Se ştie că pentru IT_PROG are loc o mărire de 10%, pentru ST_CLERK 15%, iar pentru SA_REP o mărire de 20%. Pentru ceilalŃi angajaŃi nu se acordă mărire. Să se denumească coloana "Salariu revizuit".

SELECT last_name, job_id, salary, DECODE(job_id, ‘IT_PROG’, salary*1.1, ’ST_CLERK’, salary*1.15, ‘SA_REP’, salary*1.2, salary ) “salariu revizuit” FROM employees; SELECT last_name, job_id, salary, CASE job_id WHEN ‘IT_PROG’ THEN salary* 1.1 WHEN ’ST_CLERK’ THEN salary*1.15 WHEN ‘SA_REP’ THEN salary*1.2 ELSE salary END “salariu revizuit” FROM employees; SELECT last_name, job_id, salary, CASE WHEN job_id= ‘IT_PROG’ THEN salary* 1.1 WHEN job_id=’ST_CLERK’ THEN salary*1.15 WHEN job_id =‘SA_REP’ THEN salary*1.2 ELSE salary END “salariu revizuit” FROM employees;

22. Să se afişeze numele salariatului şi codul departamentului în care acesta lucrează. Dacă există salariaŃi care nu au un cod de departament asociat, atunci pe coloana id_depratment să se afişeze: textul “fara departament”; valoarea zero.

23. a. Să se afişeze numele angajaŃilor care nu au manager.

b. Să se afişeze numele angajaŃilor şi codul managerilor lor. Pentru angajaŃii care nu au manager să apară textul “nu are sef”.

24. Să se afişeze numele salariatului şi: • venitul anual dacă are comision; • salariul dacă nu are comision.

Se va utiliza funcŃia NVL2.

25. Să se afişeze numele salariatului, salariul şi salariul revizuit astfel:

Page 42: Laborator BD combinat

17

- 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%.

CERERI MULTITABEL, SUBCERERI

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’

Page 43: Laborator BD combinat

18

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

Page 44: Laborator BD combinat

19

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.

Page 45: Laborator BD combinat

20

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;

Page 46: Laborator BD combinat

21

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; b. DaŃi o altă metodă de rezolvare a acestei probleme.

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))

Page 47: Laborator BD combinat

22

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.

SELECT department_id, manager_id, COUNT(employee_id) FROM employees WHERE manager_id IS NOT NULL AND department_id IS NOT NULL GROUP BY ROLLUP (department_id, manager_id);

department_id manager_id COUNT(employee_id) --------------------------------------------------------------------- 10 7782 1 10 7839 1 10 2 ----------------------------------------------------------------------- 20 7566 2 20 7788 1 20 7839 1 20 7902 1

20 5 ----------------------------------------------------------------------- 30 7698 5 30 7839 1

30 6

Page 48: Laborator BD combinat

23

----------------------------------------------------------------------- 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.

SELECT department_id, manager_id, COUNT(employee_id) FROM employees WHERE manager_id IS NOT NULL AND department_id IS NOT NULL GROUP BY CUBE (department_id, manager_id);

department_id manager_id COUNT(employee_id) --------------------------------------------------------------------- 10 7782 1 10 7839 1 10 2 ----------------------------------------------------------------------- 20 7566 2 20 7788 1 20 7839 1 20 7902 1 20 5 ----------------------------------------------------------------------- 30 7698 5 30 7839 1 30 6 ----------------------------------------------------------------------- 7566 2

7698 5 7782 1 7788 1 7839 3

7902 1 ----------------------------------------------------------------------

13

21. Pentru fiecare departament, job, respectiv an al angajării să se afişeze numărul de salariaŃi. De asemenea se va afişa numărul de angajaŃi: - pentru fiecare departament şi job, indiferent de anul angajării; - pentru fiecare departament, indiferent de job şi de anul angajării; - la nivel de companie.

22. Să se afişeze suma alocată pentru plata salariilor pe joburi (codul jobului), în cadrul departamentului (codul departamentului). De asemenea, să se afişeze valoarea totală necesară pentru plata salariilor la nivel de departament, valoarea totală necesară pentru plata salariilor la nivel de job, indiferent de departament şi valoarea totală necesară pentru plata salariilor la nivel de companie.

23. FuncŃia GROUPING(expresie) întoarce: - valoarea 0, dacă expresia a fost utilizată pentru calculul valorii agregat - valoarea 1, dacă expresia nu a fost utilizată.

24. 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); - întreg tabelul.

Page 49: Laborator BD combinat

24

De asemenea, să se afişeze şi o coloană care indică intervenŃia coloanelor department_name şi job_title în obŃinerea rezultatului.

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: GROUP BY GROUPING SETS ((expr_11, expr_12, …, expr_1n), (expr_21, expr_22, …expr_2m),

…)

28. Să se afişeze numele departamentelor, numele job-urilor, codurile managerilor angajaŃilor, maximul şi suma salariilor pentru: - fiecare departament şi, în cadrul său, fiecare job; - fiecare job şi, în cadrul său, pentru fiecare manager; - întreg tabelul.

GROUPING SETS ((department_name, job_title), (job_title, e.manager_id), ());

Limbajul de control al datelor (DCL). COMMIT, SAVEP OINT, ROLLBACK.

• Comanda COMMIT permanentizează modificările care au fost realizate de tranzacŃia curentă (o tranzacŃie este un set de comenzi LMD); comanda suprimă toate punctele intermediare definite în tranzacŃie şi eliberează blocările tranzacŃiei.

ObservaŃie: Sistemul realizează COMMIT implicit:

- la închiderea normală a unui client Oracle (de exemplu SQL*Plus), - după fiecare comandă LDD (CREATE, ALTER, DROP).

• Comanda SAVEPOINT marchează un punct intermediar în procesarea tranzacŃiei. În acest mod este posibilă împărŃirea tranzacŃiei în subtranzacŃii.

Comanda SAVEPOINT are sintaxa:

SAVEPOINT nume_pct_intermediar;

• Comanda ROLLBACK permite renunŃarea la modificările efectuate; aceasta determină încheierea tranzacŃiei, anularea modificărilor asupra datelor şi restaurarea stării lor precedente.

Comanda ROLLBACK are sintaxa:

ROLLBACK [TO SAVEPOINT nume_punct_salvare];

Page 50: Laborator BD combinat

25

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; DELETE FROM dept_***; INSERT INTO dept_*** VALUES (300,’Economic’,100,1000); INSERT INTO dept_*** VALUES (350,’Cercetare’,200,2000); SAVEPOINT b; INSERT INTO dept_*** VALUES (400,’Juritic’,150,3000); SELECT COUNT(*) FROM dept_***; ROLLBACK TO b; SELECT COUNT(*) FROM dept_***; ROLLBACK TO a; INSERT INTO dept_*** VALUES (500,’Contabilitate’,175,1500); COMMIT; SELECT * FROM dept_***; Limbajul de prelucrare a datelor (DML). INSERT, UPDATE, DELETE. 1. Să se creeze tabele emp_*** şi dept_***, având aceeaşi structură şi date ca şi tabelele employees,

respectiv departments.

CREATE TABLE emp_*** AS SELECT * FROM employees; 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. SalvaŃi modificările.

Page 51: Laborator BD combinat

26

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 singure 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;

6. Să se exemplifice câteva dintre 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 definită NOT NULL)

INSERT INTO dept_*** (department_id, location_id) VALUES (200, 2000);

- nepotrivirea listei de coloane cu cea de expresii

INSERT INTO dept_*** VALUES (200, 2000); INSERT INTO dept_*** (department_id, department_nam e,location_id) VALUES (200, 2000);

- nepotrivirea tipului 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. InseraŃ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. 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.

Page 52: Laborator BD combinat

27

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.

12. ŞtergeŃi angajaŃii care nu au comision. AnulaŃi modificările. DELETE FROM emp_*** WHERE commission_pct IS NULL; ROLLBACK; 13. EliminaŃi departamentele care nu au nici un angajat. AnulaŃi modificările. 14. EliminaŃi angajaŃii care nu aparŃin unui departament valid. AnulaŃi modificările. 15. Sintaxa simplificată a comenzii UPDATE:

UPDATE nume_tabel [alias] SET col1 = expr1[, col2=expr2] [WHERE conditie];

sau

UPDATE nume_tabel [alias] SET (col1,col2,...) = (subcerere) [WHERE conditie];

16. MăriŃi salariul tuturor angajaŃilor din tabelul emp_*** cu 5%. AnulaŃi modificările. 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.

Page 53: Laborator BD combinat

1

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)

data_angajarii Valoare implicită data

curentă DATE

varsta NUMBER(2)

email CHAR(50)

salariu Valoare implicită 0 NUMBER(9,2)

CREATE TABLE salariat_*** (

cod_ang NUMBER(4) NOT NULL,

nume VARCHAR2(25),

prenume VARCHAR2(25),

functia VARCHAR2(20),

sef NUMBER(4),

data_angajarii DATE DEFAULT SYSDATE,

varsta NUMBER(2),

email CHAR(50),

salariu NUMBER(9,2) DEFAULT 0);

2. Afişaţi structura tabelului creat anterior.

3. Se dau următoarele valori:

COD _ANG NUME PRENUME FUNCTIA SEF DATA_ANG VARSTA EMAIL SALARIU

1 ..... ..... director null ........ 30 ..... 5500

2 ..... ..... functionar 1 ......... 25 ..... 0

3 ..... ...... economist 1 ......... 45 ..... 3000

4 ..... .... functionar 1 ......... 35 ...... 1000

4. Inseraţi în tabelul salariat_*** prima înregistrare din tabelul de mai sus fără să precizaţi lista de

coloane în comanda INSERT.

5. Inseraţi a doua înregistrare folosind o listă de coloane din care excludeţi data_angajarii şi salariul

care au valori implicite. Observaţi apoi rezultatul.

6. Inseraţi înregistrările 3 şi 4.

7. Creaţi tabelul functionar_*** care să conţină funcţionarii din tabelul salariat_***, având

următoarele coloane: codul, numele, salariul anual şi data angajării. Verificaţi cum a fost creat

tabelul şi ce date conţine.

Page 54: Laborator BD combinat

2

Modificarea tabelelor

8. Adăugaţi o nouă coloană tabelului salariat_*** care să conţină data naşterii.

ALTER TABLE salariat_***

ADD (datan DATE);

9. Modificaţi dimensiunea coloanei nume la 30 si pe cea a salariului la 12 cu 3 zecimale. ALTER TABLE salariat_***

MODIFY (nume VARCHAR2(30), salariu NUMBER(12,3));

10. Modificaţi tipul coloanei email la VARCHAR2. 11. Modificaţi valoarea implicită a coloanei data_angajarii la data sistemului + o zi. 12. Eliminaţi coloana varsta din tabelul salariat_***. ALTER TABLE salariat_***

DROP COLUMN varsta;

Redenumirea şi eliminarea tabelelor

RENAME nume_tabel TO nume_nou;

DROP TABLE nume_tabel;

13. Redenumiţi tabelul functionar_*** cu funct_***.

14. Recreaţi tabelul functionar_*** utilizând tabelul funct_***..

15. Eliminaţi tabelul funct_***.

Constrângeri

Adăugarea constrângerilor la crearea tabelului (CREATE TABLE)

CREATE TABLE [schema.]nume_tabel (

nume_coloana tip_de_date [DEFAULT expr]

[constrangere_de_coloana], ...

..[constrangere la nivel de tabel])

16. Ştergeţi şi apoi creaţi din nou tabelul salariat_*** cu următoarea structură.

NUME TIP CONSTRÂNGERE

cod_ang NUMBER(4) Cheie primară

nume VARCHAR2(25) NOT NULL

prenume VARCHAR2(25)

data_nasterii DATE data_nasterii<data_angajarii

functia VARCHAR2(9) NOT NULL

sef NUMBER(4) Referă ca şi cheie externă cod_ang din acelaşi tabel

data_angajarii DATE

email VARCHAR2(20) unic

salariu NUMBER(12,3) > 0

cod_dept NUMBER(4) Combinaţia NUME + PRENUME să fie unică

Page 55: Laborator BD combinat

3

Observaţie:

Constrângerile de tip CHECK se pot implementa la nivel de coloană doar dacă nu referă o altă

coloană a tabelului.

DROP TABLE salariat_***;

CREATE TABLE salariat_*** (

cod_ang NUMBER(4) PRIMARY KEY,

nume VARCHAR2(25) NOT NULL,

prenume VARCHAR2(25),

data_nasterii DATE,

functia VARCHAR2(9) NOT NULL,

sef NUMBER(4) REFERENCES salariat_*** (cod_ang),

data_angajarii DATE DEFAULT SYSDATE,

email VARCHAR2(20) UNIQUE,

salariu NUMBER(9,2) CHECK (salariu > 0),

cod_dep NUMBER(4),

CONSTRAINT const_c_*** CHECK (data_angajarii > data_nasterii),

CONSTRAINT const_u_*** UNIQUE (nume,prenume,data_nasterii));

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ă.

DROP TABLE salariat_***;

CREATE TABLE salariat_*** (

cod_ang NUMBER(4),

nume VARCHAR2(25) NOT NULL,

prenume VARCHAR2(25),

data_nasterii DATE,

functia VARCHAR2(9) NOT NULL,

sef NUMBER(4),

data_angajarii DATE DEFAULT SYSDATE,

email VARCHAR2(20),

salariu NUMBER(9,2),

cod_dep NUMBER(4),

CONSTRAINT ccp_*** PRIMARY KEY (cod_ang),

CONSTRAINT cce_*** FOREIGN KEY (sef) REFERENCES salariat_***

(cod_ang),

CONSTRAINT cu1_*** UNIQUE (email),

CONSTRAINT cc1_*** CHECK (data_angajarii > data_nasterii),

CONSTRAINT cc2_***CHECK (salariu > 0),

CONSTRAINT cu2_*** UNIQUE (nume,prenume,data_nasterii));

18. Creaţi tabelul departament_*** care să aibă următoarea structură.

NUME TIP CONSTRÂNGERI

COD_DEP NUMBER(4) Cheie primară

NUME VARCHAR2(20) Not null

ORAS VARCHAR2(25)

Page 56: Laborator BD combinat

4

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

2 N2 P2 11-JUN-1960

economist 1 Sysdate E2 2000 10

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?

ALTER TABLE salariat_***

ADD CONSTRAINT cce2_*** FOREIGN KEY (cod_dep) REFERENCES

departament_*** (cod_dep);

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 nume prenume data_n functia sef data_ang email salariu cod_dep

3 N3 P3 11-JUN-1967

jurist 2 Sysdate E3 2500 20

23. Ştergeţi departamentul 20 din tabelul departament_***. Ce observaţi?

24. Ştergeţi constrângerea cce2_***. Recreaţi această constrângere adăugând opţiunea ON DELETE CASCADE.

ALTER TABLE salariat_***

DROP CONSTRAINT cce2_***;

ALTER TABLE salariat_***

ADD CONSTRAINT cce2_*** FOREIGN KEY (cod_dep) REFERENCES

departament_*** (cod_dep) ON DELETE CASCADE;

25. Ştergeţi departamentul 20 din tabelul departament_***. Ce observaţi în tabelul salariat_***?

Anulaţi modificările.

cod_dep nume loc

10 Economic Bucuresti

cod_dep nume loc

20 Juritic Constanta

Page 57: Laborator BD combinat

5

26. Ştergeţi constrângerea cce2_***. Recreaţi această constrângere adăugând opţiunea ON

DELETE SET NULL.

ALTER TABLE salariat_***

DROP CONSTRAINT cce2_***;

ALTER TABLE salariat_***

ADD CONSTRAINT cce2_*** FOREIGN KEY (cod_dep) REFERENCES

departament_*** (cod_dep) ON DELETE SET NULL;

27. Încercaţi să ştergeţi departamentul 10 din tabelul departament_***. Ce observaţi?

Consultarea dicţionarului datelor

Informaţii despre tabelele create se găsesc în vizualizările :

USER_TABLES – informaţii complete despre tabelele utilizatorului curent.

ALL_TABLES – informaţii complete despre tabelele tuturor utilizatorilor.

COLS – informaţii despre coloane.

TAB – informaţii de bază despre tabelele existente în schema utilizatorului curent.

Informaţii despre constrângeri găsim în :

USER_CONSTRAINTS – informaţii despre constrângerile definite de utilizatorul

curent;

ALL_CONSTRAINTS – informaţii despre cosntrângerile definite de toţi utilizatorii.

Page 58: Laborator BD combinat

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

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.

Nu se pot realiza operaţii LMD în vizualizări ce conţin:

- funcţii grup,

- clauza GROUP BY sau HAVING,

- cuvântul cheie DISTINCT,

- pseudocoloana ROWNUM,

- coloane definite de expresii,

- coloane NOT NULL din tabelul de bază, care nu sunt incluse în coloanele vizualizării.

- linii ce nu sunt accesibile vizualizării (în cazul utilizării clauzei WITH CHECK OPTION).

Nu se pot actualiza:

- coloane ale căror valori rezultă prin calcul sau definite cu ajutorul funcţiei DECODE,

- coloane care nu respectă constrângerile din tabelele de bază.

Pentru vizualizările bazate pe mai multe tabele, orice operaţie INSERT, UPDATE sau DELETE

poate modifica datele doar din unul din tabelele de bază. Acest tabel este cel protejat prin cheie (key

preserved).

Eliminarea unei vizualizări se face prin comanda DROP VIEW :

DROP VIEW nume_viz;

Page 59: Laborator BD combinat

Observaţie:

Subcererile temporare caracterizate de un alias ce apar în comenzile SELECT, INSERT.

UPDATE, DELETE, MERGE se numesc vizualizai inline (de exemplu o subcerere utilizată

în clauza FROM a comenzii SELECT). Spre deosebire de vizualizările propriu-zise acestea

nu sunt considerate obiecte ale schemei şi sunt entităţi temporare.

Observaţie:

Reactualizarea tabelelor implică reactualizarea corespunzătoare a vizualizărilor.

Reactualizarea vizualizărilor nu implică întotdeauna reactualizarea tabelelor de bază.

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_***.

CREATE VIEW v_emp_*** (cod, nume)

AS

SELECT employee_id, last_name

FROM emp_***;

INSERT INTO v_emp_***

VALUES (400,’N1’);

DROP VIEW 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).

CREATE VIEW v_emp_***

AS

SELECT employee_id, last_name, email, hire_date, salary,job_id

FROM emp_***;

DESC v_emp_***

SELECT * FROM v_emp_***;

INSERT INTO v_emp_***

VALUES (400,’N1’,’E1’,SYSDATE,5000,’SA_REP’);

SELECT employee_id, last_name, email, hire_date, salary, job_id

FROM emp_***;

3. Să se mărească cu 1000 salariul angajatului având codul 400 din vizualizarea creată anterior. Ce efect

va avea această acţiune asupra tabelului de bază?

UPDATE v_emp_***

SET salary=salary+1000

WHERE employee_id = 400;

Page 60: Laborator BD combinat

SELECT employee_id, last_name, salary

FROM emp_***

WHERE employee_id = 400;

4. Să se şteargă angajatul având codul 400 din vizualizarea creată anterior. Ce efect va avea această

acţiune asupra tabelului de bază?

DELETE FROM v_emp_***

WHERE employee_id = 400;

SELECT employee_id, last_name, salary

FROM emp_***

WHERE employee_id = 400;

5. a) Să se creeze vizualizarea v_emp_dept_*** care să conţină employee_id, last_name, hire_date,

job_id, department_id din tabelul emp_*** şi coloana department_name din tabelul dept_***.

CREATE VIEW v_emp_dept_*** AS

SELECT employee_id, last_name, email, hire_date, job_id,

e.department_id, department_name

FROM emp_*** e, dept_*** d

WHERE e.department_id =d.department_id;

b) Să încerce inserarea înregistrării (500, 'N2', 'E2',SYSDATE,’SA_REP’,30, 'Administrativ') în

vizualizarea creată anterior.

INSERT INTO v_emp_dept_***

VALUES (500, 'N2', 'E2',SYSDATE,’SA_REP’,30, 'Administrativ');

c) Care dintre coloanele vizualizării v_emp_dept_*** sunt actualizabile?

SELECT column_name, updatable

FROM user_updatable_columns

WHERE UPPER(table_name) = UPPER('v_emp_dept_***');

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.

ALTER TABLE emp_***

ADD CONSTRAINT cp_emp_*** PRIMARY KEY (employee_id);

ALTER TABLE dept_***

ADD CONSTRAINT cp_dept1_*** PRIMARY KEY (department_id);

ALTER TABLE emp_***

ADD CONSTRAINT ce_emp1_*** FOREIGN KEY (department_id)

REFERENCES dept_***(department_id);

SELECT column_name, updatable

FROM user_updatable_columns

WHERE UPPER(table_name) = UPPER('v_emp_dept_***');

d) Recreaţi vizualizarea v_emp_dept_***, apoi verificaţi ce coloane sunt actualizabile.

Page 61: Laborator BD combinat

DROP VIEW v_emp_dept_***;

CREATE VIEW v_emp_dept_*** AS

SELECT employee_id, last_name, email, hire_date, job_id,

e.department_id, department_name

FROM emp_*** e, dept_*** d

WHERE e.department_id =d.department_id;

SELECT column_name, updatable

FROM user_updatable_columns

WHERE UPPER(table_name) = UPPER('v_emp_dept_***');

f) Inseraţi o linie prin intermediul acestei vizualizări.

Obs. Tabelul ale cărui coloane sunt actualizabile este protejat prin cheie.

INSERT INTO v_emp_dept_*** (employee_id, last_name,email,hire_date,

job_id, department_id)

VALUES (500, 'N2', 'E2',SYSDATE,’SA_REP’,30);

g) Ce efect are o operaţie de ştergere prin intermediul vizualizării v_emp_dept_***? Comentaţi.

DELETE FROM v_emp_dept_***

WHERE employee_id = 500;

SELECT employee_id, last_name, hire_date, job_id, department_id

FROM emp_***

WHERE employee_id = 500;

SELECT department_id, department_name

FROM dept_***

WHERE department_id = 30;

6. Să se creeze vizualizarea v_dept_*** care să conţine codul şi numele departamentului, numărul de

angajaţi din departamentul respectiv şi suma alocată pentru plata salariilor. Această vizualizare

permite actualizări?

CREATE VIEW v_dept_*** (cod, nume, nr_angajati, val_salarii)

AS

SELECT e.department_id, department_name, COUNT(*) nr_angajati,

SUM(salary) val_salarii

FROM emp_*** e, dept_*** d

WHERE e.department_id = d.department_id

GROUP BY e.department_id, department_name;

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.

Page 62: Laborator BD combinat

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_***;

b) Să se listeze structura şi conţinutul vizualizării v_emp30_***.

DESCRIBE v_emp30_***

SELECT * FROM v_emp30_***;

c) Să se încerce prin intermediul vizualizării inserarea unui angajat în departamentul 10 şi a unui

angajat în departamentul 30.

INSERT INTO v_emp30_***

VALUES (111, 'N1', 'E1',SYSDATE,1000,’SA_REP’,10);

INSERT INTO v_emp30_***

VALUES (11, 'N11', 'E11',SYSDATE,1000,’SA_REP’,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.

CREATE VIEW v_dept_*** AS

SELECT *

FROM dept_***

WITH READ ONLY;

9. Să se consulte informaţii despre vizualizarea v_dept_***. Folosiţi vizualizarea dicţionarului datelor

USER_VIEWS (coloanele VIEW_NAME şi TEXT).

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.

SET LONG 200

SELECT view_name, text

FROM user_views

WHERE UPPER(view_name)=UPPER(’v_dept_***’);

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ţă

Page 63: Laborator BD combinat

[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;

Page 64: Laborator BD combinat

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');

13. Să se afişeze valoarea curentă a secvenţei.

SELECT sec_***.CURRVAL valoare

FROM DUAL;

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 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_***.

Page 65: Laborator BD combinat

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.

Informaţii din dicţionarul datelor

Tipuri de vizualizări ale dicţionarului datelor:

ALL_* - obiecte accesibile utilizatorului curent,

DBA_* - obiecte accesibile numai administratorului,

USER_* - obiecte ale utilizatorului curent

1. Tabelele utilizatorului curent:

SELECT table_name

FROM user_tables

ORDER BY table_name;

2. Definiţiile şi numele constrângerilor:

SELECT constraint_name, constraint_type, search_condition, table_name

FROM user_constraints

WHERE table_name IN ('EMPLOYEES', 'DEPARTAMENTS’)

ORDER BY table_name, constraint_name;

3. Coloanele asociate unei constrângeri:

SELECT constraint_name, column_name

FROM user_cons_columns

WHERE table_name IN ('EMPLOYEES', 'DEPARTAMENTS’)

ORDER BY table_name, constraint_name;

4. Informaţii despre vizualizări:

SELECT view_name

FROM user_views;

5. Informaţii referitoare la secvenţe:

SELECT sequence_name, min_value, max_value, increment_by, last_number

FROM user_sequences;

6. Informaţii referitoare la indecşi:

Page 66: Laborator BD combinat

SELECT index_name, table_name

FROM user_indexes;

SELECT index_name

FROM user_ind_columns;

SELECT a.index_name, a.column_name,a.column_position poz, b.uniqueness

FROM user_indexes b, user_ind_columns a

WHERE a.index_name = b.index_name

AND a.table_name = 'EMP_***';

7. Informaţii referitoare la sinonime:

SELECT synonym_name, table_owner, table_name

FROM user_synonyms;

Page 67: Laborator BD combinat

LABORATOR 8 - SQL

SQL 1999 (SQL3). Operatori pe mulţimi

SQL 1999 (SQL3)

1. Comparaţie între sintaxa Oracle şi SQL 1999. Pentru join, sistemul Oracle9i oferă şi o sintaxă specifică, în

conformitate cu standardul SQL3 (SQL:1999).

Oracle SQL 1999

Equijoin Natural Join sau Inner Join

Outer Join Outer Join

Selfjoin Join ON

Non equijoin Join USING/ ON

Produs cartezian Cross Join

Sintaxa corespunzătoare standardului SQL3 este următoarea:

SELECT tabel_1.nume_coloană, tabel_2.nume_coloană

FROM tabel_1

[CROSS JOIN tabel_2]

| [NATURAL JOIN tabel_2]

| [JOIN tabel_2 USING (nume_coloană) ]

| [JOIN tabel_2 ON (tabel_1.nume_coloană = tabel_2.nume_coloană) ]

| [LEFT | RIGHT | FULL OUTER JOIN tabel_2

ON (tabel_1.nume_coloană = tabel_2.nume_coloană) ];

2. Tipuri de join compilante cu SQL 1999, implementate de Oracle9i:

a) Cross Join. Realizează produsul cartezian a tabelor locations şi countries.

SELECT city, l.country_id, country_name

FROM locations l

CROSS JOIN countries;

SELECT city, l.country_id, country_name

FROM locations l, countries;

b) Natural Join. Se bazează pe coloanele cu acelaşi nume din cele două tabele şi selectează liniile care au

aceleaşi valori pentru aceste coloane. Dacă tipurile de date ale coloanelor cu nume identice sunt diferite,

va fi returnată o eroare. Coloanele comune nu trebuie calificate cu aliasuri. Oracle9i oferă posibilitatea

completării automate a operaţiei de join. Coloanele având acelaşi nume în cele două tabele trebuie să nu

fie precedate de numele sau alias-ul tabelului corespunzător.

SELECT last_name, job_id, job_title

FROM employees

NATURAL JOIN jobs;

SELECT last_name, e.job_id, job_title

FROM employees e, jobs j

WHERE e.job_id=j.job_id;

c) Using/On Join.

JOIN tabl2 USING nume_coloană – Dacă avem coloane cu acelaşi nume, dar cu tipurile de date

diferite, atunci în loc de NATURAL JOIN se utilizează JOIN cu clauza USING. Similar cu

NATURAL JOIN, coloana de legătură nu trebuie calificată cu alias oriunde în cadrul cererii. Acest

tip de JOIN se mai foloseşte atunci când cele două tabele au mai multe coloane cu nume comun, dar

legătura dintre ele trebuie făcută doar utilizând câteva dintre acestea.

JOIN tab2 ON tab1.nume_coloană = tab2.nume_coloană – Dacă se doreşte particularizarea,

specificarea şi/sau evidenţierea clară a condiţiei de join se utilizează clauza ON. Aceasta separă

Page 68: Laborator BD combinat

condiţia de JOIN de alte condiţii, făcând codul mai lizibil. Într-o înlănţuire de JOIN-uri acestea sunt

evaluate de la stânga la dreapta.

SELECT last_name, department_name, location_id

FROM employees JOIN departments

USING (department_id);

SELECT last_name, department_name, location_id

FROM employees e JOIN departments d

ON (e.department_id = d.department_id);

SELECT last_name, department_name, location_id

FROM employees e, departments d

WHERE e.department_id=d.department_id;

d) Outerjoin cu sau fără condiţii suplimentare (complet, la stânga sau la dreapta).

INNER vs. OUTER JOIN

Join-ul a două tabele ce returnează doar liniile ce corespund condiţiei de JOIN se numeşte INNER

JOIN.

Join-ul a două tabele ce returnează atât liniile ce corespund condiţiei de JOIN cât şi cele care nu

îndeplinesc această condiţie se numeşte OUTER JOIN. Liniile dintr-un tabel care nu au

corespondent în celălalt tabel sunt completate cu valori NULL.

LEFT/RIGHT/FULL OUTER JOIN tab_1 ON (tab1.nume_coloană = tab2.nume_coloană) efectuează outer join la stânga, dreapta, respectiv în ambele părţi pe baza condiţiei exprimate în

clauza ON.

Un join care returnează rezultatele unui inner join, dar şi cele ale outer join-urilor la stânga şi la

dreapta se numeşte full outer join.

SELECT last_name, department_name, location_id

FROM employees e

LEFT OUTER JOIN departments d

ON (e.department_id = d.department_id);

SELECT last_name, department_name, location_id

FROM employees e

RIGHT OUTER JOIN departments d

ON (e.department_id = d.department_id);

SELECT last_name, department_name, location_id

FROM employees e

FULL OUTER JOIN departments d

ON (e.department_id = d.department_id);

Exerciţiu

Alegeţi 10 cereri care utilizează join-uri din laboratorul 3 şi rezolvaţi aceste cereri cu SQL standard.

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.

Page 69: Laborator BD combinat

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;

13. Să se obţină codurile angajaţilor care nu au avut joburi anterioare.

Page 70: Laborator BD combinat

a. Utilizaţi operatorul MINUS.

b. Utilizaţi operatorul NOT IN.

14. Să se obţină codul, codul jobului şi codul departamentului angajaţilor care în trecut au lucrat pe alte joburi

sau în alte departamente faţă de prezent. Utilizaţi operatorul MINUS.

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.

Page 71: Laborator BD combinat

1

Limbajul de definire a datelor (DDL). CREATE, ALTER , DROP

Definirea tabelelor CREATE TABLE [schema.]nume_tabel (

nume_coloana tip_de_date [DEFAULT 1 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)

data_angajarii Valoare implicită data curentă

DATE

varsta NUMBER(2) email CHAR(50) salariu Valoare implicită 0 NUMBER(9,2)

CREATE TABLE salariat_*** ( cod_ang NUMBER(4) NOT NULL, nume VARCHAR2(25), prenume VARCHAR2(25), functia VARCHAR2(20), sef NUMBER(4), data_angajarii DATE DEFAULT SYSDATE, varsta NUMBER(2), email CHAR(50), salariu NUMBER(9,2) DEFAULT 0);

2. AfişaŃi structura tabelului creat anterior.

3. Se dau următoarele valori:

COD _ANG NUME PRENUME FUNCTIA SEF DATA_ANG VARSTA EMAIL SALARIU 1 ..... ..... director null ........ 30 ..... 5500 2 ..... ..... functionar 1 ......... 25 ..... 0 3 ..... ...... economist 1 ......... 45 ..... 3000 4 ..... .... functionar 1 ......... 35 ...... 1000

4. InseraŃi în tabelul salariat_*** prima înregistrare din tabelul de mai sus fără să precizaŃi lista de coloane în comanda INSERT.

5. InseraŃi a doua înregistrare folosind o listă de coloane din care excludeŃi data_angajarii şi salariul care au valori implicite. ObservaŃi apoi rezultatul.

6. InseraŃi înregistrările 3 şi 4.

7. CreaŃi tabelul functionar_*** care să conŃină funcŃionarii din tabelul salariat_*** , având următoarele coloane: codul, numele, salariul anual şi data angajării. VerificaŃi cum a fost creat tabelul şi ce date conŃine.

Page 72: Laborator BD combinat

2

Modificarea tabelelor

8. AdăugaŃi o nouă coloană tabelului salariat_*** care să conŃină data naşterii.

ALTER TABLE salariat_*** ADD (datan DATE); 9. ModificaŃi dimensiunea coloanei nume la 30 si pe cea a salariului la 12 cu 3 zecimale. ALTER TABLE salariat_*** MODIFY (nume VARCHAR2(30), salariu NUMBER(12,3)); 10. ModificaŃi tipul coloanei email la VARCHAR2. 11. ModificaŃi valoarea implicită a coloanei data_angajarii la data sistemului + o zi. 12. EliminaŃi coloana varsta din tabelul salariat_***. ALTER TABLE salariat_*** DROP COLUMN varsta;

Redenumirea şi eliminarea tabelelor

RENAME nume_tabel TO nume_nou; DROP TABLE nume_tabel;

13. RedenumiŃi tabelul functionar_*** cu funct_*** .

14. RecreaŃi tabelul functionar_*** utilizând tabelul funct_*** ..

15. EliminaŃi tabelul funct_***.

Constrângeri

Adăugarea constrângerilor la crearea tabelului (CREATE TABLE)

CREATE TABLE [schema.]nume_tabel (

nume_coloana tip_de_date [DEFAULT expr]

[constrangere_de_coloana], ...

..[constrangere la nivel de tabel])

16. ŞtergeŃi şi apoi creaŃi din nou tabelul salariat_*** cu următoarea structură.

NUME TIP CONSTRÂNGERE cod_ang NUMBER(4) Cheie primară nume VARCHAR2(25) NOT NULL prenume VARCHAR2(25) data_nasterii DATE data_nasterii<data_angajarii functia VARCHAR2(9) NOT NULL

sef NUMBER(4) Referă ca şi cheie externă cod_ang din acelaşi tabel

data_angajarii DATE email VARCHAR2(20) unic salariu NUMBER(12,3) > 0 cod_dept NUMBER(4) CombinaŃia NUME + PRENUME să fie unică

Page 73: Laborator BD combinat

3

ObservaŃie: Constrângerile de tip CHECK se pot implementa la nivel de coloană doar dacă nu referă o altă coloană a

tabelului.

DROP TABLE salariat_***; CREATE TABLE salariat_*** ( cod_ang NUMBER(4) PRIMARY KEY, nume VARCHAR2(25) NOT NULL, prenume VARCHAR2(25), data_nasterii DATE, functia VARCHAR2(9) NOT NULL, sef NUMBER(4) REFERENCES salariat_*** (cod_ang), data_angajarii DATE DEFAULT SYSDATE, email VARCHAR2(20) UNIQUE, salariu NUMBER(9,2) CHECK (salariu > 0), cod_dep NUMBER(4), CONSTRAINT const_c_*** CHECK (data_angajarii > data _nasterii), CONSTRAINT const_u_*** UNIQUE (nume,prenume,data_na sterii));

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ă.

DROP TABLE salariat_***; CREATE TABLE salariat_*** ( cod_ang NUMBER(4), nume VARCHAR2(25) NOT NULL, prenume VARCHAR2(25), data_nasterii DATE, functia VARCHAR2(9) NOT NULL, sef NUMBER(4), data_angajarii DATE DEFAULT SYSDATE, email VARCHAR2(20), salariu NUMBER(9,2), cod_dep NUMBER(4), CONSTRAINT ccp_*** PRIMARY KEY (cod_ang), CONSTRAINT cce_*** FOREIGN KEY (sef) REFERENCES sal ariat_*** (cod_ang), CONSTRAINT cu1_*** UNIQUE (email), CONSTRAINT cc1_*** CHECK (data_angajarii > data_nas terii), CONSTRAINT cc2_***CHECK (salariu > 0), CONSTRAINT cu2_*** UNIQUE (nume,prenume,data_naster ii));

18. CreaŃi tabelul departament_*** care să aibă următoarea structură.

NUME TIP CONSTRÂNGERI COD_DEP NUMBER(4) Cheie primară NUME VARCHAR2(20) Not null ORAS VARCHAR2(25)

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

Page 74: Laborator BD combinat

4

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

2 N2 P2 11-JUN-1960

economist 1 Sysdate E2 2000 10

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?

ALTER TABLE salariat_*** ADD CONSTRAINT cce2_*** FOREIGN KEY (cod_dep) REFER ENCES departament_*** (cod_dep); 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 nume prenume data_n functia sef data_ang email salariu cod_dep

3 N3 P3 11-JUN-1967

jurist 2 Sysdate E3 2500 20

23. ŞtergeŃi departamentul 20 din tabelul departament_***. Ce observaŃi?

24. ŞtergeŃi constrângerea cce2_***. RecreaŃi această constrângere adăugând opŃiunea ON DELETE CASCADE.

25. ŞtergeŃi departamentul 20 din tabelul departament_***. Ce observaŃi în tabelul salariat_***? AnulaŃi modificările.

26. ŞtergeŃi constrângerea cce2_***. RecreaŃi această constrângere adăugând opŃiunea ON DELETE SET NULL.

27. ÎncercaŃi să ştergeŃi departamentul 10 din tabelul departament_***. Ce observaŃi? Consultarea dicŃionarului datelor

InformaŃii despre tabelele create se găsesc în vizualizările :

• USER_TABLES – informaŃii complete despre tabelele utilizatorului curent.

cod_dep nume loc 10 Economic Bucuresti

cod_dep nume loc 20 Juritic Constanta

Page 75: Laborator BD combinat

5

• ALL_TABLES – informaŃii complete despre tabelele tuturor utilizatorilor. • COLS – informaŃii despre coloane. • TAB – informaŃii de bază despre tabelele existente în schema utilizatorului curent.

InformaŃii despre constrângeri găsim în :

• USER_CONSTRAINTS – informaŃii despre constrângerile definite de utilizatorul curent; • ALL_CONSTRAINTS – informaŃii despre cosntrângerile definite de toŃi utilizatorii.

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_***.

CREATE VIEW v_emp_*** (cod, nume) AS SELECT employee_id, last_name FROM emp_***; INSERT INTO v_emp_*** VALUES (400,’N1’); DROP VIEW 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ă.

CREATE VIEW v_emp_*** AS SELECT employee_id, last_name, email, hire_date, s alary,job_id FROM emp_***; DESC v_emp_*** SELECT * FROM v_emp_***;

Page 76: Laborator BD combinat

6

INSERT INTO v_emp_*** VALUES (400,’N1’,’E1’,SYSDATE,5000,’SA_REP’); SELECT employee_id, last_name, email, hire_date, sa lary, job_id FROM emp_***;

3. Să se mărească cu 1000 salariul angajatului având codul 400 din vizualizarea creată anterior. Ce efect va avea această acŃiune asupra tabelului de bază?

4. Să se şteargă angajatul având codul 400 din vizualizarea creată anterior. Ce efect va avea această acŃiune asupra tabelului de bază?

5. a) Să se creeze vizualizarea v_emp_dept_*** care să conŃină employee_id, last_name, hire_date, job_id, department_id din tabelul emp_*** şi coloana department_name din tabelul dept_***. b) Să încerce inserarea înregistrării (500, 'N2', 'E2',SYSDATE,’SA_REP’,30, 'Administrativ') în vizualizarea creată anterior.

c) Care dintre coloanele vizualizării v_emp_dept_*** sunt actualizabile?

SELECT column_name, updatable FROM user_updatable_columns WHERE UPPER(table_name) = UPPER('v_emp_dept_***'); 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. 6. Să se creeze vizualizarea v_dept_*** care să conŃine codul şi numele departamentului, numărul de

angajaŃi din departamentul respectiv şi suma alocată pentru plata salariilor. Această vizualizare permite actualizări?

CREATE VIEW v_dept_*** (cod, nume, nr_angajati, val _salarii) AS SELECT e.department_id, department_name, COUNT(*) nr_angajati, SUM(salary) val_salarii FROM emp_*** e, dept_*** d WHERE e.department_id = d.department_id GROUP BY e.department_id, department_name; 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, s alary, job_id, department_id FROM emp_*** WHERE department_id=30 WITH CHECK OPTION CONSTRAINT ck_option1_***;

b) Să se listeze structura şi conŃinutul vizualizării v_emp30_***.

Page 77: Laborator BD combinat

7

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.

CREATE VIEW v_dept_*** AS SELECT * FROM dept_*** WITH READ ONLY; 9. Să se consulte informaŃii despre vizualizarea v_dept_***. FolosiŃi vizualizarea dicŃionarului datelor USER_VIEWS (coloanele VIEW_NAME şi TEXT). 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. SET LONG 200 SELECT view_name, text FROM user_views WHERE UPPER(view_name)=UPPER(’v_dept_***’);

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ă. 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.

Page 78: Laborator BD combinat

8

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. SELECT sec_***.CURRVAL valoare FROM DUAL; 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.

Page 79: Laborator BD combinat

9

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} …] ]

2. Să se listeze structura tabelelor din schema HR (EMPLOYEES, DEPARTMENTS, JOB_HISTORY, JOBS, LOCATIONS, COUNTRIES, REGIONS), observând tipurile de date ale coloanelor.

Obs: Se va utiliza comanda SQL*Plus

DESCRIBE nume_tabel

3. Să se listeze conŃinutul tabelelor din schema considerată, afişând valorile tuturor câmpurilor.

Obs: Se va utiliza comanda SQL

SELECT * FROM nume_tabel;

4. Să se obŃină încă o dată rezultatul cererii precedente, fără a rescrie cererea.

Obs: Ultima comandă SQL lansată de către client este păstrată în buffer-ul SQL.

Pentru rularea acesteia se utilizează “/” sau RUN.

5. ListaŃi structura tabelului EMPLOYEES şi apoi daŃi comanda RUN (sau “/”). Ce observaŃi? Comenzile SQL*Plus sunt păstrate în buffer?

DESC employees RUN

6. 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

7. ReexecutaŃi cererea folosind fişierul p1_14.sql. START z:\…\ p1_14.sql

sau @ z:\…\ p1_14.sql

8. 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

9. Să se listeze, cu şi fără duplicate, codurile job-urilor din tabelul EMPLOYEES.

Obs. DISTINCT = UNIQUE

10. Să se afişeze numele concatenat cu prenumele, separate prin spaŃiu. EtichetaŃi coloana “Nume si prenume”.

Page 80: Laborator BD combinat

10

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.

Page 81: Laborator BD combinat

11

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%';

21. Folosind data curentă să se afişeze următoarele informaŃii: - numele zilei, numărul zilei din săptămână, numărul zilei din luna, respectiv numărul zilei din an; - numărul lunii din an, numele lunii cu abreviere la 3 caractere, respectiv numele complet al lunii; - ora curentă (ora, minute, secunde).

22. Să se listeze numele departamentelor care funcŃionează în locaŃia având codul 1700 şi al căror manager este cunoscut.

23. Să se afişeze codurile departamentelor în care lucrează salariaŃi.

24. Să se afişeze numele şi prenumele salariaŃilor angajaŃi în luna mai 1987.

25. Să se listeze codurile angajaŃilor care au avut şi alte joburi faŃă de cel prezent. Să se ordoneze rezultatul descrescător după codul angajatului.

26. Să se afişeze numele şi data angajării pentru cei care lucrează în departamentul 80 şi au fost angajaŃi în luna martie a anului 1997.

27. Să se afişeze numele joburilor care permit un salariu cuprins între 8300$ şi 14000$.

Page 82: Laborator BD combinat

12

28. Care este grila de salarizare pentru un salariu de 10000$?

29. Să se listeze numele tuturor angajaŃilor care au 2 litere 'L' în nume şi lucrează în departamentul 30 sau managerul lor este 123.

30. 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 $.

31. 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).

FUNCłII SQL (single-row) 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.

1. AnalizaŃi următoarele funcŃii pentru prelucrarea şirurilor de caractere:

FuncŃie SemnificaŃie Exemplu

LOWER (expresie) Converteşte un şir de caractere la minuscule.

LOWER ('AbCdE') = 'abcde'

UPPER (expresie) Converteşte un şir de caractere la majuscule.

UPPER ('AbCdE') = 'ABCDE'

INITCAP (expresie)

Converteşte un şir de caractere la un şir care începe cu majusculă şi continuă cu minuscule.

INITCAP ('AbCdE') = 'Abcde'

SUBSTR (expresie, m[, n])

Extrage din expresia de tip şir de caractere, n caractere începând cu poziŃia m. Dacă lipseşte argumentul n, atunci extrage toate caracterele până la sfârşitul şirului. Dacă m este negativ numărătoarea poziŃiilor începe de la sfârşitul şirului de caractere spre început.

SUBSTR ('AbCdE', 2, 2) = 'bC' SUBSTR ('AbCdE', 2) = 'bCdE' SUBSTR ('AbCdE', -3,2) = 'Cd' SUBSTR ('AbCdE', -3) = 'CdE'

LENGTH (expresie) Returnează numărul de caractere al expresiei.

LENGTH ('AbCdE') = 5

INSTR (expresie, expr1[, m][, n])

Returnează poziŃia la care se găseşte a n-a ocurentă a expresiei 'expr1' în cadrul expresiei 'expresie', căutarea începând de la poziŃia m. Daca m sau n lipsesc, valorile implicite sunt 1 pentru ambele.

INSTR (LOWER('AbC aBcDe'), 'ab', 5, 2) = 0 INSTR (LOWER('AbCdE aBcDe'), 'ab', 5) = 7

LTRIM (expresie[, expr1]) sau RTRIM (expresie[, expr1])

Reversul funcŃiilor LPAD, RPAD. Trunchează expresia caracter la stânga sau la dreapta prin eliminarea succesivă a caracterelor din expresia expr1. Implicit, daca lipseşte, expr1

RTRIM ('abcdeXXXX', 'X') = 'abcde' LTRIM (' abcde') = 'abcde'

Page 83: Laborator BD combinat

13

este ' ' un spaŃiu.

TRIM (LEADING | TRAILING | BOTH caractere_trim FROM expresie)

Permite eliminarea caracterelor specificate (caractere_trim) de la începutul (leading) , sfârşitul (trailing) sau din ambele părŃi, dintr-o expresie caracter data.

TRIM (LEADING 'X' FROM 'XXXabcdeXXX') = 'abcdeXXX'

TRIM (TRAILING 'X' FROM 'XXXabcdeXXX') = 'XXXabcde'

TRIM ( BOTH 'X' FROM 'XXXabcdeXXX') = 'abcde'

TRIM (' abcde ') = 'abcde'

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 (expresie [, n])

Returnează valoarea rotunjită a expresiei până la n zecimale. Daca n este negativ sunt rotunjite cifre din stânga virgulei. Valoarea implicită pentru n este 0.

ROUND(1.6) = 2 ROUND(1.4) = 1 ROUND (1234.56,1) = 1234.6 ROUND (1230.56, -2) = 1200 ROUND (1260.56, -2) = 1300

MOD (m,n) Returnează restul împărŃirii lui m la n. MOD (11, 4) = MOD (11, -4) = 3 MOD(-11, 4) = MOD (-11, -4) = -3

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ă:

OperaŃie Tipul de date al rezultatului

Descriere

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 +/- number/24

Date Scade/Adaugă un număr de ore la o / dintr-o dată calendaristică.

9. Să se afişeze data (luna, ziua, ora, minutul si secunda) de peste 10 zile.

Page 84: Laborator BD combinat

14

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

MONTHS_BETWEEN (date1, date2)

Returnează numărul de luni dintre data date1 şi data date2. Rezultatul poate fi pozitiv sau negativ după cum date1 este mai recentă sau nu faŃă de date2. Zecimalele reprezintă parŃi dintr-o luna!

ROUND(MONTHS_BETWEEN (SYSDATE + 31, SYSDATE)) = 1

ADD_MONTHS (date, n) Adaugă n luni la o data specificată. Valoarea n trebuie să fie întreagă (pozitivă sau negativă).

MONTHS_BETWEEN (ADD_MONTHS(SYSDATE, 3), SYSDATE) = 3

NEXT_DAY (date, char) Returnează data corespunzătoare primei zile a săptămânii specificate (char) care urmează după date.

NEXT_DAY('15-dec-2006','Monday') = '18-dec-2006' NEXT_DAY ('15-dec-2006',1) = '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”; SELECT last_name, ROUND(MONTHS_BETWEEN(SYSDATE, hire_date)) “Luni lucrate” FROM employees

ORDER BY 2;

15. AnalizaŃi următoarele funcŃii de conversie:

Obs. Conversiile implicite asigurate de server-ul Oracle sunt: •••• de la VARCHAR2 sau CHAR la NUMBER; •••• de la VARCHAR2 sau CHAR la DATE; •••• de la NUMBER la VARCHAR2 sau CHAR; •••• de la DATE la VARCHAR2 sau CHAR.

Page 85: Laborator BD combinat

15

SELECT last_name FROM employees WHERE TO_CHAR(hire_date,'yyyy')=1994;

SELECT last_name FROM employees WHERE hire_date='07-JUN-1994';

SELECT employee_id||' '||last_name||' '||hire_date FROM employees WHERE department_id=10;

Conversiile explicite se realizează cu ajutorul funcŃiilor de tip TO_{tip}

FuncŃie SemnificaŃie Exemplu

TO_CHAR (expr_number_sau_date[, format][, nlsparameters])

Converteşte o valoare de tip numeric sau dată calendaristică, la un şir de caractere conform cu formatul specificat sau cu setările naŃionale specificate (NLS - National Language Support). Daca formatul sau parametrii lipsesc se utilizează formatul şi parametrii impliciŃi. Formatul este case sensitive.

TO_CHAR('3') = ' 3' TO_CHAR(-12) = '-12' TO_CHAR(sysdate, 'DDMMYYYY')

= ' 09122004' TO_CHAR (sysdate + 365 * 57, 'ddmmyyyy') = ' 25112061'

TO_NUMBER (expr_char[, format][, nlsparameters])

Converteşte o valoare de tip şir de caractere la o valoare numerică conform cu formatul specificat. Dacă formatul sau parametrii lipsesc se utilizează formatul şi parametrii impliciŃi.

TO_NUMBER ('-12.22', 'S99.99') = -12.22

TO_DATE (expr_char[, format][, nlsparameters])

Converteşte o valoare de tip şir de caractere la o valoare de tip dată calendaristică în conformitate cu formatul specificat. Dacă formatul sau parametrii lipsesc se utilizează formatul şi parametrii impliciŃi.

TO_DATE ('15-feb-2006','dd-mon-yyyy')

16. Să se afişeze numele şi prenumele pentru toŃi angajaŃii care s-au angajat în luna mai.

17. AnalizaŃi următoarele funcŃii SQL :

FuncŃie SemnificaŃie Exemplu

NVL (expr1, expr2)

Returnează expr1 dacă aceasta nu este NULL, expr2 în caz contrar. Cele 2 expresii trebuie să aibă acelaşi tip sau expr2 să permită conversia implicită la tipul expresiei expr1.

NVL(NULL, 1) = 1 NVL(2, 1) = 2 NVL('c', 1) = 'c' -- face conversie NVL(1, 'c') -- eroare --nu face conversie

NVL2 (expr1, expr2, expr3) Dacă expr1 este nenulă atunci returnează expr2, altfel Returnează expr3

NVL2 (1, 2, 3) = 2 NVL2 (NULL, 2, 3) = 3

18. Să se afişeze numele angajaŃilor şi comisionul. Dacă un angajat nu câştigă comision, să se scrie “Fara comision”. EtichetaŃi coloana “Comision”.

NVL(TO_CHAR(commission_pct), ‘Fara comision’)

19. Să se listeze numele, salariul şi comisionul tuturor angajaŃilor al căror venit lunar depăşeşte 10000$.

salary * NVL(commission_pct, 0) venit_lunar

20. AnalizaŃi expresia CASE şi funcŃia DECODE:

FuncŃie/Expresie SemnificaŃie Exemplu CASE expr WHEN expr_bool1 THEN return_expr1

În funcŃie de valoarea unei expresii returnează valoarea primei perechi

Page 86: Laborator BD combinat

16

[WHEN expr_bool2 THEN return_expr2 ... WHEN expr_booln THEN return_exprn ] [ELSE return_expr] END

WHEN .. THEN care se potriveşte sau dacă nu se potriveşte nici una expresia din ELSE. Nu se poate specifica NULL pentru toate expresiile de returnat. (return_expri). Toate expresiile trebuie sa aibă acelaşi tip de date

DECODE (expr, expr_cautare1, expr_rezultat1, [expr_cautare2, expr_rezultat2, .. expr_cautaren, expr_rezultatn, ] [rezultat_implicit])

Decodifică valoarea expresiei. Dacă valoarea expresiei este expr_cautarei atunci e returnată expr_rezultati. Dacă nu se potriveşte nici o expresie de căutare atunci e returnat rezultat_implicit.

DECODE (1, 1, 2, 3) = 2 DECODE (2, 1, 2, 3) = 3 DECODE (3, 1, 2, 3) = 3

21. Să se afişeze numele, codul funcŃiei, salariul şi o coloana care să arate salariul după mărire. Se ştie că pentru IT_PROG are loc o mărire de 10%, pentru ST_CLERK 15%, iar pentru SA_REP o mărire de 20%. Pentru ceilalŃi angajaŃi nu se acordă mărire. Să se denumească coloana "Salariu revizuit".

SELECT last_name, job_id, salary, DECODE(job_id, ‘IT_PROG’, salary*1.1, ’ST_CLERK’, salary*1.15, ‘SA_REP’, salary*1.2, salary ) “salariu revizuit” FROM employees; SELECT last_name, job_id, salary, CASE job_id WHEN ‘IT_PROG’ THEN salary* 1.1 WHEN ’ST_CLERK’ THEN salary*1.15 WHEN ‘SA_REP’ THEN salary*1.2 ELSE salary END “salariu revizuit” FROM employees; SELECT last_name, job_id, salary, CASE WHEN job_id= ‘IT_PROG’ THEN salary* 1.1 WHEN job_id=’ST_CLERK’ THEN salary*1.15 WHEN job_id =‘SA_REP’ THEN salary*1.2 ELSE salary END “salariu revizuit” FROM employees;

22. Să se afişeze numele salariatului şi codul departamentului în care acesta lucrează. Dacă există salariaŃi care nu au un cod de departament asociat, atunci pe coloana id_depratment să se afişeze: textul “fara departament”; valoarea zero.

23. a. Să se afişeze numele angajaŃilor care nu au manager.

b. Să se afişeze numele angajaŃilor şi codul managerilor lor. Pentru angajaŃii care nu au manager să apară textul “nu are sef”.

24. Să se afişeze numele salariatului şi: • venitul anual dacă are comision; • salariul dacă nu are comision.

Se va utiliza funcŃia NVL2.

25. Să se afişeze numele salariatului, salariul şi salariul revizuit astfel:

Page 87: Laborator BD combinat

17

- 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%.

CERERI MULTITABEL, SUBCERERI

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’

Page 88: Laborator BD combinat

18

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

Page 89: Laborator BD combinat

19

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.

Page 90: Laborator BD combinat

20

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;

Page 91: Laborator BD combinat

21

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; b. DaŃi o altă metodă de rezolvare a acestei probleme.

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))

Page 92: Laborator BD combinat

22

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.

SELECT department_id, manager_id, COUNT(employee_id) FROM employees WHERE manager_id IS NOT NULL AND department_id IS NOT NULL GROUP BY ROLLUP (department_id, manager_id);

department_id manager_id COUNT(employee_id) --------------------------------------------------------------------- 10 7782 1 10 7839 1 10 2 ----------------------------------------------------------------------- 20 7566 2 20 7788 1 20 7839 1 20 7902 1

20 5 ----------------------------------------------------------------------- 30 7698 5 30 7839 1

30 6

Page 93: Laborator BD combinat

23

----------------------------------------------------------------------- 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.

SELECT department_id, manager_id, COUNT(employee_id) FROM employees WHERE manager_id IS NOT NULL AND department_id IS NOT NULL GROUP BY CUBE (department_id, manager_id);

department_id manager_id COUNT(employee_id) --------------------------------------------------------------------- 10 7782 1 10 7839 1 10 2 ----------------------------------------------------------------------- 20 7566 2 20 7788 1 20 7839 1 20 7902 1 20 5 ----------------------------------------------------------------------- 30 7698 5 30 7839 1 30 6 ----------------------------------------------------------------------- 7566 2

7698 5 7782 1 7788 1 7839 3

7902 1 ----------------------------------------------------------------------

13

21. Pentru fiecare departament, job, respectiv an al angajării să se afişeze numărul de salariaŃi. De asemenea se va afişa numărul de angajaŃi: - pentru fiecare departament şi job, indiferent de anul angajării; - pentru fiecare departament, indiferent de job şi de anul angajării; - la nivel de companie.

22. Să se afişeze suma alocată pentru plata salariilor pe joburi (codul jobului), în cadrul departamentului (codul departamentului). De asemenea, să se afişeze valoarea totală necesară pentru plata salariilor la nivel de departament, valoarea totală necesară pentru plata salariilor la nivel de job, indiferent de departament şi valoarea totală necesară pentru plata salariilor la nivel de companie.

23. FuncŃia GROUPING(expresie) întoarce: - valoarea 0, dacă expresia a fost utilizată pentru calculul valorii agregat - valoarea 1, dacă expresia nu a fost utilizată.

24. 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); - întreg tabelul.

Page 94: Laborator BD combinat

24

De asemenea, să se afişeze şi o coloană care indică intervenŃia coloanelor department_name şi job_title în obŃinerea rezultatului.

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: GROUP BY GROUPING SETS ((expr_11, expr_12, …, expr_1n), (expr_21, expr_22, …expr_2m),

…)

28. Să se afişeze numele departamentelor, numele job-urilor, codurile managerilor angajaŃilor, maximul şi suma salariilor pentru: - fiecare departament şi, în cadrul său, fiecare job; - fiecare job şi, în cadrul său, pentru fiecare manager; - întreg tabelul.

GROUPING SETS ((department_name, job_title), (job_title, e.manager_id), ());

Limbajul de control al datelor (DCL). COMMIT, SAVEP OINT, ROLLBACK.

• Comanda COMMIT permanentizează modificările care au fost realizate de tranzacŃia curentă (o tranzacŃie este un set de comenzi LMD); comanda suprimă toate punctele intermediare definite în tranzacŃie şi eliberează blocările tranzacŃiei.

ObservaŃie: Sistemul realizează COMMIT implicit:

- la închiderea normală a unui client Oracle (de exemplu SQL*Plus), - după fiecare comandă LDD (CREATE, ALTER, DROP).

• Comanda SAVEPOINT marchează un punct intermediar în procesarea tranzacŃiei. În acest mod este posibilă împărŃirea tranzacŃiei în subtranzacŃii.

Comanda SAVEPOINT are sintaxa:

SAVEPOINT nume_pct_intermediar;

• Comanda ROLLBACK permite renunŃarea la modificările efectuate; aceasta determină încheierea tranzacŃiei, anularea modificărilor asupra datelor şi restaurarea stării lor precedente.

Comanda ROLLBACK are sintaxa:

ROLLBACK [TO SAVEPOINT nume_punct_salvare];

Page 95: Laborator BD combinat

25

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; DELETE FROM dept_***; INSERT INTO dept_*** VALUES (300,’Economic’,100,1000); INSERT INTO dept_*** VALUES (350,’Cercetare’,200,2000); SAVEPOINT b; INSERT INTO dept_*** VALUES (400,’Juritic’,150,3000); SELECT COUNT(*) FROM dept_***; ROLLBACK TO b; SELECT COUNT(*) FROM dept_***; ROLLBACK TO a; INSERT INTO dept_*** VALUES (500,’Contabilitate’,175,1500); COMMIT; SELECT * FROM dept_***; Limbajul de prelucrare a datelor (DML). INSERT, UPDATE, DELETE. 1. Să se creeze tabele emp_*** şi dept_***, având aceeaşi structură şi date ca şi tabelele employees,

respectiv departments.

CREATE TABLE emp_*** AS SELECT * FROM employees; 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. SalvaŃi modificările.

Page 96: Laborator BD combinat

26

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 singure 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;

6. Să se exemplifice câteva dintre 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 definită NOT NULL)

INSERT INTO dept_*** (department_id, location_id) VALUES (200, 2000);

- nepotrivirea listei de coloane cu cea de expresii

INSERT INTO dept_*** VALUES (200, 2000); INSERT INTO dept_*** (department_id, department_nam e,location_id) VALUES (200, 2000);

- nepotrivirea tipului 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. InseraŃ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. 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.

Page 97: Laborator BD combinat

27

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.

12. ŞtergeŃi angajaŃii care nu au comision. AnulaŃi modificările. DELETE FROM emp_*** WHERE commission_pct IS NULL; ROLLBACK; 13. EliminaŃi departamentele care nu au nici un angajat. AnulaŃi modificările. 14. EliminaŃi angajaŃii care nu aparŃin unui departament valid. AnulaŃi modificările. 15. Sintaxa simplificată a comenzii UPDATE:

UPDATE nume_tabel [alias] SET col1 = expr1[, col2=expr2] [WHERE conditie];

sau

UPDATE nume_tabel [alias] SET (col1,col2,...) = (subcerere) [WHERE conditie];

16. MăriŃi salariul tuturor angajaŃilor din tabelul emp_*** cu 5%. AnulaŃi modificările. 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.