Sunteți pe pagina 1din 9

Laborator 6 PL/SQL Declanatori

Un declanator este un bloc PL/SQL care se execut automat ori de cte ori are loc un anumit eveniment declanator (de exemplu, inserarea unei linii ntr-un tabel, tergerea unor nregistrri etc.) Tipuri de declanatori: la nivel de baz de date se declaneaz la un eveniment legat de date ( LMD) sau de sistem (logon, shutdown); la nivel de aplicaie se declaneaz la apariia unui eveniment legat de o aplicaie particular. Sintaxa comenzii de creare a unui declanator este urmtoarea: CREATE [OR REPLACE] TRIGGER [schema.]nume_declanator {BEFORE | AFTER} [INSTEAD OF] {DELETE | INSERT | UPDATE [OF coloana[, coloana ] ] } [OR {DELETE | INSERT | UPDATE [OF coloana[, coloana ] ] } ON [schema.]nume_tabel [REFERENCING {OLD [AS] vechi NEW [AS] nou | NEW [AS] nou OLD [AS] vechi } ] [FOR EACH ROW] [WHEN (condiie) ] corp_declanator; Observaie: Informaii despre declanatori se pot obine interognd vizualizrile USER_TRIGGERS, USER_TRIGGER_COL, ALL_TRIGGERS, DBA_TRIGGERS. nainte de a scrie codul PL/SQL, trebuie s stabilim: - momentul cnd este executat trigger-ul: BEFORE, AFTER, INSTEAD OF - ce fel de aciuni l declaneaz: INSERT, UPDATE, DELETE - tipul trigger-ului (de cate ori se execut): la nivel de instruciune sau la nivel de linie ( FOR EACH ROW). Dezactivarea, respectiv activarea declanatorilor se realizeaz prin urmtoarele comenzi: ALTER TABLE nume_tabel DISABLE ALL TRIGGERS; ALTER TABLE nume_tabel ENABLE ALL TRIGGERS; ALTER TRIGGER nume_trig ENABLE; ALTER TRIGGER nume_trig DISABLE; Eliminarea unui declanator se face prin DROP TRIGGER nume_trig; 1. S se creeze un declanator la nivel de instruciune care s permit lucrul asupra tabelului emp_*** (INSERT, UPDATE, DELETE) dect n intervalul de ore 8:00 - 20:00, de luni pn smbt. CREATE OR REPLACE TRIGGER trig1_*** BEFORE INSERT OR UPDATE OR DELETE ON emp_*** BEGIN IF (TO_CHAR(SYSDATE,'D') = 1) OR (TO_CHAR(SYSDATE,'HH24') NOT BETWEEN 8 AND 20)

THEN RAISE_APPLICATION_ERROR (-20001, 'tabelul emp_*** nu poate fi reactualizat'); -- numarul erorii trebuie cuprins intre -20999si -20000 END IF; END; / DROP TRIGGER trig1_***; 2. S se creeze un declanator la nivel de linie (FOR EACH ROW) prin care s nu se permit micorarea salariilor angajailor din tabelul emp_***. Varianta 1 CREATE OR REPLACE TRIGGER trig2_*** BEFORE UPDATE OF salary ON emp_*** FOR EACH ROW BEGIN IF (:NEW.salary < :OLD.salary) THEN RAISE_APPLICATION_ERROR (-20002, 'salariul nu poate fi micsorat'); END IF; END; / UPDATE emp_*** SET salary=salary-100; DROP TRIGGER trig2_***; Varianta 2 CREATE OR REPLACE TRIGGER trig2_*** BEFORE UPDATE OF salary ON emp_*** FOR EACH ROW WHEN (NEW.salary < OLD.salary) BEGIN RAISE_APPLICATION_ERROR (-20002, 'salariul nu poate fi micsorat'); END; / UPDATE emp_*** SET salary=salary-100; DROP TRIGGER trig2_***; 3. S se creeze un declanator la nivel de linie care s nu permit modificarea valorii lowest_sal (mrirea) a grilei de salarizare 1, respectiv modificarea valorii highest_sal (micorarea) a grilei de salarizare 7 dect dac toate salariile se gsesc n intervalul dat de aceste dou valori modificate (lowest_sal_marit highest_sal_micsorat). Se va utiliza tabelul job_grades_*** care va fi creat dup tabelul job_grades. CREATE OR REPLACE TRIGGER trig3_*** BEFORE UPDATE OF lowest_sal, highest_sal ON job_grades_*** FOR EACH ROW DECLARE v_min_sal emp_***.salary%TYPE; v_max_sal emp_***.salary%TYPE; exceptie EXCEPTION;

BEGIN SELECT MIN(salary), MAX(salary) INTO v_min_sal,v_max_sal FROM emp_***; IF (:OLD.grade_level=1) AND (v_min_sal< :NEW.lowest_sal) THEN RAISE exceptie; END IF; IF (:OLD.grade_level=7) AND (v_max_sal> :NEW.highest_sal) THEN RAISE exceptie; END IF; EXCEPTION WHEN exceptie THEN RAISE_APPLICATION_ERROR (-20003, 'Exista salarii care se gasesc in afara intervalului'); END; / UPDATE job_grades_*** SET lowest_sal =3000 WHERE grade_level=1; UPDATE job_grades_*** SET highest_sal =20000 WHERE grade_level=7; DROP TRIGGER trig3_***; 4. S se introduc n tabelul dept_*** un nou cmp (pli) care s reprezinte pentru fiecare departament suma alocat pentru plata salariilor angajailor care lucreaz n departamentul respectiv. S se actualizeze cmpul nou creat. S se creeze un declanator care va actualiza automat cmpul pli atunci cnd se introduce un nou salariat, respectiv se terge un salariat sau se modific salariul unui angajat. ALTER TABLE dept_*** ADD (plati NUMBER(10)); UPDATE dept_*** SET plati = (SELECT SUM(salary) FROM emp_*** WHERE emp_***.department_id=dept_***.department_id); SELECT * FROM dept_***; CREATE OR REPLACE PROCEDURE modific_plati_*** (v_codd dept_***.department_id %TYPE, v_plati dept_***.plati%TYPE) AS BEGIN UPDATE dept_*** SET plati = NVL (plati, 0) + v_plati WHERE department_id = v_codd; END; / CREATE OR REPLACE TRIGGER trig4_*** AFTER DELETE OR UPDATE OR INSERT OF salary ON emp_*** FOR EACH ROW BEGIN IF DELETING THEN -- se sterge un angajat

modific_plati_*** (:OLD.department_id, -1*:OLD.salary); ELSIF UPDATING THEN --se modifica salariul unui angajat modific_plati_*** (:NEW.department_id, :NEW.salary - :OLD.salary); ELSE -- se introduce un nou angajat modific_plati_*** (:NEW.department_id, :NEW.salary); END IF; END; / SELECT salary FROM emp_*** WHERE employee_id=100; SELECT * FROM dept_*** WHERE department_id=90; DELETE FROM emp_*** WHERE employee_id=100; -- lucreaza in departamentul 90 SELECT * FROM dept_*** WHERE department_id=90; ROLLBACK; UPDATE emp_*** SET salary=salary - 1000 WHERE employee_id=100; SELECT * FROM dept_*** WHERE department_id=90; ROLLBACK; INSERT INTO emp_*** (employee_id, last_name, email, hire_date, job_id, salary, department_id) VALUES (300, 'Alec', 'alec@g.com',sysdate, 'SA_REP', 5000, 90); SELECT * FROM dept_*** WHERE department_id=90; ROLLBACK; DROP TRIGGER trig4_***; 5. S se creeze o vizualizare care s conin date despre fiecare salariat (employee_id, last_name, email, hire_date, job_id, salary, department_id) i departamentul n care lucreaz acesta (department_id, department_name, plati). S se defineasc un declanator (declanator INSTEAD OF) prin care reactualizrile ce au loc asupra vizualizrii se propag automat n tabelele de baz. CREATE OR REPLACE VIEW v_join_*** AS SELECT employee_id, last_name, email, hire_date, job_id, salary, e.department_id, department_name, plati FROM emp_*** e, dept_*** d WHERE e.department_id = d.department_id; SELECT column_name, updatable

FROM user_updatable_columns WHERE table_name = UPPER('v_join_***'); CREATE OR REPLACE TRIGGER trig5_*** INSTEAD OF INSERT OR DELETE OR UPDATE ON v_join_*** FOR EACH ROW BEGIN IF INSERTING THEN -- inserarea in vizualizare determina inserarea in emp_*** si reactualizarea in dept_*** INSERT INTO dept_***(department_id, department_name, plati) VALUES (:NEW.department_id, :NEW.department_name, :NEW.salary); INSERT INTO emp_*** (employee_id, last_name, email, hire_date, job_id, salary, department_id) VALUES (:NEW.employee_id, :NEW.last_name, :NEW.email, :NEW.hire_date, :NEW.job_id, :NEW.salary, :NEW.department_id); ELSIF DELETING THEN -- stergerea unui salariat din vizualizare determina stergerea din emp_*** si reactualizarea in dept_*** DELETE FROM emp_*** WHERE department_id = :OLD.department_id; UPDATE dept_*** SET plati = plati - :OLD.salary WHERE department_id = :OLD.department_id; ELSIF UPDATING ('salary') THEN /* modificarea unui salariu din vizualizare determina modificarea salariului in emp_*** si reactualizarea in dept_*** */ UPDATE emp_*** SET salary = :NEW.salary WHERE employee_id = :OLD.employee_id; UPDATE dept_*** SET plati = plati - :OLD.salary + :NEW.salary WHERE department_id = :OLD.department_id; ELSIF UPDATING ('department_id') THEN /* modificarea unui cod de departament din vizualizare determina modificarea codului in salariat si reactualizarea in departament */ UPDATE emp_*** SET department_id = :NEW.department_id WHERE employee_id = :OLD.employee_id; UPDATE dept_*** SET plati = plati - :OLD.salary WHERE department_id = :OLD.department_id; UPDATE dept_*** SET plati = plati + :NEW.salary WHERE department_id = :NEW.department_id; END IF; END; / SELECT column_name, updatable FROM user_updatable_columns WHERE table_name = UPPER('v_join_***');

--inserarea in vizualizare INSERT INTO v_join_*** (employee_id, last_name, email, hire_date, job_id, salary, department_id, department_name) VALUES ( 400, 'YYY', 'YYY',SYSDATE, 'YYY', 3000,99,'dept nou'); SELECT last_name, email, hire_date, job_id, salary, department_id FROM emp_*** WHERE employee_id=400; SELECT * FROM dept_*** WHERE department_id=99; ROLLBACK; -- stergerea din vizualizare SELECT * FROM dept_*** WHERE department_id =10; DELETE FROM v_join_*** WHERE employee_id=200; SELECT last_name, email, hire_date, job_id, salary, department_id FROM emp_*** WHERE employee_id=200; SELECT * FROM dept_*** WHERE department_id=10; ROLLBACK; -- modificarea salariului unui angajat SELECT last_name, email, hire_date, job_id, salary, department_id FROM emp_*** WHERE employee_id=100; SELECT * FROM dept_*** WHERE department_id=90; UPDATE v_join_*** SET salary=salary + 1000 WHERE employee_id=100; SELECT employee_id, last_name, email, hire_date, job_id, salary, department_id FROM emp_*** WHERE employee_id=100; SELECT * FROM dept_*** WHERE department_id=90; ROLLBACK; --modificarea departamentului unui angajat SELECT * FROM dept_***

WHERE department_id IN (10,90); UPDATE v_join_*** SET department_id=10 WHERE employee_id=100; SELECT last_name, email, hire_date, job_id, salary, department_id FROM emp_*** WHERE employee_id=100; SELECT * FROM dept_*** WHERE department_id IN (10,90); ROLLBACK; DROP TRIGGER trig5_***; 6. S creeze un declanator prin care s nu se permit tergerea informaiilor din tabelul emp_*** de ctre utilizatorul curent (declanator la nivel de baz de date). CREATE OR REPLACE TRIGGER trig6_*** BEFORE DELETE ON emp_*** BEGIN IF USER= UPPER('g233') THEN RAISE_APPLICATION_ERROR(-20900,'Nu ai voie sa stergi!'); END IF; END; / DROP TRIGGER trig6_***; 7. S se creeze un tabel ce conine urmtoarele cmpuri: user_id, nume_bd, eveniment_sis, nume_obj, data. Apoi, s se creeze un declanator sistem (la nivel de schem) care s introduc date n acest tabel dup ce utilizatorul a folosit o comand LDD. Obs. Sintaxa pentru crearea unui declanator sistem este urmtoarea CREATE [OR REPLACE] TRIGGER [schema.]nume_declanator {BEFORE | AFTER} {lista_evenimente_LDD | lista_evenimente_baz} ON {DATABASE | SCHEMA} [WHEN (condiie) ] corp_declanator; lista_evenimente_LDD - CREATE, DROP, ALTER) lista_evenimente_baz - STARTUP, SHUTDOWN, LOGON, LOGOFF, SERVERERROR, SUSPEND) CREATE TABLE info_*** (user_id VARCHAR2(30), nume_bd VARCHAR2(50), eveniment_sis VARCHAR2(20), nume_obj VARCHAR2(30), data DATE); CREATE OR REPLACE TRIGGER trig7_*** AFTER CREATE OR DROP OR ALTER ON SCHEMA BEGIN INSERT INTO info_***

