Documente Academic
Documente Profesional
Documente Cultură
varsta NUMBER(2)
email CHAR(50)
salariu Valoare implicită 0 NUMBER(9,2)
4. Inserati în tabelul salariat_*** prima înregistrare din tabelul de mai sus fără să precizati lista de coloane
în comanda INSERT.
INSERT INTO salariat VALUES (
1, '.....', '.....', 'director', null ,’' , 30, '.....', 5500 );
5. Inserati a doua înregistrare folosind o listă de coloane din care excludeti data_angajarii si salariul care
au valori implicite. Observati
apoi rezultatul.
1
INSERT INTO salariat (cod_ang, nume, prenume, functia, sef, varsta, email)
VALUES (2, '...', '...', 'functionar', 1, 25, '...' );
6. Inserati înregistrările 3 si 4.
INSERT INTO salariat (cod_ang, nume, prenume, functia, sef, varsta, email, salariu) VALUES (3, '...', '...',
'economist', 1, 45, '...', 3000 );
INSERT INTO salariat (cod_ang, nume, prenume, functia, sef, varsta, email, salariu) VALUES (4, '...', '...',
'functionar', 1, 35, '...', 1000 );
7. Creati tabelul functionar_*** care să contină functionarii din tabelul salariat_***, având următoarele
coloane: codul, numele, salariul anual si data angajării. Verificati cum a fost creat tabelul si ce date contine.
2
DROP TABLE funct;
16. Stergeti si apoi creati din nou tabelul salariat_*** cu următoarea structură.
17. Stergeti tabelul salariat_***, iar apoi recreati-l implementând toate constrângerile la nivel de tabel.
Observatie: Constrângerea de tip NOT NULL se poate declara doar la nivel de coloană.
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;
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 observati? Introduceti înregistrarea dar specificând valoarea NULL pentru coloana sef.
20. Încercati să adăugati o constrângere de cheie externă pe cod_dep din salariat_***. Ce observati?
ALTER TABLE salariat
ADD CONSTRAINT cce2 FOREIGN KEY (cod_dep) REFERENCES departament (cod_dep);
/*EROARE la linia 2: ORA-02298: (SCOTT.CCE2) nu a putut fi validata - nu au fost gasite cheile parinte
21. Inserati o nouă înregistrare în departament_***. Apoi adăugati constrângerea de cheie externă definită
anterior.
22. Inserati noi înregistrări în salariat_***, respectiv în departament_***. Care trebuie să fie ordinea de
inserare?
20 Juridic Constanta
24. Stergeti constrângerea cce2_***. Recreati această constrângere adăugând optiunea 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. Stergeti departamentul 20 din tabelul departament_***. Ce observati în tabelul salariat_***? Anulati
modificările.
DELETE FROM departament
WHERE cod_dep=20;
ROLLBACK;
26. Stergeti constrângerea cce2_***. Recreati această constrângere adăugând optiunea 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;
Definirea vizualizărilor
CREATE [OR REPLACE] [FORCE | NOFORCE] VIEW nume_view [(alias, alias, ..)]
AS subcerere
[WITH CHECK OPTION [CONSTRAINT nume_constr]]
[WITH READ ONLY [CONSTRAINT nume_constr]];
1. Să se creeze vizualizarea v_emp_*** care să contină codul si numele salariatilor din tabelul emp_***. Să
se afiseze continutul acesteia. Să se insereze o nouă înregistrare în această vizualizare. Ce observati? Să se
steargă vizualizarea v_emp_***.
2. Să se creeze vizualizarea v_emp_*** care să contină codul, numele, emailul, data angajării, salariul si
codul jobului salariatilor din tabelul emp_***. Să se analizeze structura si continutul vizualizării. Să se
insereze o nouă înregistrare în această vizualizare. Să se verifice că noua înregistrare a fost inserată si în
tabelul de bază.
3. Să se mărească cu 1000 salariul angajatului având codul 400 din vizualizarea creată anterior. Ce efect va
avea această actiune asupra tabelului de bază?
UPDATE v_emp
SET salary = salary + 1000
WHERE employee_id = 400;
SELECT * FROM v_emp;
SELECT * FROM emp;
/* salariul angajatului cu codul 400 devine 2000, in rest nu se schimba nimic
4. Să se steargă angajatul având codul 400 din vizualizarea creată anterior. Ce efect va avea această
actiune asupra tabelului de bază?
5.a) Să se creeze vizualizarea v_emp_dept_*** care să contină employee_id, last_name, hire_date, job_id,
department_id din tabelul emp_*** si coloana department_name din tabelul dept_***.
Tabelul emp nu are coloana department_id asa ca trebuie creata pentru a putea continua
ALTER TABLE emp
ADD department_id NUMBER(2);
Se creaza vizualizarea
CREATE VIEW v_emp_dept
AS SELECT e.employee_id, e.last_name, e.hire_date, e.job_id, e.department_id, d.department_name
FROM emp e, dept d
WHERE e.department_id =d.department_id;
5.d) Adăugati tabelului emp_*** constrângerea de cheie externă care referă tabelul dept_***, apoi
verificati ce coloane din vizualizarea v_emp_dept_*** sunt actualizabile.
7. a) Să se creeze vizualizarea v_emp30_*** care să contină numele, emailul, data angajării, salariul, codul
jobului si codul departamentului celor care lucrează în departamentul 30. În această vizualizare nu se va
permite modificarea sau inserarea liniilor ce nu sunt accesibile ei. Dati un nume constrângerii.
DESCRIBE v_emp30;
SELECT * FROM v_emp30;
/*nici o inregistrare selectata
UPDATE v_emp30
SET department_id =20
WHERE employee_id = 11;
/*0 înregistrãri actualizate.
8. Să se creeze o vizualizare (v_dept_***) asupra tabelului dept_*** să nu permită efectuarea nici unei
operatii LMD. Testati operatiile de inserare, modificare si stergere asupra acestei vizualizări.
9
9. Să se consulte informatii despre vizualizarea v_dept_***. Folositi vizualizarea dictionarului datelor
USER_VIEWS (coloanele VIEW_NAME si 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 afisate.
Definirea secventelor
10. Să se creeze o secventă care are pasul de incrementare 10 si începe de la 10, are ca valoare maximă
10000 si nu ciclează.
11. Să se modifice toate liniile din tabelul emp_***, regenerând codul angajatilor astfel încât să utilizeze
secventa sec_emp***. Să se anuleze modificările.
UPDATE emp
SET employee_id = sec_emp.NEXTVAL;
ROLLBACK;
12. Să se introducă un nou salariat în tabelul emp_*** folosindu-se pentru codul salariatului secventa
creată.
Exercitiu
a) Creati o secventă pentru generarea codurilor de departamente, seq_dept_***. Secventa va începe de la
200, va creste cu 10 la fiecare pas si va avea valoarea maximă 20000, nu va cicla.
10
CREATE SEQUENCE seq_dept
START WITH 200
INCREMENT BY 10
MAXVALUE 20000
NOCYCLE;
b) Să se selecteze informatii despre secventele utilizatorului curent (nume, valoare minimă, maximă, de
incrementare, ultimul număr generat). Se va utiliza vizualizarea user_sequences.
e) Să se steargă secventa.
Definirea indecsilor
14. Să se creeze un index neunic, emp_last_name_idx_***, asupra coloanei last_name din tabelul emp_***.
15. Să se creeze indecsi unici asupra codului angajatului (employee_id) si asupra combinatiei last_name,
first_name, hire_date.
16. Creati un index neunic asupra coloanei department_id din emp_*** pentru a eficientiza joinurile dintre
acest tabel si dept_***.
Definirea sinonimelor
11
Comanda pentru crearea sinonimelor este:
19. Utilizând sinonimele create anterior, afisati informatii depre salariti si despre departamente.
CERERI MONOTABEL
1. Analizati sintaxa simplificată a comenzii SELECT. Care dintre clauze sunt obligatorii?
12
Se creaza tabelele:
1. REGIONS TABLE
CREATE TABLE regions
( region_id NUMBER
CONSTRAINT region_id_nn NOT NULL ,
region_name VARCHAR2(25) );
2. COUNTRIES TABLE
CREATE TABLE countries
( country_id CHAR(2)
CONSTRAINT country_id_nn NOT NULL
, country_name VARCHAR2(40)
, region_id NUMBER
, CONSTRAINT country_c_id_pk
PRIMARY KEY (country_id) )
ORGANIZATION INDEX;
3. LOCATIONS TABLE
CREATE TABLE locations
( location_id NUMBER(4)
, street_address VARCHAR2(40)
, postal_code VARCHAR2(12)
, city VARCHAR2(30)
CONSTRAINT loc_city_nn NOT NULL
, state_province VARCHAR2(25)
13
, country_id CHAR(2)
);
4. DEPARTAMENTS TABLE
CREATE TABLE departments
( department_id NUMBER(4)
, department_name VARCHAR2(30)
CONSTRAINT dept_name_nn NOT NULL
, manager_id NUMBER(6)
, location_id NUMBER(4)
);
5. JOBS TABLE
CREATE TABLE jobs
( job_id VARCHAR2(10)
, job_title VARCHAR2(35)
CONSTRAINT job_title_nn NOT NULL
, min_salary NUMBER(6)
, max_salary NUMBER(6)
);
6. EMPLOYYES TABLE
CREATE TABLE employees
( employee_id NUMBER(6)
, first_name VARCHAR2(20)
, last_name VARCHAR2(25)
CONSTRAINT emp_last_name_nn NOT NULL
, email VARCHAR2(25)
CONSTRAINT emp_email_nn NOT NULL
, phone_number VARCHAR2(20)
, hire_date DATE
CONSTRAINT emp_hire_date_nn NOT NULL
, job_id VARCHAR2(10)
CONSTRAINT emp_job_nn NOT NULL
, salary NUMBER(8,2)
, commission_pct NUMBER(2,2)
, manager_id NUMBER(6)
, department_id NUMBER(4)
, CONSTRAINT emp_salary_min
CHECK (salary > 0)
, CONSTRAINT emp_email_uk
UNIQUE (email)) ;
7. JOB_HISTORY TABLE
CREATE TABLE job_history
( employee_id NUMBER(6)
CONSTRAINT jhist_employee_nn NOT NULL
, start_date DATE
CONSTRAINT jhist_start_date_nn NOT NULL
, end_date DATE
CONSTRAINT jhist_end_date_nn NOT NULL
, job_id VARCHAR2(10)
CONSTRAINT jhist_job_nn NOT NULL
, department_id NUMBER(4)
, CONSTRAINT jhist_date_interval
CHECK (end_date > start_date) ) ;
14
8. JOB_GRADES TABLE
CREATE TABLE JOB_GRADES
(grade_level VARCHAR2(3),
lowest_sal NUMBER,
highest_sal NUMBER);
DESCRIBE employees;
DESCRIBE departments;
DESCRIBE jobs;
DESCRIBE job_history;
DESCRIBE locations;
DESCRIBE countries;
DESCRIBE regions;
3.Să se listeze continutul tabelelor din schema considerată, afisând valorile tuturor câmpurilor. Obs: Se va
utiliza comanda SQL SELECT * FROM nume_tabel;
Reluam exercitiul
RUN sau /
/* Acelasi rezultat ca la ex. 3
5. Listati structura tabelului EMPLOYEES si apoi dati comanda RUN (sau “/”). Ce observati? Comenzile
SQL*Plus sunt păstrate în buffer?
DESC employees
RUN
/*Comenzile sunt pastrate in buffer.
6. Să se afiseze codul angajatului, numele, codul job-ului, data angajării. Salvati instruciunea SQL într-un
fisier numit p1_14.sql.
Obs: Pentru salvarea ultimei comenzi SQL se utilizează comanda SAVE. Precizarea extensiei „.sql” a
fisierului nu este obligatorie.
SELECT employee_id, last_name, job_id, hire_date
FROM employees;
SAVE z:\…\ p1_14.sql
START E:\Oracle\p1_14.sql;
@ E:\Oracle\p1_14.sql;
8. Editati fisierul p1_14.sql, adăugând coloanelor câte un alias (cod, nume, cod job, data angajarii).
EDIT z:\…\ p1_14.sql
EDIT E:\Oracle\p1_14.sql;
SELECT employee_id cod, last_name nume, job_id "cod job", hire_date "data angajarii"
FROM employees;
10. Să se afiseze numele concatenat cu prenumele, separate prin spatiu. Etichetati coloana “Nume si
prenume”.
Obs: Operatorul de concatenare este “||”. Sirurile de caractere se specifică între apostrofuri (NU ghilimele,
caz în care ar fi interpretate ca alias-uri).
11. Să se listeze numele si salariul angajatilor care câstigă mai mult de 10000 $.
12. Să se modifice cererea anterioară astfel încât să afiseze numele si salariul pentru toti angajatii al căror
salariu este cuprins între 5000$ si10000$.
Obs: Pentru testarea apartenentei la un domeniu de valori se poate utiliza operatorul [NOT] BETWEEN
valoare1 AND valoare2
13. Să se creeze o cerere pentru a afisa numele angajatului si numărul departamentului pentru angajatul
104.
14. Să se afiseze numele si salariul pentru toti angajatii din departamentele 10 sau 30, în ordine alfabetică a
numelor.
Obs: Apartenenta la o multime finită de valori se poate testa prin intermediul operatorului IN, urmat de
lista valorilor între paranteze si 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;
/*afiseaza numai numele salariatilor in ordine alfabetica
Sau
SELECT last_name||' '||first_name "Nume complet", salary
FROM employees
WHERE department_id IN (10,30)
ORDER BY last_name, first_name;
/* afiseaza last_mame si frist_name (numele complet) in ordine alfabetica.
15. Să listeze numele si salariile angajatilor care câstigă mai mult de 10000 $ si lucrează în departamentul
10 sau 30. Se vor eticheta coloanele drept Angajat si Salariu lunar.
50
Element Semnificaie
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.
17. Să se afiseze numele si data angajării pentru fiecare salariat care a fost angajat în 1987. Se cer 2 solutii:
una în care se lucrează cu formatul implicit al datei si alta prin care se formatează data.
19. Să se afiseze numele, salariul si comisionul pentru toti salariatii care câstigă comisioane. Să se sorteze
datele în ordine descrescătoare a salariilor, iar pentru cei care au acelasi salariu în ordine crescătoare a
comisioanelor.
20. Să se listeze numele tuturor angajatilor care au a treia litera din nume 'a'.
51
Obs: Pentru a forma măstile de caractere utilizate împreună cu operatorul LIKE cu scopul de a compara sirurile
de caractere, se utilizează:
% - reprezentând orice sir de caractere, inclusiv sirul vid; _ (underscore) reprezentând un singur caracter.
- numărul lunii din an, numele lunii cu abreviere la 3 caractere, respectiv numele complet al lunii;
SELECT TO_CHAR(SYSDATE,'MM-MON-MONTH') FROM DUAL;
22. Să se listeze numele departamentelor care functionează în locatia având codul 1700 si al căror manager
este cunoscut.
SELECT department_name
FROM departments
WHERE location_id=1700 AND manager_id IS NOT NULL;
Sau
SELECT last_name, first_name
FROM employees
WHERE TO_CHAR (hire_date, 'mm-YYYY') = '05-1987';
25. Să se listeze codurile angajatilor care au avut si alte joburi fată de cel prezent. Să se ordoneze rezultatul
descrescător după codul angajatului.
26. Să se afiseze numele si data angajării pentru cei care lucrează în departamentul 80 si au fost angajati în
luna martie a anului 1997.
27. Să se afiseze numele joburilor care permit un salariu cuprins între 8300$ si 14000$.
52
SELECT DISTINCT j.job_title, s.salary
FROM jobs j, employees s
WHERE j.job_id = s.job_id and salary BETWEEN 8300 AND 14000
ORDER BY salary DESC;
29. Să se listeze numele tuturor angajatilor care au 2 litere 'L' în nume si lucrează în departamentul 30 sau
managerul lor este 123.
30. Să se afiseze numele, job-ul si salariul pentru toti salariatii al căror job contine sirul 'CLERK' sau
'REP' si salariul nu este egal cu 1000, 2000 sau 3000 $.
31. Să se afiseze numele, salariul si comisionul pentru toti angajatii al căror salariu este mai mare decât de
5 ori valoarea comisionului (salary*commission_pct*5).
INITCAP (expresie) - Converteste un sir de caractere la un sir care începe cu majusculă si continuă cu
INITCAP ('AbCdE') = 'Abcde'
INITCAP (expresie) - Converteste un sir de caractere la un sir care începe cu majusculă si continuă cu minuscule.
INITCAP ('AbCdE') = 'Abcde'
53
SUBSTR (expresie, m[, n]) - Extrage din expresia de tip sir de caractere, n caractere începând cu pozitia m. Dacă
lipseste argumentul n, atunci extrage toate caracterele până la sfârsitul sirului. Dacă m este negativ numărătoarea
poziŃiilor începe de la sfârsitul sirului de caractere spre început.
SUBSTR ('AbCdE', 2) = 'bCdE'
SUBSTR ('AbCdE', -3,2) = 'Cd'
SUBSTR ('AbCdE', -3) = 'CdE'
INSTR (expresie, expr1[, m][, n]) - Returnează pozitia la care se găseste 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('AbCdE aBcDe'), 'ab', 5) = 7
INSTR (LOWER('AbC aBcDe'), 'ab', 5, 2) = 0
LTRIM (expresie[, expr1]) sau RTRIM (expresie[, expr1]) - Reversul functiilor LPAD, RPAD. Trunchează
expresia RTRIM (expresie[, expr1]) caracter la stânga sau la dreapta prin eliminarea succesivă a caracterelor din
expresia expr1. Implicit, daca lipseste, expr1 = 'abcde'
RTRIM ('abcdeXXXX', 'X') = 'abcde'
LTRIM (' abcde') = 'abcde'
TRIM (LEADING | TRAILING | BOTH caractere_trim FROM expresie) - Permite eliminarea caracterelor
specificate (caractere_trim) de la începutul (leading) , sfârsitul (trailing) sau din ambele părti, 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 afiseze pentru fiecare angajat din departamentul 20 un sir de caractere de forma "Functia
salariatului {prenume} {nume} este {cod functie}".
Să se afiseze prenumele cu initiala litera mare, iar numele cu litere mari (Stephen KING), iar codul functiei
să se afiseze cu litere mici.
SELECT 'Functia salariatului ' || INITCAP(first_name)||' '||UPPER(last_name) ||' este ' ||LOWER(job_id)||' .' AS
"Angajatul si codul functiei"
FROM employees
WHERE department_id = 20;
3. Să se afiseze pentru angajatul cu numele 'HIGGINS' codul, numele si codul departamentului. Cum se
scrie conditia din WHERE astfel încât să existe siguranta 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.
4. Să se afiseze pentru toti angajatii al căror nume se termină în 'n', codul, numele, lungimea numelui si
pozitia din nume în care apare prima data litera 'a'. Asociati aliasuri coloanelor returnate de cerere.
54
SELECT employee_id, last_name, LENGTH(last_name), INSTR(UPPER(last_name), 'A')
FROM employees
WHERE SUBSTR(last_name,-1)='n';
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
7. Să se afiseze numele, salariul si numărul de mii al salariului rotunjit la 2 zecimale pentru cei care nu au
salariul divizibil cu 1000.
ADD_MONTHS (date, n) - Adaugă n luni la o data specificată. Valoarea n trebuie să fie întreagă (pozitivă sau
negativă).
ADD_MONTHS (date, n)
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 afiseze numele angajatului, data angajării si data negocierii salariului, care a avut loc în prima zi
de Luni, după 6 luni de serviciu. Etichetati această coloană “Negociere”.
NEXT_DAY(ADD_MONTHS(hire_date, 6), ‘Monday’)
14. Pentru fiecare angajat să se afiseze numele si numărul de luni de la data angajării. Etichetati
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
FROM employees
WHERE TO_CHAR(hire_date,'yyyy')=1994;
/* afiseaza o singura coloana cu numele salariatilor care au fost angajati in anul 1994*/
SELECT last_name
56
FROM employees
WHERE hire_date='07-IUN-1994';
/*afiseaza numele salariatilor care au fost angajati in 7 iunie 1994*/
16. Să se afiseze numele si prenumele pentru toti angajatii care s-au angajat în luna mai.
18. Să se afiseze numele angajatilor si comisionul. Dacă un angajat nu câstigă comision, să se scrie “Fara
comision”. Etichetati coloana “Comision”.
NVL(TO_CHAR(commission_pct), ‘Fara comision’)
19. Să se listeze numele, salariul si comisionul tuturor angajatilor al căror venit lunar depăseste 10000$.
salary * NVL(commission_pct, 0) venit_lunar
21. Să se afiseze numele, codul functiei, salariul si o coloana care să arate salariul după mărire. Se stie 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 ceilalti angajati nu se acordă mărire. Să se denumească coloana "Salariu revizuit".
IT_PROG >> 44
ST_CLERK >> 55
SA_REP >> 99
22. Să se afiseze numele salariatului si codul departamentului în care acesta lucrează. Dacă există salariati
care nu au un cod de departament asociat, atunci pe coloana id_depratment să se afiseze: textul “fara
departament”; valoarea zero.
SELECT last_name,
CASE WHEN department_id IS NULL THEN 'Fara departament'
ELSE TO_CHAR(department_id)
END "DEPARTAMENT"
FROM employees;
SELECT last_name,
CASE WHEN department_id IS NULL THEN 0
ELSE department_id
END "DEPARTAMENT"
FROM employees;
sau
SELECT last_name||' '||first_name FROM employees WHERE manager_id IS NULL;
23.b. Să se afiseze numele angajatilor si codul managerilor lor. Pentru angajatii care nu au manager să
apară textul “nu are sef”.
SELECT last_name,
CASE WHEN manager_id IS NULL THEN 'Nu are sef'
ELSE TO_CHAR(manager_id)
END "manager"
FROM employees;
Sau
SELECT last_name||' '||first_name,
CASE WHEN manager_id IS NULL THEN 'Nu are sef'
ELSE TO_CHAR(manager_id)
END "manager"
FROM employees;
Functie
NVL2 (expr1, expr2, expr3)
Explicatie
Dacă expr1 este nenulă atunci returnează expr2, altfel Returnează expr3
Exemplu
NVL2 (1, 2, 3) = 2
NVL2 (NULL, 2, 3) = 3
/*nu am inteles exact ce ar trebui sa facem asa ca am pus sa afiseze si separat pe doua coloane */
SELECT last_name, NVL2(commission_pct, salary+commission_pct, 0) "astia au comision",
NVL2(commission_pct, 0, salary) "astia nu au comision"
FROM employees;
?????????
59
CERERI MULTITABEL, SUBCERERI
Tipuri de join:
- equijoin (se mai numeste inner join sau simple join) - compunerea a două tabele diferite după o conditie ce
contine operatorul de egalitate.
Obs: Numele sau alias-urile tabelelor sunt obligatorii în dreptul coloanelor care au acelasi nume
în mai multe tabele.
- nonequijoin - compunerea a două relatii tabele după o conditie oarecare, ce NU contine operatorul de egalitate.
- outerjoin - compunerea externă a două tabele diferite completând una dintre relatii cu valori NULL acolo unde
nu există în aceasta nici un tuplu ce îndeplineste conditia de corelare. Relatia completată cu valori NULL este cea
în dreptul căreia apare “(+)”. Operatorul (+) poate fi plasat în orice parte a conditiei de join, dar nu în ambele
părti. Full outer join = Left outer join UNION Right outer join.
2. Să se afiseze numele angajatului, numele departamentului pentru toti angajatii care câstigă comision.
SELECT last_name, department_name
FROM employees e, departments d
WHERE e.department_id = d.department_id
AND commission_pct IS NOT NULL;
3. Să se listeze numele job-urile care există în departamentul 30.
4. Sa se afiseze numele, job-ul si numele departamentului pentru tot angajati care lucrează în Seattle.
60
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’;
Sau
5. Să se afiseze numele, salariul, data angajării si numele departamentului pentru toti programatorii care
lucrează în America.
region_name = ‘Americas’
job_title = ‘Programmer’
7. Să se afiseze numele departamentelor si numele salariatilor care lucrează în ele. Se vor afisa si
departamentele care nu au salariati (left outher join).
9. Să se afiseze codul angajatului si numele acestuia, împreună cu numele si codul sefului său direct. Se vor
eticheta coloanele Ang#, Angajat, Mgr#, Manager. Să se salveze instrucsiunea într-un fisier numit p3_9.sql.
10. Să se modifice p3_9.sql pentru a afisa toti salariatii, inclusiv pe cei care nu au sef.
11. Să se afiseze numele salariatului si data angajării împreună cu numele si data angajării sefului direct
pentru salariatii care au fost angajati înaintea sefilor lor. Se vor eticheta coloanele Angajat, Data_ang,
Manager si Data_mgr.
12. Pentru fiecare angajat din departamentele 20 si 30 să afiseze numele, codul departamentului si toti
colegii săi (salariatii care lucrează în acelasi 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 afiseze numele si data angajării pentru salariatii care au fost angajati după 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. Scrieti o cerere pentru a afisa numele si salariul pentru toti colegii (din acelasi departament) lui Fay. Se
va exclude Fay.
62
15. Să se afiseze codul departamentului, codul si numele angajatilor care lucrează în acelasi departament
cu cel putin un angajat al cărui nume contine litera “T”. Să se ordoneze după codul departamentului.
18. Să se afiseze numele angajatilor, numărul departamentului si job-ul tuturor salariatilor al căror
departament este localizat în Seattle.
19. Să se afle dacă există angajati care nu lucrează în departamentul ‘Sales’ si al căror salariu si comision
coincid cu salariul si comisionul unui angajat din departamentul ‘Sales’.
20. Scrieti o cerere pentru a afisa numele, numele departamentului si salariul angajatilor care nu câstigă
comision, dar al căror manager coincide cu managerul unui angajat care câstigă comision.
63
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. Scrieti o cerere pentru a afisa angajatii care câstigă mai mult decât oricare functionar. Sortati
rezultatele după salariu, în ordine descrescătoare.
22. Să se afiseze codul, numele si salariul tuturor angajatilor care câstigă mai mult decât salariul mediu.
SELECT employee_id, last_name, salary
FROM employees
WHERE salary > (SELECT AVG(salary)
FROM employees);
23. Să se afiseze pentru fiecare salariat angajat în luna martie numele său, data angajării si numele jobului.
24. Să se afiseze pentru fiecare salariat al cărui câstig total lunar este mai mare decât 12000, numele său,
câstigul total lunar si numele departamentului în care lucrează.
25. Să se afiseze pentru fiecare angajat codul său si numele joburilor sale anterioare, precum si intervalul
de timp în care a lucrat pe jobul respectiv.??
SELECT employee_id, job_id, start_date "data angaj job anterior",end_date"data final job anterior",
ROUND(MONTHS_BETWEEN(end_date, start_date)) "interval angajare"
FROM Job_history;
/* Nu stiu daca este bine
26. Să se modifice cererea de la punctul 25 astfel încât să se afiseze si numele angajatului, respectiv codul
jobului său curent.
27. Să se modifice cererea de la punctul 26 astfel încât să se afiseze si numele jobului său curent.
SELECT last_name, e.job_id, job_title, hire_date "data angajarii", SYSDATE "data curenta",
ROUND(MONTHS_BETWEEN(SYSDATE, hire_date))||' ' ||'luni' "Vechime in firma"
FROM employees e, jobs j
WHERE e.job_id = j.job_id;
28. Să se afiseze salariatii care au acelasi manager ca si angajatul având codul 140.
Aceste tipuri de functii pot fi utilizate pentru a returna informatia corespunzătoare fiecăruia dintre
grupurile obtinute în urma divizării liniilor tabelului cu ajutorul clauzei GROUP BY.
Pot apărea în clauzele SELECT, ORDER BY si HAVING.
Server-ul Oracle aplică aceste functii fiecărui grup de linii si returnează un singur rezultat pentru fiecare
multime.
Exemple de functii grup: AVG, SUM, MAX, MIN, COUNT etc.
Tipurile de date ale argumentelor functiilor grup pot fi CHAR, VARCHAR2, NUMBER sau DATE.
Functiile AVG si SUM, operează numai asupra valorilor numerice. Functiile MAX si MIN pot opera
asupra valorilor numerice, caracter sau dată calendaristică.
Toate functiile grup, cu exceptia 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 si nu întoarce niciodată valoarea null.
Când este utilizată clauza GROUP BY, server-ul sortează implicit multimea rezultată în
ordinea crescătoare a valorilor coloanelor după care se realizează gruparea.
Absenta 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 functiilor grup.
1. Să se afiseze cel mai mare salariu, cel mai mic salariu, suma si media salariilor tuturor angajatilor.
Etichetati coloanele Maxim, Minim, Suma, respectiv Media. Să se rotunjească rezultatele.
65
SELECT MIN(salary) min, MAX(salary) max, SUM(salary) suma,
ROUND(AVG(salary)) media
FROM employees;
c. numărul de manageri.
SELECT COUNT(*) "Numar manageri" FROM employees WHERE manager_id IS NULL;
3. Să se afiseze diferenta dintre cel mai mare si cel mai mic salariu. Etichetati coloana “Diferenta”.
6. Să se selecteze valoarea medie si suma salariilor pentru toti angajatii care sunt reprezentanti de vânzări
(SA_MAN, SA_REP).
10. Să se afiseze codul departamentului si media salariilor pentru fiecare job din cadrul acestuia.
11. a. Să se afiseze codul departamentelor pentru care salariul minim depăseste 5000$.
11.b. Să se modifice cererea anterioară astfel încât să se afiseze si orasul în care functionează aceste
departamente.
12. Să se obtină codul departamentelor si numărul de angajati al acestora pentru departamentele care au
cel putin 10 angajati.
13. Să se obtină codul departamentelor si suma salariilor angajatilor care lucrează în acestea, în ordine
descrescătoare după sumă. Se consideră angajatii care au comision si departamentele care au mai mult de 5
angajati.
SELECT job_id
FROM employees
GROUP BY job_id
HAVING AVG(salary) = (SELECT MIN(AVG(salary))
FROM employees
GROUP BY job_id);
SELECT AVG(salary)
FROM employees
GROUP BY department_id
HAVING AVG(salary) = (SELECT MAX(AVG(salary)) FROM employees GROUP BY department_id);
17. a. Scrieti o cerere pentru a afisa numele departamentului, numărul de angajati si salariul mediu pentru
angajatii din acel departament. Coloanele vor fi etichetate Departament, Nr. angajati, Salariu Mediu.
18. Să se creeze o cerere prin care să se afiseze numărul total de angajati si, din acest total, numărul celor
care au fost angajati în 1997, 1998, 1999 si 2000. Datele vor fi afisate în forma următoare:
SUM(DECODE(TO_CHAR(hire_date,'yyyy'),1997,1,0))
/*afiseaza
68
Operatorii ROLLUP si CUBE
Clauza GROUP BY permite gruparea liniilor selectate după valorile expresiilor precizate în aceasta.
Pentru fiecare grup, va fi returnată o singură linie de informatie. 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 specificatia
GROUP BY si returnează o singură linie pentru fiecare grup.
- 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ă functia 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
obisnuite, 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 absentei clauzei GROUP BY si deci, calculului funcŃiilor
grup din cerere pentru întreg tabelul.
CUBE grupează liniile selectate pe baza valorilor tuturor combinatiilor posibile ale expresiilor specificate
si returnează câte o linie totalizatoare pentru fiecare grup. Acest operator este folosit pentru a produce multimi de
rezultate care sunt utilizate în rapoarte. În vreme ce ROLLUP produce subtotalurile doar pentru o parte dintre
combinatiile posibile, operatorul CUBE produce subtotaluri pentru toate combinatiile posibile de grupări
specificate în clauza GROUP BY, precum si un total general.
Dacă există n coloane sau expresii în clauza GROUP BY, vor exista 2n combinatii posibile superagregat.
19. Să se afiseze codurile departamentelor în care lucrează cel putin un angajat, iar pentru fiecare dintre
acestea si pentru fiecare manager care lucrează în departamentul respectiv să se afiseze numărul de
salariati. De asemenea, să se afiseze numărul de salariati pentru fiecare departament indiferent de manager
si numărul total de angajati din companie.
20. Să se afiseze codurile departamentelor în care lucrează cel putin un angajat, iar pentru fiecare dintre
acestea si pentru fiecare manager care lucrează în departamentul respectiv să se afiseze numărul de
salariati. De asemenea, să se afiseze numărul de salariati pentru fiecare departament indiferent de
manager, numărul de angajati subordonati unui manager indiferent de departament si numărul total de
angajati din companie.
21. Pentru fiecare departament, job, respectiv an al angajării să se afiseze numărul de salariati. De
asemenea se va afisa numărul de angajati:
- pentru fiecare departament si job, indiferent de anul angajării;
69
- pentru fiecare departament, indiferent de job si de anul angajării;
- la nivel de companie.
Exemplu:
Să se afiseze valoarea totală a operelor de artă ale unui autor, expuse în cadrul fiecărei galerii având codul mai
mic decât 50. De asemenea, să se afiseze valoarea totală a operelor din fiecare galerie având codul mai mic decât
50, valoarea totală a operelor fiecărui autor indiferent de galerie si valoarea totală a operelor din galeriile având
codul mai mic decât 50.
22. Să se afiseze suma alocată pentru plata salariilor pe joburi (codul jobului), în cadrul departamentului
(codul departamentului). De asemenea, să se afiseze valoarea totală necesară pentru plata salariilor la nivel
de departament, valoarea totală necesară pentru plata salariilor la nivel de job, indiferent de departament
si valoarea totală necesară pentru plata salariilor la nivel de companie.
24. Să se afiseze numele departamentelor, titlurile job-urilor si valoarea medie a salariilor, pentru:
- fiecare departament si, în cadrul său pentru fiecare job;
- fiecare departament (indiferent de job);
- întreg tabelul.
De asemenea, să se afiseze si o coloană care indică intervenŃia coloanelor department_name si job_title în
obtinerea rezultatului.
25. Modificati cererea anterioară astfel încât să se afiseze numele departamentelor, titlurile job-urilor si
valoarea medie a salariilor, pentru:
- fiecare departament si, în cadrul său pentru fiecare job;
- fiecare departament (indiferent de job);
- fiecare job(indiferent de departament);
- întreg tabelul.
Cum intervin coloanele în obtinerea rezultatului? Să se afiseze ’Dept’, dacă departamentul a intervenit în
agregare si ‘Job’, dacă job-ul a intervenit în agregare.
DECODE(GROUPING(department_name), 0, ‘Dept’)
/*Cererea de la pct.20*/
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);
/* 54 de inregistrari selectate*/
27. Clauza GROUPING SETS. Permite obtinerea 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 afiseze numele departamentelor, numele job-urilor, codurile managerilor angajatilor, maximul si
suma salariilor pentru:
- fiecare departament si, în cadrul său, fiecare job;
- fiecare job si, în cadrul său, pentru fiecare manager;
- întreg tabelul.
GROUPING SETS ((department_name, job_title), (job_title, e.manager_id), ());
· Comanda COMMIT permanentizează modificările care au fost realizate de tranzactia curentă (o tranzactie este
un set de comenzi LMD); comanda suprimă toate punctele intermediare definite în tranzactie si eliberează
blocările tranzactiei.
Observatie:
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 tranzactiei. În acest mod este posibilă
împărtirea tranzactiei în subtranzactii.
71
Comanda SAVEPOINT are sintaxa:
SAVEPOINT nume_pct_intermediar;
· Comanda ROLLBACK permite renuntarea la modificările efectuate; aceasta determină încheierea tranzactiei,
anularea modificărilor asupra datelor si restaurarea stării lor precedente.
Observatii:
- sistemul realizează ROLLBACK implicit dacă se închide anormal (defectiune hardware sau software, pană de
curent etc.);
- nici o comanda LDD (CREATE, ALTER; DROP) nu poate fi anulată.
1. Să se creeze tabele emp_*** si dept_***, având aceeasi structură si date ca si tabelele employees,
respectiv departments.
CREATE TABLE emp AS SELECT * FROM employees;
CREATE TABLE dept AS SELECT * FROM departments;
3.Stergeti toate înregistrările din cele 2 tabele create anterior. Salvati modificările.
DESCRIBE employees;
DESCRIBE emp;
/*Au aceeasi structura.*/
6. Să se exemplifice câteva dintre erorile care pot să apară la inserare si 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);
*/EROARE la linia 1: ORA-01400: nu poate fi inserat NULL în ("SCOTT"."DEPT3"."DEPARTMENT_NAME")*/
9. Să se creeze tabelul emp0_*** cu aceeasi structură ca tabelul employees. Inserati, utilizând o singură
comandă INSERT, informatii din tabelul employees:
- în tabelul emp0_*** salariatii care lucrează în departamentul 80;
- în tabelul emp1_*** salariatii care au salariul mai mic decât 6000 (care nu se regăsesc în tabelul
emp0_***);
- în tabelul emp2_*** salariatii care au salariul cuprins între 6000 si 10000 (care nu se regăsesc în
tabelele emp0_*** si emp1_***);
- în tabelul emp3_*** salariatii care au salariul mai mare decât 10000 (care nu se regăsesc în tabelele
emp0_***, emp1_*** si emp2_***).
Obs.
Clauza FIRST a comenzii INSERT determină inserarea corespunzătoare primei clauze WHEN a cărei
conditie este evaluată TRUE. Toate celelalte clauze WHEN sunt ignorate.
11. Stergeti toate înregistrările din tabelele emp_*** si dept_***. Inserati în aceste tabele toate înregistrările
corespunzătoare din employees, respectiv departments. Permanentizati tranzactia.
14. Eliminati angajatii care nu apartin unui departament valid. Anulati modificările.
16. Măriti salariul tuturor angajatilor din tabelul emp_*** cu 5%. Anulati modificările.
75
UPDATE emp
SET salary = salary * 1.05;
ROLLBACK;
17. Schimbati jobul tuturor salariatilor din departamentul 80 care au comision în 'SA_REP'. Anulati
modificările.
UPDATE emp
SET job_id = 'SA_REP'
WHERE department_id=80 AND commission_pct IS NOT NULL;
ROLLBACK;
UPDATE emp
SET job_id = 99
WHERE department_id=80 AND commission IS NOT NULL;
ROLLBACK;
18. Să se modifice jobul si departamentul angajatului având codul 114, astfel încât să fie la fel cu cele ale
angajatului având codul 205.
UPDATE emp
SET (job_id, department_id) = (SELECT job_id, department_id
FROM emp
WHERE employee_id = 205)
WHERE employee_id = 114;
ROLLBACK;
19. Schimbati salariul si 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.
UPDATE emp e
SET salary = (SELECT AVG(salary)
FROM emp)
WHERE hire_date = (SELECT MIN(hire_date)
FROM emp
WHERE department_id=e.department_id);
ROLLBACK;
21. Să se modifice valoarea emailului pentru angajatii care câstigă cel mai mult în departamentul în care
lucrează astfel încât acesta să devină initiala numelui concatenată cu prenumele. Dacă nu are prenume
atunci în loc de acesta apare caracterul ‘.’. Anulati modificările.
UPDATE emp
SET email = LOWER(SUBSTR(first_name,1,1)) || LOWER(NVL(last_name, '. '))
76
WHERE (department_id, salary) IN (SELECT department_id, MAX(salary)
FROM emp
GROUP BY department_id);
ROLLBACK;
77