VALUES (SYS.LOGIN_USER, SYS.DATABASE_NAME, SYS.SYSEVENT, SYS.DICTIONARY_OBJ_NAME, SYSDATE); END; / CREATE INDEX ind_*** ON salariat_***(nume); DROP INDEX ind_***; SELECT * FROM info_***; DROP TRIGGER trig7_***; 8. S se creeze un declanator (la nivel de linie) care s nu permit modificarea: - valorii salariului maxim astfel nct acesta s devin mai mic dect media tuturor salariilor; - valorii salariului minim astfel nct acesta s devin mai mare dect media tuturor salariilor. Observaie: n acest caz este necesar meninerea unor variabile n care s se rein salariul minim, salariul maxim, respectiv media salariilor. Variabilele se definesc ntr-un pachet, iar apoi pot fi referite n declanator prin nume_pachet.nume_variabila. Este necesar s se defineasc doi declanatori: - un declanator n carea s se utilizeze o comand SELECT ... INTO pentru a menine valorile actuale corespunztoare acestor variabile. - un declanator n care s se realizeze verificarea. CREATE OR REPLACE PACKAGE pachet_*** AS smin emp_***.salary%type; smax emp_***.salary%type; smed emp_***.salary%type; END pachet_***; / CREATE OR REPLACE TRIGGER trig81_*** BEFORE UPDATE OF salary ON emp_*** BEGIN SELECT MIN(salary),AVG(salary),MAX(salary) INTO pachet_***.smin, pachet_***.smed, pachet_***.smax FROM emp_***; END; / CREATE OR REPLACE TRIGGER trig82_*** BEFORE UPDATE OF salary ON emp_*** FOR EACH ROW BEGIN IF(:OLD.salary=pachet_***.smin) AND (:NEW.salary>pachet_***.smed) THEN RAISE_APPLICATION_ERROR(-20001,'Acest salariu depaseste valoarea medie'); ELSIF (:OLD.salary= pachet_***.smax) AND (:NEW.salary< pachet_***.smed) THEN RAISE_APPLICATION_ERROR(-20001,'Acest salariu este sub valoarea medie'); END IF; END; / SELECT AVG(salary) FROM emp_***;

UPDATE emp_*** SET salary=10000 WHERE salary=(SELECT MIN(salary) FROM emp_***); UPDATE emp_*** SET salary=1000 WHERE salary=(SELECT MAX(salary) FROM emp_***); DROP TRIGGER trig81_***; DROP TRIGGER trig82_***;

EXERCIII
1. S se creeze un declanator (la nivel de instruciune) care s permit tergerea liniilor din tabelul dept_*** dect n dac utilizatorul este SCOTT. 2. S se creeze un declanator (la nivel de linie) prin care s nu se permit mrirea comisionului astfel nct s depeasc 50% din valoarea salariului. 3. S se introduc n tabelul departament un nou cmp (numar) care s reprezinte pentru fiecare departament numrul de angajai care lucreaz n departamentul respectiv. S se actualizeze cmpul nou creat. S se creeze un declanator care va actualiza automat cmpul numar atunci cnd se introduce un nou salariat, respectiv se terge un salariat sau se modific numrul de departament al unui angajat. 4. S se creeze un declanator cu ajutorul cruia s se implementeze restricia conform creia ntr-un departament nu pot lucra mai mult de 45 persoane. 5. S se creeze un declanator care va determina tergeri i modificri n cascad: - tergerea angajailor dintr-un departament dac acesta este eliminat din tabelul dept_***; - modificarea codului de departament pentru angajaii care lucreaz n cadrul acestuia dac departamentul respectiv este modificat n tabelul dept_***. 6. S se creeze un tabel ce conine urmtoarele cmpuri: user_id (SYS.LOGIN_USER), nume_bd (SYS.DATABASE_NAME), erori (DBMS_UTILITY.FORMAT_ERROR_STACK), data. Apoi, s se creeze un declanator sistem (la nivel de baz de date) care s introduc date n acest tabel referitoare la erorile aprute.

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