Sunteți pe pagina 1din 270

BAZE DE DATE AVANSATE

LIMBAJUL PL/SQL
Suport pentru SQL Suport pentru programarea orientata obiect Performanta buna Portabilitate Productivitate mare Integrarea cu Oracle
2

Limbajul PL/SQL- Tabele


CREATE TABLE dept(deptno NUMBER(2) NOT NULL, dname VARCHAR2(14),loc VARCHAR2(13)) CREATE TABLE emp(empno NUMBER(4) NOT NULL,ename VARCHAR2(10),job VARCHAR2(9),mgr NUMBER(4),hiredate DATE,sal NUMBER(7,2),comm NUMBER(7,2),deptno NUMBER(2))
3

Limbajul PL/SQL- Elemente de baz


Caractere de baz: A..Z, a..z 0..9 tab, space, CR Simboli)+-*/<>=!~;:.@%,#$&_{}?[] Nu este case senzitive
4

Limbajul PL/SQL- Elemente de baz


Unitati lexicale: - delimitatori - identificatori - literali - comentarii Unitatile lexicale sunt separate prin spatii
5

Limbajul PL/SQL- Elemente de baz


Delimitatori: simboli simpli: +,*,%,etc. simboli compusi: **, <>,!=,~=,<=,>=,:=,=> .., ||,<<,>>,--,?*,*/ Identificatori: Formati din litere, numerale, $, _,semne numerice
6

Limbajul PL/SQL- Elemente de baz


Cuvinte rezervate: DECLARE, BEGIN , END, BOOLEAN, .. Identificatori predefiniti: INVALID_NUMBER, Identificatori cu sir caractere Ex.TYPE cuvint rezervat, SELECT numar, type, .-eroare SELECT numar,TYPE,
7

Literali numerici: -sir de cifre, eventual precedat de +, sau -notatia stiintifica cu E sau e -operatorul ** Literali de tip caracter: c Literali de tip sir: sir de caractere Literalii de tip sir, cu exceptia sirului nul au tipul de date CHAR.
8

Limbajul PL/SQL- Elemente de baz

Limbajul PL/SQL- Elemente de baz


Literali booleeni: TRUE, FALSE, NULL Comentarii: -*/comentarii . /*
9

Tipuri de date: - Scalare: BINARY_INTEGER DEC DECIMAL DOUBLE PRECISION FLOAT INT INTEGER NATURAL

Limbajul PL/SQL- Elemente de baz


NATURALN NUMBER NUMERIC PLS_INTEGER POSITIVE POSITIVEN REAL SIGNTYPE
10

Limbajul PL/SQL- Elemente de baz


Tipuri scalare: CHAR CHARACTER LONG LONG RAW NCHAR NVARCHAR2 RAW ROWID STRING VARCHAR VARCHAR2 BOOLEAN DATE
11

Tipuri compuse: RECORD TABLE VARRAY Tipuri referin: REF CURSOR REF tip-obiect

Limbajul PL/SQL- Elemente de baz


Tipuri LOB: BFILE BLOB CLOB NCLOB

12

Limbajul PL/SQL- Elemente de baz


BINARY_INTEGER :[-2**31,2**31-1] Subtipuri ale lui BINARY_INTEGER: -SUBTYPE numesubtip IS tip-baza Subtipuri predefinite: -NATURAL -NATURALN -POSITIVE -POSITIVEN -SIGNTYPE

13

Limbajul PL/SQL- Elemente de baz


NUMBER[(precizie,nrzec)], 1.0E-130.. 9.99E125 NUMBER(precizie) max precizie 38 nrzec [-84,127] Subtipuri ale lui NUMBER: -DEC INTEGER -DECIMAL INT -NUMERIC DOUBLE PRECISION -FLOAT REAL -SMALLINT PLS_INTEGER 14

Tipuri caracter: - CHAR[(lungimef)], lungimef<=32767octeti max coloana tabela CHAR =2000 octeti - LONG lungime max=32760 max coloana tabela LONG=2**31-1 octeti Coloanele de tip LONG utilizate in: SELECT, UPDATE, INSERT dar nu in expresii, functii SQL, clauze WHERE, GROUP BY, CONNECT BY

Limbajul PL/SQL- Elemente de baz

15

Limbajul PL/SQL- Elemente de baz


RAW(lungime), lungime<=32767. max lungime coloana tabela =2000 octeti. LONG RAW lungime max.=32760. max lungime coloana tabela LONG RAW 2**31-1. ROWID - identificator de linie - numar obiect date(nr.segment date) - numar fisier date - numar bloc date in fisier date - numar linie in bloc de date VARCHAR2(lungime) lungime <=32767 16 Subtipuri: STRING, VARCHAR

National Language Support(NLS). - multime caractere database - multime caractere nationale NCHAR[(lungime)], lungime<=32767. coduri US7ASCII, JA16SJIS. Lungime in caractere. max lungime coloana tabela NCHAR=2000 NVARCHAR2(lungimemax), <=32767 max lungime coloana tabela =4000

Limbajul PL/SQL- Elemente de baz

17

Limbajul PL/SQL- Elemente de baz


Tipuri LOB(Large Objects) 4Go Mem.valori numite locatori. Pentru coloanele tip BLOB, CLOB,NCLOB datele memorate in baza de date. Pentru BFILE datele in fisiere ale SO. - BFILE. nr. max SESSION_MAX-OPEN_FILES . Read Only - BLOB Particip in tranzactii - CLOB blocuri de caractere - NCLOB blocuri 1 octet sau multiocteti.

18

Limbajul PL/SQL- Elemente de baz


Alte tipuri: - BOOLEAN -operatii logice -DATE. functia SYSDATE return data si timpul. Jan.1 4712 BC.. December 31, 4712 AD O data Julian =nr.zile din 1ian.4712 Functiile TO_DATE , TO_CHAR cu format J, da conversia valori DATE si echivalentul Julian. Formatul implicit dat este dat de parametrul NLS_DATE_FORMAT. Ex. DD-MON-YY
19

Definirea tipurilor -Tipuri de baza(BINARY_INTEGER, DEC..) -Tipuri definite de utilizator: TYPE numetip IS Definirea variabilelor: numevariabila numetip[:=expresie]; numevariabila numesubtip[:=expresie];

Limbajul PL/SQL- Elemente de baz

20

Limbajul PL/SQL- Elemente de baz


Definirea subtipurilor: -SUBTYPE numesubtip IS tipbaza; -SUBTYPE numesubtip IS tabela.cimp%TYPE;
-SUBTYPE numesubtip IS variabila%TYPE;

-SUBTYPE numesubtip IS cursor%ROWTYPE

21

Limbajul PL/SQL- Elemente de baz


DECLARE SUBTYPE EmpDate IS DATE; SUBTYPE alfa IS NATURAL; TYPE Nume1 IS TABLE OF VARCHAR2(15); SUBTYPE beta IS nume1; TYPE timprec IS RECORD( minute INTEGER, ore INTEGER); SUBTYPE timp IS timprec;
22

Limbajul PL/SQL- Elemente de baz


SUBTYPE numeid IS emp.empno%TYPE; CURSOR c1 IS SELECT * FROM dept; SUBTYPE deptlinie IS c1%ROWTYPE; In definitia unui subtip nu se poate specifica restrictie pe tipul de baza. SUBTYPE gama1 IS NUMBER(6,2); SUBTYPE gama2 IS CHAR(1); SUBTYPE gama3 IS VARCHAR(10);

23

Definirea de restrictii indirect: DECLARE var1 VARCHAR2(10); SUBTYPE vartip IS var1%TYPE; Folosirea subtipurilor: DECLARE SUBTYPE contor IS NATURAL; nr1 contor; nr2 contor;

Limbajul PL/SQL- Elemente de baz

24

Limbajul PL/SQL- Elemente de baz


DECLARE SUBTYPE alfatip IS NUMBER; total alfatip(8,2); DECLARE temp NUMBER(2,0); SUBTYPE alfa IS temp%TYPE; x alfa; y alfa; BEGIN x:=100; -- eroare
25

Compatibilitatea tipurilor: Un subtip nerestrins este interschimbabil cu tipul de baz. DECLARE SUBTYPE tipx IS NUMBER; cant NUMBER(8,2); total tipx; BEGIN total:=cant;
26

Limbajul PL/SQL- Elemente de baz

Subtipuri diferite sunt interschimbabile dac au acelasi tip de baz. DECLARE SUBTYPE tip1 IS BOOLEAN; SUBTYPE tip2 IS BOOLEAN; alfa tip1; beta tip2; BEGIN alfa:=beta;
27

Limbajul PL/SQL- Elemente de baz

Limbajul PL/SQL- Elemente de baz


Subtipuri diferite sunt interschimbabile dac tipurile lor de baz sunt in aceeasi familie. DECLARE SUBTYPE tip1 IS CHAR; SUBTYPE tip2 IS VARCHAR2; alfa tip1; beta tip2; BEGIN alfa:=beta;

28

Conversia tipurilor de date. 1. Conversia explicit: TO_DATE de la CHAR la DATE TO_NUMBER de la CHAR la NUMBER TO_CHAR de la DATE sau NUMBER la CHAR 2. Conversia implicit: DECLARE timp1 char(5); timp2 char(5);

Limbajul PL/SQL- Elemente de baz

29

Limbajul PL/SQL- Elemente de baz


diferenta number(5); BEGIN SELECT TO_CHAR(SYSDATE,SSSSS) INTO timp1 FROM sys.dual; secventa comenzi SELECT TO_CHAR(SYSDATE,SSSSS) INTO timp2 FROM sys.dual; diferenta:=timp2-timp1; INSERT INTO rezult VALUES (diferenta,..) 30 END;

Limbajul PL/SQL- Elemente de baz


________________________________________________________________

bin_int char date long number pls_int raw rowid varchar2 bin_int * * * * * Char * * * * Date * * * Long * * * Number * * * * * Pls_int * * * * * Raw * * * Rowid * * Varchar2 * * * * * * * * ______________________________________________________
31

Limbajul PL/SQL- Elemente de baz


Ex. 02-JUL-99 -> DATE xyDTRA -> DATE ? 12345ABCD -> NUMBER ? RAW sau LONG RAW in CHAR sau VARCHAR2. Coloana->variabil octet-> 2 caractere cd, unde c si d sunt cifre hexazecimale. CHAR sau VARCHAR2 in RAW sau LONG RAW. Variabil->coloan

32

Limbajul PL/SQL- Elemente de baz


Declararea variabilelor i constantelor: identificator tip [:=expresie]; identificator CONSTANT tip:=expresie; variabile neinitializate NULL - Cuvintul DEFAULT ptr.iniializarea variabilelor alfa BOOLEAN DEFAULT FALSE; - NOT NULL in declaraii urmat de iniializare.
33

Limbajul PL/SQL- Elemente de baz


Folosirea %TYPE: Specific tipul de dat al variabilelor sau coloanelor. NOT NULL nu se transmite. DECLARE nume emp.empno%TYPE BEGIN nume:=NULL;
34

Utilizare %ROWTYPE: Tip de inregistrare o linie tabel sau view DECLARE emp_rec emp%TYPE; CURSOR c1 IS SELECT deptno,dname,loc FROM dept; dept_rec c1%ROWTYPE; Coloanele din tip inregistrare au acelai tip cu cmpurile din nregistrare. SELECT * INTO emp_rec FROM emp where
35

Limbajul PL/SQL- Elemente de baz

Limbajul PL/SQL- Elemente de baz


Valorile coloanelor returnate de SELECT -> cmpurile nregistrrii. Referina la un cmp: inregistrare.cmp Asignare agregat: Declaraia cu%ROWTYPE nu are clauz de ini. DECLARE dept_rec1 dept%ROWTYPE; dept_rec2 dept%ROWTYPE; CURSOR c1 IS SELECT deptno,dname,loc FROM dept; 36

Limbajul PL/SQL- Elemente de baz


dept_rec3 c1%ROWTYPE; BEGIN dept_rec1:=dept_rec2; dept_rec2:=dept_rec3; --incorect Putem asigna o lista de valori la o inregistrare cu SELECT sau FETCH: SELECT deptno,dname,loc INTO dept_rec1 FROM dept WHERE deptno=10; 37

Nu putem asigna o lista de valori pentru o asignare: Numeinregistrare:=(val1,val2,)incorect Nu putem folosi inregistrarile pentru inserare sau actualizare: INSERT INTO dept VALUES (numeinregistrare)incorect PL/SQL nu permite referine forward Nu putem defini acelai tip de data pentru mai multe variabile.
38

Limbajul PL/SQL- Elemente de baz

Precedena operatorilor: **, NOT +, *, / +, -, || =, !=,<, >, <=, >= IS NULL, LIKE, BETWEEN, IN AND OR

Limbajul PL/SQL- Elemente de baz

39

Limbajul PL/SQL- Elemente de baz


Funcia NVL NVL(exp1,exp2) returneaz exp2 daca exp1=NULL altfel exp1 Funcia REPLACE REPLACE(sir1,sir2,sir3) returneaz: sir1 dac sir2 este NULL, indiferent de sir3 sir1 din care se elimin toate aparitiile lui sir2, cind sir2 nu e NULL si sir3 nu e NULL sir1 cind sir2 este NOT NULL si sir3 este NULL
40

Limbajul PL/SQL- Elemente de baz


Funcii Built-in 1) privitoare la erori: SQLCODE, SQLERRM 2) privitoare la numere: ABS COSH ROUND ACOS EXP SIGN ASIN FLOOR SIN ATAN LN SINH ATAN2 LOG SQRT CEIL MOD TAN COS POWER TANH

TRUNC 41

Limbajul PL/SQL- Elemente de baz


3)Funcii caracter: ASCII LPAD RTRIM CHR LTRIM SOUNDEX CONCAT NLS_INITCAP SUBSTR INITCAP NLS_LOWER SUBSTRB INSTR NLS_UPPER TRANSLATE INSTRB NLSSORT UPPER LENGTH REPLACE 42 LOWER RPAD

Limbajul PL/SQL- Elemente de baz


4)Conversii: CHARTOROWID CONVERT HEXTORAW NLS_CHARSET_ID NLS_CHARSET_NAME RAWTOHEX ROWIDTOCHAR

TO_CHAR TO_DATE TO_LABEL TO_MULTI_BYTE TO_NUMBER TO_SINGLE_BYTE


43

Limbajul PL/SQL- Elemente de baz


5) Dat calendaristic: ADD_MONTHS LAST_DAY MONTHS_BETWEEN NEW_TIME NEXT_DAY ROUND SYSDATE TRUNC
44

Limbajul PL/SQL- Elemente de baz


6) Diverse: DECODE DUMP GREATEST GREATEST_LB LEAST
LEAST_UB NVL UID USER USERENV VSIZE
45

Limbajul PL/SQL- Structuri de control


IF-THEN IF conditie THEN sir de comenzi; END IF; IF-THEN-ELSE: IF conditie THEN sir de comenzi1; ELSE sir de comenzi2; END IF;
46

Limbajul PL/SQL- Structuri de control


IF-THEN-ELSIF IF conditi1 THEN sir de comenzi1; ELSIF conditie2 THEN sir de comenzi2; ELSE sir de comenzi3; END IF;
47

LOOP LOOP sir de comenzi; END LOOP; EXIT si EXIT-WHEN LOOP IF conditie THEN EXIT; END IF END LOOP;

Limbajul PL/SQL- Structuri de control

48

Limbajul PL/SQL- Structuri de control


LOOP FETCH c1 INTO EXIT WHEN c1%NOTFOUND; . END LOOP; CLOSE c1;
IF c1%NOTFOUND THEN EXIT; END IF;
49

Limbajul PL/SQL- Structuri de control


Etichete LOOP <<nume eticheta>> LOOP sir de comenzi; END LOOP [nume eticheta]; <<e1>> LOOP <<e2>>

50

Limbajul PL/SQL- Structuri de control


EXIT e1 WHEN conditie; END LOOP e2; .. END LOOP e1; WHILE-LOOP WHILE conditie LOOP sir de comenzi; END LOOP;
51

FOR-LOOP FOR contor IN [REVERSE] min..max LOOP sir de comenzi; END LOOP; In interior contor este referit ca o constant. min, max pot fi :literali, variabile, expresii evaluate ca intregi. STEP h - IF MOD(contor,h)=0 THEN contor nu trebuie definit. 52

Limbajul PL/SQL- Structuri de control

Limbajul PL/SQL- Structuri de control


Ex. DECLARE contor integer; BEGIN FOR contor IN 1.. 20 LOOP . IF contor >8 THEN --refer contor din FOR END IF; END LOOP; END;
53

Limbajul PL/SQL- Structuri de control


Pentru a referi variabila global contor vom da: <<et1>> DECLARE contor INTEGER; BEGIN FOR contor IN 1.20 LOOP IF et1.contor > 8 THEN END IF; END LOOP; END et1; Acelai lucru i pentru FOR imbricai.

54

Limbajul PL/SQL- Structuri de control


<<et1>> FOR pas IN 1..20 LOOP FOR pas IN 1..5 LOOP . IF et1.pas >=12 THEN END IF; END LOOP; END LOOP et1;
55

Limbajul PL/SQL- Structuri de control


Folosirea lui EXIT: DECLARE emp_rec emp%ROWTYPE; CURSOR c1 IS SELECT deptno,dname,loc FROM dept; numarrec integer :=0; BEGIN SELECT COUNT(*) INTO numarrec FROM c1; FOR j IN 1..numarrec LOOP 56

Limbajul PL/SQL- Structuri de control


FETCH c1 INTO emp_rec; EXIT WHEN c1%NOTFOUND; . END LOOP; END;

57

Limbajul PL/SQL- Structuri de control


<<et1>> FOR i IN 1..10 LOOP FOR j IN 1..5 LOOP FETCH c1 INTO emp_rec; EXIT et1 WHEN c1%NOTFOUND; . END LOOP; END LOOP et1; --aici trece controlul
58

Limbajul PL/SQL- Structuri de control


Instruciunile GOTO i NULL. -GOTO eticheta Dup eticheta trebuie sa fie o instruciune executabil END LOOP nu este executabil. Folosim NULL; GOTO nu poate face saltul in interiorul unui IF, instruciune LOOP sau subbloc. GOTO nu poate face saltul de la o clauz IF la alta clauz a aceluai IF. GOTO nu poate face saltul dintr-un bloc de exceptii n blocul curent.

59

Limbajul PL/SQL- Colecii i nregistrri


Colecie=grup ordonat de elemente de acelai tip. Un element are indice unic n colecie. Dou tipuri de colecii: tabele nested i tablouri de dimensiune variabil-varrays. Coleciile pot memora instane ale unui tip obiect. Coleciile pot fi atribute ale unui tip obiect. Coleciile pot fi folosite ca parametri. Tabelele nested pot fi interpretate ca tabele cu o singur coloan. 60

Limbajul PL/SQL- Colecii i nregistrri


Arrays au un numr maxim de elemente. Tabelele nested sunt nemrginite. Arrays trebuie sa fie dense, fr spaii ntre elemente. Nu se pot terge elemente individuale din array. Iniial tabelele nested sunt dense. Cu procedura DELETE se pot terge elemente in tabele nested. Cu procedura NEXT operm asupra indicilor.
61

Limbajul PL/SQL- Colecii i nregistrri


Diferene ntre tabele nested i tabele index-by. - Tipuri permise pentru tabele index-by dar nu pentru tabele nested: Binary_integer, Boolean, Long,Long Raw, Natural, NaturalN, Pls_integer, Positive, PositiveN, Signtype, String. - Tabelele index-by sunt definite cu clauza INDEX BY BINARY_INTEGER. - O tabel nested neiniializat este NULL, ns o - tabel index-by neiniializat este vid. 62

Limbajul PL/SQL- Colecii i nregistrri


Pentru tabele nested indicele 1..2*31-1 Pentru tabele index-by indicele 2**31.. 2**31-1 Pentru extinderea unei tabele nested folosim procedura EXTEND, pentru tabele index-by specificm indici mai mari. Procedurile EXTEND i TRIM se pot aplica numai la tabele nested.

63

Limbajul PL/SQL- Colecii i nregistrri


Definirea i declararea coleciilor
TYPE numetip IS TABLE OF tipelement [NOT NULL] TYPE numetip IS{VARRAY|VARYING ARRAY}(max) OF tipelement [NOT NULL] Tipelement este orice tip PL/SQL cu excepia tipurilor: BINARY_INTEGER NCLOB SIGNTYPE BOOLEAN NVARCHAR2 STRING LONG PLS_INTEGER TABLE LONG RAW POSITIVE VARRAY NATURAL POSITIVEN NATURALN REF CURSOR NCHAR Tipuri obiect cu atribute TABLE sau VARRAY
64

Limbajul PL/SQL- Colecii i nregistrri


Dac tipelement este tip RECORD, atunci un cmp din nregistrare trebuie s fie tip scalar sau tip obiect. Definirea tipului tabele index-by:
TYPE numetip IS TABLE OF tipelement [NOT NULL] INDEXED BY BINARY_INTEGER; Tipuri permise pentru tabele index-by: BINARY_INTEGER NATURAL POSITIVEN BOOLEAN NATURALN SIGNTYPE LONG PLS_INTEGER STRING LONG RAW POSITIVE

65

Limbajul PL/SQL- Colecii i nregistrri


Tabelele index-by initial nu sunt dense. Ex. DECLARE TYPE tip1 IS TABLE OF emp%ROWTYPE INDEX BY BINARY_INTEGER; emp_tab_by tip1; BEGIN SELECT * INTO emp_tab_by(100) FROM emp WHERE empno=100; END;
66

Limbajul PL/SQL- Colecii i nregistrri Folosim %TYPE ce d tipul unei variabile sau coloan a unei tabele. Folosim %ROWTYPE ce d tipul de linie a unui cursor sau tabel. DECLARE
TYPE lista_emp IS TABLE OF emp.ename%TYPE; CURSOR c1 IS SELECT * FROM dept; TYPE tip_dept IS VARRAY(15) OF c1%ROWTYPE; BEGIN . 67

Limbajul PL/SQL- Colecii i nregistrri DECLARE TYPE inreg1 IS RECORD ( nume VARCHAR2(20), nrcopii NATURAL); TYPE persoane IS VARRAY(100) OF inreg1; BEGIN

68

Limbajul PL/SQL- Colecii i nregistrri

Declararea coleciilor identificator numetip; CREATE TYPE lista_cursuri AS TABLE OF VARCHAR2(10) / CREATE TYPE Student AS OBJECT ( marca INTEGER(4), nume VARCHAR2(15), cursuri lista_cursuri) /

69

Limbajul PL/SQL- Colecii i nregistrri


CREATE TYPE Proiect AS OBJECT( nr_proiect NUMBER(2), cost NUMBER(7,2)) / CREATE TYPE lista_proiecte AS VARRAY(20) OF proiect / CREATE TABLE depart2 ( id_dept NUMBER(2), nume VARCHAR2(20), proiecte lista_proiecte) /

70

Limbajul PL/SQL- Colecii i nregistrri


Iniializarea i referirea coleciilor. -Dup declarare colecia este cu valoarea NULL. -Pentru iniializare folosim constructor. Ex. DECLARE cursuri_felea lista_cursuri; BEGIN cursuri_felea:=lista_cursuri(Baze de date I, Baze de date II, Baze de date orientate obiect); sau cursuri_felea lista_cursuri:=lista_cursuri(Baze de date I,); Putem utiliza NULL. 71

Limbajul PL/SQL- Colecii i nregistrri


Ex. DECLARE proiecte_info lista_proiecte; BEGIN proiecte_info := lista_proiecte(proiect(1,1000), proiect(2,1500),proiect(3,1600)); Constructor fr argumente d colecie vid dar NOT NULL. Ex. DECLARE TYPE clientela IS VARRAY(50) OF Customer; clientela_felea clientele:=clientela(); --tablou vid BEGIN IF clientela_felea IS NOT NULL THEN -TRUE
72

Limbajul PL/SQL- Colecii i nregistrri -Constructorii sunt permii in clauze ca VALUES,SET, componente din SELECT Ex. BEGIN INSERT INTO depart2 VALUES( 1,info,lista_proiecte(proiect(20,1000), proiect(30,1400),proiect(40,12000)));

Referirea coleciilor nume_colectie(indice) indice: 1..2147483647(2**31-1) tabele nested 1..maximum - varray 73

Limbajul PL/SQL- Colecii i nregistrri


Ex. DECLARE TYPE filme IS TABLE OF VARCHAR2(30); filme_rom filme:=filme(Mihai Viteazul,Rascoala,); i BINARY_INTEGER; x VARCHAR2(30); BEGIN i:=1; IF filme_rom(i)=xxxx THEN nume_procedura(filme_rom(i)); x:=nume_functie(par1,par2,,parn)(i)
74

Limbajul PL/SQL- Colecii i nregistrri


Asignarea coleciilor: INSERT, UPDATE, FETCH, SELECT, comanda de asignare sau chemare de subprogram. Ex. DECLARE TYPE clientela1 IS VARRAY(50) OF Customer; TYPE clientela2 IS VARRAY(50) OF Customer; clientela_soc1 clientela1:=clientela1(); clientela_soc2 clientela1:=clientela1(); clientela_soc3 clientela2:=clientela2(); BEGIN clientela_soc2:=clientela_soc1; clientela_soc3:=clientela_soc2; -- incorect 75

Limbajul PL/SQL- Colecii i nregistrri


Ex. DECLARE TYPE clientela iS TABLE OF Customer; grup1 clientela:=clientela(); grup2 clientela; -- NULL grup3 clientela:=clientela(); BEGIN IF grup1 IS NULL THEN --FALSE grup1:=grup2; IF grup2 IS NULL THEN -- TRUE grup2:=grup3; If grup2 IS NULL THEN --FALSE
76

Limbajul PL/SQL- Colecii i nregistrri


Asignarea elementelor coleciilor nume_colectie(indice):=expresie; Dac indice este NULL sau neconvertibil la un intreg, atunci avem excepia VALUE_ERROR Dac colecia este NULL, atunci avem excepia COLLECTION_IS_NULL Ex. DECLARE TYPE lista IS TABLE OF INTEGER; nume1 lista:=lista(100,200,300); nume2 lista;
77

Limbajul PL/SQL- Colecii i nregistrri


BEGIN nume1(2):=150; nume1(1):=nume1(2); nume1(3):=ASCII(G); nume1(H):=400; -- excepie VALUE_ERROR nume2(2):= 145; -- excepie COLLECTION_IS_NULL - Coleciile nu pot fi comparate cu = sau <> - Coleciile nu pot apare n DISTINCT, GROUP BY, ORDER
78

Limbajul PL/SQL- Colecii i nregistrri


CREATE TYPE curs AS OBJECT ( nr_curs NUMBER(5), titlu VARCHAR(30), credite NUMBER(1)); CREATE TYPE list_cursuri AS TABLE OF curs; CREATE TABLE depart3 ( nume VARCHAR2(25), director VARCHAR2(30), cursuri list_cursuri) NESTED TABLE cursuri STORE AS Tcursuri;
79

Limbajul PL/SQL- Colecii i nregistrri


BEGIN INSERT INTO depart3 VALUES (INFO,POPESCU,list_cursuri(curs(1,ALGORITMI,6),c urs(2,BAZE DE DATE,6))); DECLARE noua_lista list_cursuri:= list_cursuri(curs(10,Programare,6), curs(20,Logica,6)); BEGIN UPDATE depart3 SET cursuri=noua_lista WHERE nume=INFO;
80

Limbajul PL/SQL- Colecii i nregistrri Ex. DECLARE cursuri_info list_cursuri; BEGIN SELECT cursuri INTO cursuri_info FROM depart3 WHERE nume= INFO;

81

Prelucrarea elementelor individuale - Pentru elementele unei tabele nested THE - Pentru elementele unui VARRAY proceduri Ex. BEGIN INSERT INTO THE(SELECT cursuri FROM depart3 WHERE nume=INFO) VALUES(22,Teoria algoritmilor,6); UPDATE THE(SELECT cursuri FROM depart3 WHERE nume=INFO) SET credite=credite+1 WHERE nr_curs IN(1,22); 82

Limbajul PL/SQL- Colecii i nregistrri

Limbajul PL/SQL- Colecii i nregistrri


DECLARE nr_cursv NUMBER(5); titluv VARCHAR2(30); BEGIN SELECT nr_curs,titlu INTO nr_cursv,titluv FROM THE(SELECT cursuri FROM depart3 WHERE nume=INFO) WHERE nr_curs=1; DELETE THE(SELECT cursuri FROM depart3 WHERE nume=INFO) WHERE titlu=BD2; 83

Limbajul PL/SQL- Colecii i nregistrri


CREATE PROCEDURE adauga_proiect( nr_dept IN NUMBER; proiect_nou IN Proiect; pozitie IN NUMBER) AS proiecte_dept lista_proiecte; BEGIN SELECT proiecte INTO proiecte_dept FROM depart2 WHERE id_dept=nr_dept FOR UPDATE OF proiecte; /* Returneaza lista de proiecte in variabila proiecte_dept*/ proiecte_dept.EXTENDED; /*Extinde tabloul pentru a face loc noului element*/
84

Limbajul PL/SQL- Colecii i nregistrri


FOR i IN REVERSE pozitie..proiecte_dept.LAST1 LOOP proiecte_dept(i+1):=proiecte_dept(i); END LOOP; /* Deplaseaza elementele tabloului spre dreapta incepind cu indicele pozitie */ proiecte_dept(pozitie):= proiect_nou; /* Insereaza noul proiect */ UPDATE depart2 SET proiecte= proiecte_dept WHERE id_dept= nr_dept; /* Actualizeaza tabela depart2 */ END adauga_proiect; 85

Limbajul PL/SQL- Colecii i nregistrri


CREATE PROCEDURE actualiz_proiect( nr_dept IN NUMBER; nr_proiect IN NUMBER; cost_nou IN NUMBER DEFAULT NULL)AS proiecte_dept lista_proiecte; BEGIN SELECT proiecte INTO proiecte_dept FROM depart2 WHERE id_dept=nr_dept FOR UPDATE OF proiecte; FOR i IN proiecte_dept.FIRST..proiecte_dept.LAST LOOP IF proiecte_dept(i).nr_proiect=nr_proiect THEN
86

Limbajul PL/SQL- Colecii i nregistrri


IF cost_nou IS NOT NULL THEN proiecte_dept(i).cost:=cost_nou; END IF; EXIT; END IF; END LOOP; UPDATE depart2 SET proiecte=proiecte_dept WHERE id_dept=nr_dept; END actualiz_proiect;
87

Limbajul PL/SQL- Colecii i nregistrri


Ex. Apelul procedurii actualiz_proiect DECLARE nr_deptv NUMBER :=10; nr_proiectv NUMBER :=100; cost_nouv NUMBER :=2000; BEGIN . acualiz_proiect(nr_deptv,nr_proiectv,cost_nouv); acualiz_proiect(nr_deptv,nr_proiectv,cost_nou=>1700);
88

Limbajul PL/SQL- Colecii i nregistrri


Metode ale coleciilor: - EXISTS - COUNT - LIMIT - FIRST, LAST - PRIOR, NEXT - EXTEND - TRIM - DELETE Apelul unei metode: nume_colectie.nume_metoda[(lista_de_parametri)]

89

Limbajul PL/SQL- Colecii i nregistrri


Numai EXISTS se poate aplica la colecii nule. Dac o alt metod se aplic la o colecie nul, atunci se apeleaz COLLECTION_IS_NULL. - EXISTS(n) , n este intreg. Ex. IF cursuri.EXISTS(i) THEN cursuri(i):= - COUNT returneaz nr. de elemente ale coleciei. - Pentru VARRAY COUNT=LAST - LIMIT pentru VARRAY d numrul maxim de elemente, pentru tabele nested are valoarea NULL. - FIRST, LAST primul i ultimul indice din colecie. Pentru VARRAY FIRST =1, LAST=COUNT 90

Limbajul PL/SQL- Colecii i nregistrri


PRIOR(n) indicele ce precede indicele n. NEXT(n) - indicele ce succede indicele n. Dac elementul n nu are predecesor, PRIOR(n) este NULL. Dac elementul n nu are succesor, NEXT(n) este NULL. Ex. Traversarea unei tabele nested: i:=cursuri.FIRST; WHILE i IS NOT NULL LOOP .prelucreaz curs(i).. i:=cursuri.NEXT(i); END LOOP; La traversare PRIOR i NEXT ignor elementele terse 91

Limbajul PL/SQL- Colecii i nregistrri


EXTEND mrete dimensiunea coleciei. - EXTEND adaug un element null. - EXTEND(n) - adaug n elemente null. - EXTEND(n,i) - adaug n copii ale elementului i. Nu se poate folosi EXTEND pentru a initializa o colecie nul. Dac impunem NOT NULL pentru tipul TABLE sau VARRAY, atunci nu trebuie folosit EXTEND de primele 2 tipuri. DECLARE TYPE lista_cursuri1 IS TABLE OF VARCHAR2(10); cursuri1 lista_cursuri1;
92

Limbajul PL/SQL- Colecii i nregistrri


BEGIN cursuri1:=lista_cursuri1(Algoritmi,Baze de date I,Limbaje formale,Tehnici de compilare); cursuri1.DELETE(3); cursuri1.EXTEND; - adaug un element null. cursuri1(5):=Programare obiect; END; Dac se utilizeaz cursuri1(i), unde i>5, atunci se iniiaz excepia SUBSCRIPT_BEYOND_COUNT Elementele terse sunt socotite n calculul dimensiunii. COUNT pentru tabele nested returneaz nr. de elemente neterse 93

Limbajul PL/SQL- Colecii i nregistrri TRIM are dou forme:


- TRIM ndeprteaz un element de la sfritul coleciei - TRIM(n) ndeprteaz n elemente Dac n>COUNT atunci se lanseaz excepia SUBSCRIPT_BEYOND_COUNT TRIM consider elementele terse. DELETE are trei forme: - DELETE terge toate elementele unei colecii, - DELETE(n) terge al n-lea element din tabel nested, - DELETE(m,n) terge toate elementele cu indici m..n Dac m>n sau m is null sau n is null, atunci DELETE nu terge nimic. 94

Limbajul PL/SQL- Colecii i nregistrri Varrays sunt dense, deci nu folosim proc. DELETE PL/SQL ine o eviden a elementelor terse.
O tabel nested sau un varray poate fi parametru formal al unei proceduri sau funcii. Evitarea excepiilor. - Referirea la un element inexistent produce o excepie predefinit. Ex. DECLARE TYPE numlist IS TABLE OF NUMBER; nums numlist; -- colecie atomic nul. BEGIN nums(1):=10; -- excepia: COLLECTION_IS_NULL nums:=numlist(15,20); --iniializarea tabelei 95

Limbajul PL/SQL- Colecii i nregistrri


nums(NULL):=5; -- VALUE_ERROR nums(0):= 15; --SUBSCRIPT_OUTSIDE_LIMIT nums(3):=40; --SUBSCRIPT_BEYOND_COUNT nums.DELETE(1); - terge elementul 1 IF nums(1)= 15 THEN --NO_DATA_FOUND Excepie Apare cnd.. COLLECTION_is_NULL colecia este atomic nul NO_DATA_FOUND indicele specific un element ters SUBSCRIPT_BEYOND_FOUND indicele depete numrul de elemente din colecie. SUBSCRIPT_OUTSIDE_LIMIT indice n afara domeniului legal. VALUE_ERROR indice null sau neconvertibil la un intreg 96

Limbajul PL/SQL- Inregistrri Definirea:


TYPE tip_inreg IS RECORD (cimp1,cimp2,); cimpi are forma general: numecimp tip [[NOT NULL] {:=|DEFAULT} expresie] Tipul inregistrare nu poate fi creat si memorat in baza de date. Putem folosi %TYPE si %ROWTYPE pentru a specifica tipul cimpurilor. Tipul obiect nu poate avea ca atribute tipul RECORD. Inregistrarile pot contine obiecte, colectii si alte inregistrari, numite inregistrari nested.
97

Limbajul PL/SQL- Inregistrri


DECLARE TYPE TimeRec IS RECORD ( seconds SMALLINT, minutes SMALLINT, hours SMALLINT); TYPE FlightRec IS RECORD ( flight_no INTEGER, plane_id VARCHAR2(10), captain Employee, --obiect passengers PassengerList, --varray depart_time TimeRec, airport_code VARCHAR2(10));
98

Limbajul PL/SQL- Inregistrri


Declararea: var_inregistrare tip_inregistrare; - var_inregistrare poate fi parametru formal pentru proceduri sau funcii. Iniializarea i referirea nregistrrilor: - numecimp tip [[NOT NULL] {:=|DEFAULT} expresie] Referirea: var_inregistrare.numecimp Dac o funcie returneaz o inregistrare, atunci referirea unui cimp se face: nume_functie(lista_parametri).numecimp
99

Limbajul PL/SQL- Inregistrri


DECLARE TYPE EmpRec IS RECORD ( emp_id NUMBER(4), job_title CHAR(14), salary REAL(7,2)); middle_sal REAL; FUNCTION F1(n INTEGER) RETURN EmpRec Is emp_info EmpRec; BEGIN RETURN emp_info; END;
100

Limbajul PL/SQL- Inregistrri


BEGIN middle_sal:=F1(10).salary; END; Folosim notaia . pentru referirea la cimpuri nested i la obiecte memorate ntr-un cimp. Asignarea nregistrrilor: var_inregistrare_numecimp:=expresie; ex. emp_info.name :=UPPER(emp_info.name); var_inreg1:=var_inreg2; -- acelai tip;

101

Limbajul PL/SQL- Inregistrri


DECLARE TYPE DeptRec IS RECORD ( dept_num NUMBER(2), dept_name CHAR(14), location CHAR(13)); dept1_info DeptRec; dept2_info dept%ROWTYPE; BEGIN SELECT * INTO dept2_info FROM dept WHERE deptno=10; dept1_info:=dept2_info; sau SELECT * INTO dept1_info FROM dept WHERE deptno=10;

102

Limbajul PL/SQL- Inregistrri


- Nu putem folosi var_inregistrare n INSERT.
- Nu putem folosi: var_inregistrare:=(v1,v2,); - Nu putem compara nregistrrile, nici cu IS NULL sau IS NOT NULL. Prelucrarea nregistrrilor: SQL> CREATE TYPE Passenger AS OBJECT ( flight_no NUMBER(3), name VARCHAR2(20), seat CHAR(5)); SQL> CREATE TYPE PassengerList AS VARRAY(300) OF Passenger; SQL> CREATE TABLE flights ( 103

Limbajul PL/SQL- Inregistrri


flight_no NUMBER(3), gate CHAR(5), departure CHAR(15), arrival CHAR(15), passengers PassengerList); BEGIN INSERT INTO flights VALUES(100,L25,BUC 6:50PM,IASI 7.50PM, PassengerList(Passenger(100,Popescu,3A), Passenger(100,Ionescu,4A), Passenger(100,Eftimie,5A))); Ex.Program pentru citirea tabelei flights folosind o var de tip inregistrare. 104

Limbajul PL/SQL- Interactiunea cu Oracle


Functii SQL: PL/SQL permite utilizarea functiilor SQL, inclusiv AVG,MIN, MAX,COUNT, SUM, STDDEV, VARIANCE - nume_functie ([ALL|DISTINCT] expresie) - functiile de grupare ignora NULL,cu exceptia lui COUNT(*) Pseudocoloane SQL: CURRVAL, LEVEL, NEXTVAL, ROWID, ROWNUM - Se folosesc in instr.SQL, nu in cele procedurale. - CURRVAL si NEXTVAL: -O secventa este o schema ce genereaza numere secventiale. 105

Limbajul PL/SQL- Interactiunea cu Oracle


CREATE SEQUENCE nume_secv INCREMENT BY pas MINVALUE val1 MAXVALUE val2 NOCYCLE NOCACHE ORDER - Secventa este initializata prin NEXTVAL. - Exista tabela USER_SEQUENCES cu LAST_VAL LEVEL ROWID returneaza adresa binara a unei linii. - Tipul de data este ROWID DECLARE mid1 ROWID; mname emp.name%TYPE; mjob emp.job%TYPE; CURSOR C1 IS SELECT ename, job, ROWID FROM emp;
106

Limbajul PL/SQL- Interactiunea cu Oracle


BEGIN OPEN C1; LOOP FETCH C1 INTO mname, mjob, mid1; EXIT WHEN C1%NOTFOUND; UPDATE emp SET sal=sal*1.1 WHERE ROWID=mid1; COMMIT; END LOOP: CLOSE C1; END;

107

Limbajul PL/SQL- Interactiunea cu Oracle


ROWNUM asigneaza un numar unic fiecarei linii. CURSOR C1 IS SELECT empno, sal FROM emp WHERE sal>2000 AND ROWNUM <15; Operatori SQL: ALL, ANY/SOME, BETWEEN, EXISTS, IN, IS NULL, LIKE, AND, NOT ,OR. Operatori de tip multime: INTERSECT, MINUS, UNION, UNION ALL Operatori de tip linie: ALL, DISTINCT, PRIOR, CONNECT BY
108

Limbajul PL/SQL- Interactiunea cu Oracle


CREATE PROCEDURE creare AS BEGIN CREATE TABLE dept1(cimp1 NUMBER(2),) incorect END;

CREATE PROCEDURE sterge (nume_tabela IN VARCHAR2) AS BEGIN DROP TABLE nume_tabela; -- incorect END;
109

Limbajul PL/SQL- Interactiunea cu Oracle


Cursori impliciti si expliciti. Declararea: CURSOR nume_cursor [(p1,p2,)] [RETURN tip_returnat] IS SELECT; tip_returnat specifica o inregistrare sau o linie intr-o tabela. p1,p2,.. au forma: nume_parametru [IN] tip [{:= | DEFAULT} expresie] OPEN nume_cursor(v1,v2,); -- notatie pozitionala, OPEN nume cursor(p1=>v1,): --notatie cu nume, OPEN nume cursor(v1,p2=>v2,); -- mixta Comanda pe un cursor inchis produce exceptia: INVALID_CURSOR. 110

Limbajul PL/SQL- Interactiunea cu Oracle


Cursori in pachete. CREATE PACKAGE pachet1 AS CURSOR c1 RETURN emp%ROWTYPE; /* Declaratie specificare cursor*/ . END pachet1; CREATE PACKAGE BODY pachet1 AS CURSOR c1 RETURN emp%ROWTYPE IS SELECT * FROM emp WHERE sal >4000; /*Definirea corpului cursorului */ END pachet1;

111

Folosirea cursorului in Ciclu FOR DECLARE result NUMBER(5); CURSOR c1 IS SELECT cimp1,cimp2 FROM T1 WHERE marca=10; BEGIN FOR c1_rec IN c1 LOOP result:=c1_rec.cimp1+c1_rec.cimp2; INSERT INTO temp VALUES(result,NULL,NULL); END LOOP; COMMIT; END; 112

Limbajul PL/SQL- Interactiunea cu Oracle

Limbajul PL/SQL- Interactiunea cu Oracle


Folosirea subinterogarilor. DECLARE bonus REAL; BEGIN FOR emp_rec IN( SELECT ampno, sal,comm FROM emp) LOOP bonus:=(emp_rec.sal*0.1)+(emp_rec.comm*0.05); INSERT INTO bonuses VALUES (emp_rec.empno,bonus); END LOOP; COMMIT; END; 113

Limbajul PL/SQL- Interactiunea cu Oracle


Cursor cu parametri. CURSOR nume_c (p1,p2,) IS SELECT FOR v1 IN nume_c(v1,v2,) LOOP . END LOOP; Variabile cursor. - Are tipul REF CURSOR - Definirea: TYPE ref_type_name IS REF CURSOR RETURN return_type; Ex. TYPE tipc1 IS REF CURSOR RETURN emp%ROWTYPE; TYPE tipc2 IS REF CURSOR; - Declararea: var_cursor tip_cursor; 114

Limbajul PL/SQL- Interactiunea cu Oracle Variabile cursor parametri formali. TYPE tip_c IS REF CURSOR RETURN emp%ROWTYPE; PROCEDURE proc1 (par1 IN OUT tip_c) IS Controlul variabilelor cursor:OPEN-FOR, FETCH, CLOSE. - OPEN nume_var_cursor |:nume_var_cursor_host} FOR SELECT; atribute: %FOUND, %NOTFOUND, %ISOPEN, %ROWCOUNT. IF NOT nume_var_cursor%ISOPEN THEN OPEN nume_var_cursor FOR SELECT * FROM emp; END IF; 115

Limbajul PL/SQL- Interactiunea cu Oracle OPEN-FOR poate deschide aceeasi variabila cursor pentru diferite interogari. Ex. CREATE PACKAGE p1 AS
TYPE tipemp IS REF CURSOR RETURN emp%ROWTYPE; PROCEDURE open_emp (emp_c IN OUT tipemp); END p1; CREATE PACKAGE BODY p1 AS PROCEDURE open_emp (emp_c IN OUT tipemp) IS BEGIN OPEN emp_c FOR SELECT * FROM emp; END open_mp; END p1;

116

Limbajul PL/SQL- Interactiunea cu Oracle Ex. CREATE PACKAGE p2 AS TYPE generic1 IS REF CURSOR; TYPE emptip IS REF CURSOR RETURN emp%ROWTYPE; TYPE depttip IS REF CURSOR RETURN dept%ROWTYPE; END p2; CREATE PROCEDURE open_emp(emp_cv IN OUT p2.emptip) AS BEGIN OPEN emp_cv FOR SELECT * FROM emp WHERE ; END open_mp; 117

Limbajul PL/SQL- Interactiunea cu Oracle


CREATE PACKAGE p3 AS TYPE generic2 IS REF CURSOR; TYPE emptip IS REF CURSOR RETURN emp%ROWTYPE; PROCEDURE open_emp(emp_c IN OUT emptip, I IN NUMBER); END p3; CREATE PACKAGE BODY p3 AS PROCEDURE open_emp(emp_c IN OUT emptip, I IN NUMBER) IS BEGIN IF I=1 THEN OPEN emp_c FOR SELECT * FROM emp WHERE comm =0; IF I=2 THEN OPEN emp_c FOR SELECT * FROM emp WHERE sal>1000; END IF; END open_emp; END p3; 118

Limbajul PL/SQL- Interactiunea cu Oracle


CREATE PACKAGE BODY p3 AS PROCEDURE open_emp(generic_cv IN OUT generic2, I IN NUMBER) IS BEGIN IF I=1 THEN OPEN generic_cv FOR SELECT * FROM emp; ELSIF I=2 THEN OPEN generic_cv FOR SELECT * FROM dept; ELSIF OPEN generic_cv FOR SELECT * FROM salgrade; END IF; END open_emp; END p3;
119

Limbajul PL/SQL- Interactiunea cu Oracle Evitarea exceptiilor. var_cursor1:=var_cursor2; -- trebuie sa fie de acelasi tip.
DECLARE TYPE TypEmp IS REF CURSOR RETURN emp%ROWTYPE; TYPE TypTmp IS REF CURSOR RETURN emp%ROWTYPE; PROCEDURE open_cursor (emp_cv IN OUT TypEmp, tmp_cv IN OUT TypTmp) IS BEGIN emp_cv:=tmp_cv; -- eroare wrong type END; Daca unul este slab tipizat, atunci cei doi nu trebuie sa aiba acelasi tip
120

Limbajul PL/SQL- Interactiunea cu Oracle


DECLARE TYPE TypEmp IS REF CURSOR RETURN emp%ROWTYPE; emp_cv1 TypEmp; emp_cv2 TypEmp; emp_rec emp%ROWTYPE; BEGIN emp_cv2:=emp_cv1; -- inutil OPEN emp_cv1 FOR SELECT * FROM emp; /* emp_cv1 pointeaza catre o zona de lucru */ FETCH emp_cv1 INTO emp_rec; FETCH emp_cv2 INTO emp_rec; --exceptia INVALID_CURSOR EXCEPTION WHEN INVALID_CURSOR THEN /* facem ca emp_cv2 si emp_cv1 sa pointeze aceeasi zona de lucru*/121

Limbajul PL/SQL- Interactiunea cu Oracle


emp_cv2:=emp_cv1; FETCH emp_cv2 INTO emp_rec; -- returneaza a doua linie. OPEN emp_cv2 FOR SELECT * FROM emp1; /* reutilizarea zonei de lucru pentru alta interogare */ FETCH emp_cv1 INTO rep_rec; /* furnizeaza prima linie din tabela emp1 */ END; Daca parametrii actuali si cei formali nu au acelasi tip- exceptia ROWTYPE_MISMATCH emp_cv2:=emp_cv1; -- primul este un alias pentru al doilea PROCEDURE proc1 (emp_cv1 IN OUT TypEmp, emp_cv2 IN OUT TypEmp) IS emp_rec emp%ROWTYPE;
122

Limbajul PL/SQL- Interactiunea cu Oracle


BEGIN
OPEN emp_cv1 FOR SELECT * FROM emp; emp_cv2:=emp_cv1; FETCH emp_cv1 INTO emp_rec; -- prima linie FETCH emp_cv2 INTO emp_rec; -- a doua linie FETCH emp_cv1 INTO emp_rec; -- a treia linie CLOSE emp_cv1; FETCH emp_cv2 INTO emp_rec; -- exceptia INVALID_CURSOR; END proc1; Aceeasi eroare apare cind un parametru apare de 2 ori intr-un apel. Procedure proc2 (emp_cv1 IN OUT TypEmp,emp_cv2 IN OUT TypEmp) IS emp_cv TypEmp; proc2(emp_cv,emp_cv); 123

Limbajul PL/SQL- Interactiunea cu Oracle


Restrictii asupra variabilelor cursor: - Nu se pot declara in pachete deoarece nu au o stare persistenta. - O interogare asociata cu o variabila cursor intr-o instructiune OPENFOR nu poate fi FOR UPDATE. -Nu putem folosi variabile cursor in operatori de comparare:=,!=, NULL - Nu putem asigna NULL la variabile cursor - Nu putem folosi tipul REF CURSOR pentru o coloana in comenzile CREATE TABLE si CREATE VIEW. - Nu putem folosi REF CURSOR sa specificam tipul elementelor unei colectii. - Cursorii si variabilele cursor nu sunt interoperabile. CURSOR emp_1 IS SELECT * FROM emp; TYPE TypEmp IS REF CURSOR RETURN emp%ROWTYPE; emp_cv TypEmp; FOR emp_rec IN emp_cv LOOP --ilegal 124

Limbajul PL/SQL- Interactiunea cu Oracle


DECLARE TYPE EmpTyp IS REF CURSOR RETURN emp%ROWTYPE; empv EmpTyp; PROCEDURE process_emp_cv (emp_cv IN EmpTyp) IS person emp%ROWTYPE; BEGIN dbms_output.put_line(*****'); LOOP FETCH emp_cv INTO person; EXIT WHEN emp_cv%NOTFOUND; dbms_output.put_line('Nume = ' || person.first_name || ' ' || person.last_name); END LOOP; END; 125

Limbajul PL/SQL- Interactiunea cu Oracle


BEGIN OPEN empv FOR SELECT * FROM emp WHERE ROWNUM < 10; process_emp_cv(empv); CLOSE emp; END; Expresii cursor: Returneaza un cursor imbricat. O linie returnata de un cursor obisnuit poate contine valori sau o submultime de alte linii produse de subinterogari. Sintaxa expresiei cursor: CURSOR(interogare SELECT) Expresiile cursor pot apare in declaratii cursor, declaratii REF CURSOR, interogari SQL.
126

Limbajul PL/SQL- Interactiunea cu Oracle


DECLARE TYPE emp_typ IS REF CURSOR;

emp_c emp_typ; dept_name departments.department_name%TYPE; emp_name emp.last_name%TYPE; CURSOR c1 IS SELECT department_name, CURSOR ( SELECT e.last_name FROM emp e WHERE e.department_id = d.department_id ) employees FROM departments d WHERE department_name like INFO%'; BEGIN OPEN c1; LOOP FETCH c1 INTO dept_name, emp_c; EXIT WHEN c1%NOTFOUND;
127

Limbajul PL/SQL- Interactiunea cu Oracle


dbms_output.put_line('Department: ' || dept_name); -- Pentru fiecare linie a rezultatului prelucram submultimea definita de subinterogare. LOOP FETCH emp_c INTO emp_name; EXIT WHEN emp_c%NOTFOUND; dbms_output.put_line(' Employee: ' || emp_name); END LOOP; END LOOP; CLOSE c1; END; Restrictii: -Nu putem folosi o expresie cursor cu un cursor implicit -Nu pot apare in declaratii view - Nu putem realiza operatii EXECUTE pe expresii cursor
128

Limbajul PL/SQL- Interactiunea cu Oracle


Atribute cursor : %FOUND, %ISOPEN, %NOTFOUND, %ROWCOUNT CURSOR C1 IF C1%ISOPEN THEN cursor deschis ELSE -- il deschidem OPEN C1; END IF; Inainte de FETCH, %NOTFOUND este NULL. EXIT WHEN C1%NOTFOUND OR C1%NOTFOUND IS NULL Inainte de deschiderea unui cursor sau variabila cursor %ROWCOUNT este 0.
129

Limbajul PL/SQL- Interactiunea cu Oracle


LOOP FETCH C1 INTO inreg; IF C1%ROWCOUNT >11 THEN END IF; END LOOP; In cazul cind cursorul e nedeschis referirea la %ROWCOUNT produce exceptia INVALID_CURSOR. Dupa prima executie FETCH daca nu exista linii in multimea respectiva, atunci %FOUND este FALSE, %NOTFOUND este TRUE si %ROWCOUNT este 0. Atributele pentru cursori impliciti sunt aceleasi, dar returneaza informatii despre executia comenzilor INSERT, UPDATE, DELETE, SELECT. 130

Limbajul PL/SQL- Interactiunea cu Oracle


%FOUND Inainte ca instructiunea SQL sa fie executata, %FOUND este NULL. Apoi %FOUND este TRUE daca INSERT, UPDATE sau DELETE a afectat cel putin o linie, sau SELECT INTO returneaza cel putin o linie. Altfel %FOUND este FALSE. DELETE FROM emp WHERE empno=emp1; IF SQL%FOUND THEN stergere cu succes INSERT INTO emp_new VALUES(emp1,..); %ISOPEN Oracle inchide automat cursorul SQL dupa executia instructiunii SQL. Deci%ISOPEN este mereu FALSE. %NOTFOUND Produce TRUE daca INSERT, UPDATE sau DELETE nu afecteaza nicio linie, sau SELECT INTO nu returneaza nicio linie.Altfel, ea produce FALSE. 131

Limbajul PL/SQL- Interactiunea cu Oracle


%ROWCOUNT Produce numarul de linii afectate de INSERT, UPDATE, DELETE sau returnate de SELECT INTO. Daca SELECT INTO returneaza cel putin 2 linii, atunci apare exceptia TOO_MANY_ROWS si %ROWCOUNT este 1. Valorile atributelor cursor se refera la cea mai recenta instructiune SQL executata. Daca SELECT INTO nu returneaza nicio linie , atunci PL/SQL produce exceptia NO_DATA_FOUND. SELECT INTO cu o functie de grupare nu produce exceptia de sus, deoarece functia de grupare produce o valoare sau NULL. Atunci %NOTFOUND este FALSE.
132

Limbajul PL/SQL- Interactiunea cu Oracle


Prelucrarea tranzactiilor -COMMIT Face permanente schimbarile din timpul tranzactiei. BEGIN SELECT suma INTO suma1 FROM cont WHERE nrcont=1500; UPDATE cont SET suma= suma1-debit WHERE nrcont=1500; UPDATE cont SET suma=suma1+debit WHERE nrcont=1600; COMMIT WORK; END; COMMIT COMENT mesaj;
133

Limbajul PL/SQL- Interactiunea cu Oracle


ROLLBACK DECLARE emp_id INTEGER; BEGIN SELECT ampno, INTO emp_id, FROM .. INSERT INTO emp VALUES (emp_id,); INSERT INTO emp1 VALUES (emp_id,); INSERT INTO emp2 VALUES (emp_id,); EXCEPTION WHEN DUP_VAL_ON_INDEX THEN ROLLBACK; END;

134

Limbajul PL/SQL- Interactiunea cu Oracle


SAVEPOINT Numeste si marcheaza un punct curent in prelucrarea unei tranzactii. DECLARE emp_id emp.empno%TYPE: BEGIN UPDATE emp SET WHERE empno=emp_id; DELETE FROM emp WHERE SAVEPOINT insert; INSERT INTO emp VALUES (emp_id,); EXCEPTION WHEN DUP_VAL_ON_INDEX THEN ROLLBACK TO insert; END; 135

Limbajul PL/SQL- Interactiunea cu Oracle


SET TRANSACTION DECLARE vinzari_zi REAL; vinzari_saptamina REAL; vinzari_luna REAL; BEGIN COMMIT; SET TRANSACTION READ ONLY; SELECT SUM(cant) INTO vinzari_zi FROM sales WHERE data=SYSDATE; SELECT SUM(cant) INTO vinzari_saptamina FROM sales WHERE data >SYSDATE-7; SELECT SUM(cant) INTO vinzari_luna FROM sales WHERE data>SYSDATE-30; COMMIT; END; 136

Limbajul PL/SQL- Interactiunea cu Oracle


Restrictii -Numai SELECT INTO, OPEN, FETCH, CLOSE, LOCK TABLE, COMMIT si ROLLBACK sunt permise in tranzactii read-only. -Interogarile nu pot contine FOR UPDATE Blocari - Oracle blocheaza linia ce apare pentru UPDATE sau DELETE. - Folosim FOR UPDATE sa blocam toate liniile inainte de comanda UPDATE sau DELETE. - Blocarea intregii tabele cu LOCK TABLE DECLARE CURSOR C1 IS SELECT empno, sal FROM emp WHERE job=saleman AND comm >sal FOR UPDATE NOWAIT; BEGIN OPEN C1; -- toate liniile lui C1 sunt blocate, deblocarea:COMMIT -- sau ROLLBACK 137

Limbajul PL/SQL- Interactiunea cu Oracle


In interogari cu mai multe tabele putem bloca numai linii din anumite tabele. DECLARE CURSOR C1 IS SELECT ename, dname FROM emp, dept WHERE emp.deptno=dept.deptno AND job=MANAGER FOR UPDATE OF sal; In instructiunea UPDATE sau DELETE folosim CURRENT OF: DECLARE CURSOR C1 IS SELECT empno, job, sal FROM emp FOR UPDATE; BEGIN OPEN C1; LOOP FETCH c1 INTO UPDATE emp SET sal =new_sal WHERE CURRENT OF C1; END LOOP; 138

Limbajul PL/SQL- Interactiunea cu Oracle


FETCH si COMMIT. FETCH nu poate urma lui COMMIT. DECLARE CURSOR C1 IS SELECT ename FROM emp FOR UPDATE OF sal; ctr NUMBER:=0; BEGIN FOR emp_rec IN C1 LOOP ctr:=ctr+1; INSERT INTO temp VALUES (ctr,info); IF ctr>=10 THEN COMMIT; END IF; END LOOP; END; 139

Limbajul PL/SQL- Interactiunea cu Oracle


In loc de FOR UPDATE si CURRENT OF ROWID DECLARE CURSOR C1 IS SELECT ename, job, rowid FROM emp; ename1 emp.ename%TYPE; job1 emp.ename%TYPE; rowid1 ROWID; BEGIN OPEN C1; LOOP FETCH C1 INTO ename1, job1, rowid1; EXIT WHEN C1%NOTFOUND; UPDATE emp SET sal=sal *1.1 WHERE ROWID= rowid1; COMMIT; END LOOP; CLOSE C1; END;

140

Limbajul PL/SQL- Interactiunea cu Oracle


Utilizarea atributului %ROWTYPE cu cursori ce refera ROWID DECLARE CURSOR C1 IS SELECT ename, sal, rowid FROM emp; emp_rec C1%ROWTYPE; BEGIN OPEN C1; LOOP FETCH C1 INTO emp_rec; EXIT WHEN C1%NOTFOUND; IF THEN DELETE FROM emp WHERE ROWID=emp_rec.ROWID; END IF; END LOOP; CLOSE C1; END; 141

Limbajul PL/SQL-Subprograme
Proceduri PROCEDURE nume[(p1,p2,)] IS declaratii locale BEGIN instructiuni executabile [EXCEPTION tratarea exceptiilor] END [nume]; p1 [IN|OUT|IN OUT] tip [{:=|DEFAULT} expresie] Nu este permisa restrictia NOT NULL pentru parametri formali. Nu se poate specifica restrictia pe un tip de date: p1 NUMBER(4) Chemarea procedurii: BEGIN nume[(a1,a2,)]; 142

Limbajul PL/SQL-Subprograme
Functii FUNCTION numef [(p1,p2,)] RETURN tip_returnat IS declaratii locale BEGIN instructiuni executabile [EXCEPTION tratarea exceptiilor] END [numef]; P1 [IN|OUT| IN OUT] tip [{:=|DEFAULT } expresie] Apel: numef[(a1,a2,)] ce apare intr-o expresie. Trebuie sa existe instr.RETURN exp; Daca nu exista se produce exceptia: PROGRAM_ERROR Putem declara subprograme in blocuri PL/SQL,subprograme sau pachete, dar in partea finala a sectiunii DECLARE

143

Limbajul PL/SQL-Subprograme
Declaratii forward. PL/SQL cere declararea unui identificator inainte de folosirea lui. DECLARE PROCEDURE P1 IS BEGIN P2(); END; PROCEDURE P2() IS BEGIN END; /* incorect */
144

Limbajul PL/SQL-Subprograme
1) Declaratie forward prin prototip. DECLARE PROCEDURE P2(); --prototipul lui P2 /*Definirea subprogramelor */ PROCEDURE P1 IS BEGIN P2(); END; PROCEDURE P2() IS BEGIN END;
145

Limbajul PL/SQL-Subprograme
In pachete Prototipurile subprogramelor se dau in specificarea pachetului. Corpul subprogramelor se dau in corpul pachetului. Subprograme memorate Crearea si memorarea subprogramelor permanent in baza Oracle se realizeaza prin CREATE PROCEDURE sau CREATE FUNCTION AS , date intr-un script SQL. Parametrii actuali si formali trebuie sa aiba tipuri compatibile. Altfel se produce eroarea: VALUE_ERROR Lista parametrilor in apel: notatie pozitionala, sau cu nume p1=>expresie Modurile IN, OUT, IN OUT p1 IN p1:= expresie; --eroare de sintaxa Parametrul actual pentru p1 de tip OUT trebuie sa fie o variabila. 146

Limbajul PL/SQL-Subprograme
Parametrii actuali corespunzatori parametrilor formali IN OUT trebuie sa fie variabile. Valori default PROCEDURE PR1 (p1 DEFAULT v1,p2 DEFAULT v2,); La apel: PR1; PR1(w1); PR1(w1,w2); PR1(w1,w2,,pi=>wi,); Trecerea parametrilor prin valoare si prin referinta Tipurile compuse se trec prin referinta. Supraincarcarea subprogramelor Putem da acelasi nume pentru diferite subprograme, lista parametrilor lor formali difera in numar, ordine sau familie de tip
147

Limbajul PL/SQL-Subprograme
DECLARE TYPE Tip_data IS TABLE OF DATE INDEXED BY BINARY_INTEGER; TYPE Tip_real IS TABLE OF REAL INDEXED BY BINARY_INTEGER; tabela_date Tip_data; tabela_salarii Tip_real; PROCEDURE initializare (tab OUT tip_data, n INTEGER) IS BEGIN FOR i IN 1..n LOOP tab(i) := SYSDATE; END LOOP; END initializare;
148

Limbajul PL/SQL-Subprograme
PROCEDURE initializare (tab OUT Tip_real, n INTEGER) IS BEGIN FOR i IN 1..n LOOP tab(i) := 0.0; END LOOP; END initializare; DECLARE TYPE Tip_data IS TABLE OF DATE INDEX BY TYPE Tip_real IS TABLE OF REAL INDEX BY Tabela1 Tip_data; Tabela2 Tip_real; nr BINARY_INTEGER :=10; BEGIN initializare(Tabela1,nr); initializare(Tabela2,nr); END;

149

Limbajul PL/SQL-Subprograme
Restrictii - Numai subprogramele locale sau incluse in pachete pot fi supraincarcate - Nu putem supraincarca subprogramele ce difera numai prin nume sau modul IN, OUT, IN OUT. - Nu putem supraincarca subprograme ce difera numai in tipul de date, dar aceste tipuri sunt din aceeasi familie. - Nu putem supraincarca subprograme daca parametrii formali difera numai in subtip, dar aceste subtipuri sunt definite prin subtipuri din aceeasi familie. DECLARE SUBTYPE D1 IS CHAR; SUBTYPE Text IS LONG; PROCEDURE PR1 (z D1) IS BEGIN PROCEDURE PR1(z Text) IS 150

Limbajul PL/SQL-Subprograme
- Nu putem supraincarca doua functii ce difera numai in tipul returnat, chiar daca aceste tipuri sunt din aceeasi familie. Functiile standard PL/SQL declara functiile stadard in pachetul STANDARD. Redeclararea lor local produce eroare. DECLARE X NUMBER; BEGIN DECLARE FUNCTION SIGN (n NUMBER) RETURN NUMBER IS BEGIN IF n<0 THEN RETURN 1 ELSE RETURN 1; END IF; END; BEGIN X:= SIGN(0); -- X ia valoarea 1 151

Limbajul PL/SQL-Subprograme
END; X:= SIGN(0); -- X ia valoarea 0 END; Pentru a chema o functie standard folosim notatia STANDARD.numef X:= STANDARD.SIGN(0); -- X ia valoarea 0. Recursie Cu fiecare chemare a unui program recursiv se creaza o noua instanta a tuturor elementelor declarate in program: parametri, variabile, cursori, exceptii, instructiuni SQL. Daca subprogramul are cursor FOR LOOP, sau instructiuni OPEN, CLOSE, atunci e posibil sa se depasesca limita setata de parametrul OPEN_CURSORS. Daca subprogramul executa la infinit va apare eroarea: STORAGE_ERROR.
152

Limbajul PL/SQL-Subprograme
FUNCTION factorial (n POSITIVE) RETURN INTEGER IS BEGIN IF n=1 THEN RETURN 1; ELSE RETURN n*factorial(n-1); END IF; END factorial; Recursie mutuala FUNCTION impar (n NATURAL) RETURN BOOLEAN; FUNCTION par (n NATURAL) RETURN BOOLEAN IS BEGIN IF n=0 THEN RETURN TRUE; ELSE RETURN IMPAR(n-1); END IF; END par;

153

Limbajul PL/SQL-Subprograme
FUNCTION impar (n NATURAL) RETURN BOOLEAN IS BEGIN IF n=0 THEN RETURN FALSE; ELSE RETURN par(n-1); END IF; END impar; Versiune recursiva -> versiune iterativa.

154

Limbajul PL/SQL-Pachete
Un pachet este o schema de obiect ce grupeaza tipuri, variabile, subprograme, cursori. Are 2 parti: o specificatie si un corp. Pachetele nu pot fi chemate, parametrizate sau imbricate. CREATE PACKAGE numepachet AS -- tipuri si variabile -- specificatii de subprograme END [numepachet]; CREATE PACKAGE BODY numepachet AS --corpul -- declaratii de tip si variabile -- corpuri de subprograme BEGIN --instructiuni END [numepachet];

155

Limbajul PL/SQL-Pachete
Specificatia pachetului contine declaratii publice. Referirea la tipuri, variabile, subprograme dintr-un pachet se face: nume_pachet.nume_tip nume_pachet.nume_variabla

nume_pachet.nume_subprogram Putem referi continutul unui pachet din subprogram memorat, aplicatie OCI, SQL Plus. SQL> EXECUTE nume_pachet.nume_procedura(a1,a2,); Corpul pachetului contine definitia fiecarui cursor si subprogram declarate in specificatia pachetului. Declaratiile de tipuri si variabile sunt accesibile numai in interiorul pachetului. Putem avea supraincarcarea subprogramelor in cadrul unui pachet. Pachetul STANDARD defineste tipurile, exceptiile, subprogramele disponibile pentru programe PL/SQL. Ex.ABS, STANDARD.ABS 156

Limbajul PL/SQL-Pachete
Pachete specifice: - DBMS_STANDARD -interactiunea cu Oracle ex. Raise_application_error -DBMS_OUTPUT -- afisam iesirea din blocuri PL/SQL, procedura PUT_LINE, GET_LINE - DBMS_PIPE -- permite diferitelor sesiuni sa comunice cu diferite zone pack_message, send_message, receive_message, unpack_message - UTL_FILE permite programelor PL/SQL sa citeasca si sa scrie fisiere text ale sistemului de operare. fopen, put_line, get_line - UTL_HTTP permite programelor PL/SQL sa faca chemari HTTP, se pot prelua date din internet. -DBMS_SQL permite executia comenzilor SQL - DBMS_ALERT permite utilizarea trigerilor pentru a alerta o aplicatie cind se schimba anumite valori in baza de date.
157

Limbajul PL/SQL- Obiecte


Object Type and Objects (Instances)

158

Limbajul PL/SQL- Obiecte


Structura unui tip obiect

159

Limbajul PL/SQL- Obiecte


CREATE TYPE tip_obiect AS OBJECT( var1 tip1, var2 tip2, MEMBER FUNCTION f1(lista1) RETURN tipf1, MEMBER FUNCTION f2(lista2) RETURN tipf2, MEMBER PROCEDURE p1(lista21), MEMBER PROCEDURE p2(lista22), ); CREATE TYPE BODY tip_obiect AS MEMBER FUNCTION f1(lista1) RETURN tipf1 IS BEGIN END f1; END;

160

Limbajul PL/SQL- Obiecte


Componentele unui tip obiect Atributele: nume si tip. Tip diferit de: LONG, LONG RAW, NCHAR, NCLOB, NVARCHAR2, MLSLABEL, ROWID, BINARY_INTEGER, RECORD, REF CURSOR, %TYPE, %ROWTYPE, tipuri definite in pachete. - Nu se poate initializa un atribut prin asignare sau DEFAULT. - Nu putem impune NOT NULL pe un atribut. - Obiectele pot fi memorate in tabele pe care se pot impune NOT NULL> Metodele = subprograme precedate de MEMBER sau STATIC. Fiecare metoda are o specificare si un corp. Intr-un tip obiect, metodele pot referi atribute si alte metode fara a folosi calificarea. 161

Limbajul PL/SQL- Obiecte


Parametrul SELF: Orice metoda a unui tip obiect accepta o instanta a acelui tip drept prim parametru. Numele acestui parametru este SELF. Indiferent daca SELF este sau nu declarat, el este mereu primul parametru de apel al metodei. In functii membru SELF nedeclarat este de tip IN, in proceduri nedeclarat el este de tip IN OUT. Nu se specifica tipul lui SELF. In corpul metodei SELF specifica obiectul pentru care a fost apelata metoda. Metodele statice nu accepta sau refera SELF, ele se adreseaza tipului obiect si nu unui obiect. CREATE FUNCTION cmmdc(x INTEGER, y INTEGER) RETURN INTEGER AS z INTEGER; BEGIN IF( y<=x) AND (x MOD y =0) THEN z:=y; ELSIF x<y THEN z:=cmmdc(y,x); END IF; RETURN z; END; 162

Limbajul PL/SQL- Obiecte


CREATE TYPE Rational AS OBJECT( numarator INTEGER, numitor INTEGER, MEMBER PROCEDURE normalizare, ) / CREATE TYPE BODY Rational AS MEMBER PROCEDURE IS g INTEGER; BEGIN g:=cmmdc(SELF.numarator,SELF.numitor); --sau g:=cmmdc(numarator,numitor); numarator:=numarator/g; numitor:=numitor/g; END normalizare; END;

163

Limbajul PL/SQL- Obiecte


Supraincarcarea. Metodele de acelasi tip(proceduri sau functii) pot fi supraincarcate. Nu se pot supraincarca doua metode daca parametrii formali difera numai in modul parametru. Nu putem supraincarca doua functii membru ce difera numai in tipul returnat. Metodele ORDER si MAP Tipurile de date scalare (CHAR, REAL,..) au o ordine predefinita, ce permite compararea lor. Instantele obiectelor nu au o ordine predefinita. Vom folosi metoda MAP. CREATE TYPE Rational AS OBJECT ( numarator INTEGER, numitor INTEGER, MAP MEMBER FUNCTION conversie RETURN REAL; ); 164

Limbajul PL/SQL- Obiecte


CREATE TYPE BODY Rational AS MAP MEMBER FUNCTION conversie RETURN REAL IS -- conversie obiect Rational la un numar REAL BEGIN RETURN numarator/numitor; END conversie; END; Ordonarile sunt necesare in realizarea clauzelor DISTINCT, GROUP BY, ORDER BY. Un tip obiect poate contine numai o metoda MAP, cu tipul returnat unul din: DATE, NUMBER, VARCHAR2, CHARACTER, REAL. Putem folosi metoda ORDER, cu doi parametri: primul SELF, al doilea de acelasi tip. 165

Limbajul PL/SQL- Obiecte


O comparare a doua obiecte implica automat invocarea metodei definite de ORDER. CREATE TYPE Student AS OBJECT ( marca NUMBER, nume VARCHAR2(15), adresa VARCHAR2(20), ORDER MEMBER FUNCTION comparare (par2 Student) RETURN INTEGER ); CREATE TYPE BODY Student AS ORDER MEMBER FUNCTION comparare (par2 Student) RETURN INTEGER ) IS BEGIN IF marca<par2.marca THEN RETURN 1; ELSIF marca > par2.marca THEN RETURN 1; ELSE RETURN 0; END IF; END; END; 166

Limbajul PL/SQL- Obiecte


Metoda constructor Fiecare tip obiect are o metoda constructor, folosita pentru initializarea si returnarea unei instante de tipul respectiv. Parametrii formali ai constructorului au acelasi tip cu atributele obiectului. Putem defini metode constructor proprii prin supraincarcarea constructorului sistem sau definind noi functii cu signatura diferita. Apelul constructorului trebuie facut explicit de catre program. Modificarea atributelor si metodelor unui tip existent: ALTER TYPE pentru adaugare, modificare, stergere atribute, adaugare, stergere metode pentru un tip existent. ALTER TYPE tip_obiect ADD ATTRIBUTE (nume1 tip1, ) CASCADE; ALTER TYPE tip_obiect DROP ATTRIBUTE nume1,.. ; 167

Limbajul PL/SQL- Obiecte


Declararea obiectelor Dupa definirea tipului obiect,acesta poate fi utilizat sa declare obiecte in blocuri PL/SQL, subprograme, pachete. In bloc sau subprogram, la intrare se creaza obiecte, care se sterg la iesire. In pacete obiectele se instantiaza la prima referire si se sterg la sfirsitul sesiunii. DECLARE nume_obiect tip_obiect; Putem declara obiectele ca parametri formali ai functiilor sau procedurilor: PROCEDURE nume_p (par1 IN OUT tip_obiect) IS FUNCTION nume_f (lista) RETURN tip_obiect IS Initializarea obiectelor: Inainte de initializare un obiect este atomic null. Compararea unui obiect null cu altul produce NULL. nume_ob1:=nume_ob2; nume_ob:=NULL; nume_obiect tip_obiect:= constructor 168

Limbajul PL/SQL- Obiecte


In expresii atributele unui obiect neinitializat au valoarea NULL.

nume_obiect.atribut:=expresie; cind nume_obiect este neinitializat produce ACCES_INTO_NULL. Apel de metoda cu obiect neintializat este permis, SELF este NULL. nume_obiect neinitializat ca parametru formal IN atributele NULL. Cind OUT sau IN OUT apare exceptia daca se asigneaza. Referinta la atribute: nume_obiect.atribut Apelul constructorului implica definirea de valori initiale atributelor (nu se poate folosi DEFAULT). Putem folosi notatia pozitionala. Apelul metodelor: nume_obiect.metoda(a1,); -- sau inlantuiri de chemari de metode. In instructiuni procedurale lista vida este optionala, dar in apel inlantuit trebuie dat () pentru functii. o.f1().F2() prima trebuie sa returneze un obiect. 169

Limbajul PL/SQL- Obiecte


Tipuri obiecte imbricate CREATE TYPE Adresa AS OBJECT ( strada VARCHAR2(20), oras VARCHAR2(15), codpostal INTEGER ) / CREATE TYPE persoana AS OBJECT ( nume VARCHAR2(20), prenume VARCHAR2(20), datanasterii DATE, adresa_domiciliu Adresa, telefon VARCHAR2(12) ) / Un obiect are un identificator de obiect. Vom utiliza REF care este pointer la un obiect. Procesul sharing. Avantaje: nereplicare si modificarea unui obiect implica actualizarea referintelor. CREATE TYPE persoana AS OBJECT ( nume VARCHAR2(20), prenume VARCHAR2(20), datanasterii DATE, adresa_domiciliu Adresa, telefon VARCHAR2(12) , tata REF persoana, mama REF persoana) 170

Limbajul PL/SQL- Obiecte


Putem declara REF pentru variabile, parametri, cimpuri, atribute, variabile de intrare/iesire in instructiuni SQL. Nu putem naviga prin aceste elemente REF: nume_referinta.atribut --nu poate specifica obiectul referit. DEREF Definitii forward de tip: CREATE TYPE Emp AS OBJECT ( nume VARCHAR2(15), dept REF departament, --incorect ) CREATE TYPE departament AS OBJECT ( numar INTEGER, manager Emp,) CREATE TYPE departament; -- definitie forward tip obiect incomplet. CREATE TYPE Emp AS OBJECT Putem folosi tip de obiect in CREATE TABLE, INSERT, nume de Metode in UPDATE CREATE TABLE Tab1 OF Rational --tabela de obiecte 171

Limbajul PL/SQL- Obiecte


Tratarea obiectelor neinitializate

In expresii atributele unui obiect neinitializat sunt evaluate la NULL. Asignarea de valori pentru un atributele unui obiect neinitializat produce exceptia ACCESS_INTO_NULL. Operatorul IS NULL aplicat obiectului neinitializat sau atributelor acestuia da TRUE. DECLARE rat Rational; -- rat este atomic null BEGIN IF rat IS NULL THEN --expresia este TRUE IF rat.numarator IS NULL THEN -- TRUE rat:=Rational(NULL,NULL); -- initializeaza rat rat.numarator:=10; -- nu produce exceptie rat:=NULL; -- rat devine atomic nul rat.numarator:=20; -- produce exceptia ACCESS_INTO_NULL EXCEPTION WHEN ACCESS_INTO_NULL THEN .. END; 172

Limbajul PL/SQL- Obiecte


Definitii de tip forward CREATE TYPE Emp AS OBJECT ( nume VARCHAR2(15), dept REF departament, --incorect ); CREATE TYPE departament AS OBJECT ( numar INTEGER, manager Emp, );

CREATE TYPE departament; -- definitie forward inainte de Emp departament tip incomplet tip obiect incomplet are atribute dar se refera la tipuri nedefinite CREATE TABLE nume_tabela OF tip_obiect -- tabela de obiecte O linie in tabela de obiecte are un identificator de obiect si serveste ca referinta la acel obiect 173

Limbajul PL/SQL- Obiecte


Selectarea obiectelor CREATE TYPE persoana AS OBJECT ( nume VARCHAR2(15), prenume VARCHAR2(15), data_nasterii DATE, adresa Address, telefon VARCHAR2(15) ) / CREATE TABLE persoane OF persoana / BEGIN INSERT INTO emp SELECT * FROM persoane p WHERE p.nume LIKE A%;
174

Limbajul PL/SQL- Obiecte


VALUE returneaza valoarea unui obiect

BEGIN INSERT INTO emp SELECT VALUE(p) FROM persoane p WHERE p.nume LIKE A%; --------------------------------------------------------DECLARE p1 persoane; p2 persoane; BEGIN SELECT VALUE(p) INTO p1 FROM persoane p WHERE p.nume=IONESCU; p2:=p1; p1.nume:=expresie; END;

175

Operatorul REF Variabila corelata= variabila de linie sau alias pentru o tabela de obiecte REF are ca argument o variabila corelata si returneaza referinta. BEGIN INSERT INTO persoane_ref SELECT REF(p) FROM persoane p WHERE p.nume LIKE A%; ------------------------------------------------------DECLARE p_ref REF persoana; telefon VARCHAR2(15); BEGIN SELECT REF(p),p.telefon INTO p_ref, telefon FROM persoane p WHERE p.nume=IONESCU; -- trebuie o singura linie END; 176

Limbajul PL/SQL- Obiecte

Limbajul PL/SQL- Obiecte


DECLARE p_ref REF persoana; wnume VARCHAR2(15); BEGIN SELECT REF(p) INTO p_ref FROM persoane p WHERE p.nume=wnume; UPDATE persoane p SET p= persoana(ION,ION,) WHERE REF(p)= p_ref; END; Referinte dangling (pointeaza la un obiect inexistent), IS DANGLING. BEGIN UPDATE departament SET manager=NULL WHERE manager IS DANGLING;
177

Limbajul PL/SQL- Obiecte


Operatorul DEREF argumentul =referinta la obiect, returneaza valoarea (obiectul) la care pointeaza. Daca ref este dangling, atunci se returneaza obiectul nul. DECLARE p1 persoana; p1_ref REF persoana; wnume VARHAR2(15); BEGIN SELECT REF(p) INTO p1_ref FROM persoane p WHERE p.marca=10; SELECT DEREF(p1_ref) INTO p1 FROM DUAL; wnume:=p1.nume; DBMS_OUTPUT.PUT_LINE(Numele este; ||wnume); END; / 178

Limbajul PL/SQL- Obiecte


Operatorul DEREF poate fi folosit in dereferinte succesive

CREATE TYPE persoanan_ref AS OBJECT (p_ref REF persoana) / CREATE TABLE persoanen_ref OF persoanan_ref / DECLARE wnume VARCHAR2(15); obiect_1 persoanan_ref :=persoanan_ref(NULL); ref_ref_p REF persoanan_ref; p persoana; ref_p REF persoana; ref_p1 persoanan_ref; BEGIN

179

Limbajul PL/SQL- Obiecte


SELECT REF(a) INTO ref_p FROM persoane a WHERE a.marca=10; obiect_1.p_ref:=ref_p; INSERT INTO persoanen_ref VALUES(obiect_1); SELECT REF(c) INTO ref_ref_p FROM persoanen_ref c WHERE c.p_ref=ref_p; SELECT DEREF(ref_ref_p) INTO ref_p1 FROM DUAL; SELECT DEREF(ref_p1.p_ref) INTO p FROM DUAL; wnume:=p.nume; DBMS_OUTPUT.PUT_LINE(wnume); END; /
180

Limbajul PL/SQL- Obiecte


Operatorul DEREF nu poate fi folosit in instructiuni procedurale: P1:=DEREF(p_ref); --incorect In comenzi SQL folosim notatia . Pentru a naviga de la coloane obiect la atribute REF si de la atribute REF la alt atribut REF. alias_tabela.coloana_obiect.atribut_ref alias_tabela.coloana_obiect.atribut_ref.atribut alias_tabela.coloana_ref.atribut CREATE TYPE Address AS OBJECT ( strada VARCHAR2(15), oras VARCHAR2(15), cod_postal INTEGER) / CREATE TYPE Person AS OBJECT (nume VARCHAR2(15),prenume VARCHAR2(15),adresa_dom REF Address,telefon VARCHAR2(15),strada VARCHAR2(15)) / CREATE TABLE persons OF Person / 181

Limbajul PL/SQL- Obiecte


DECLARE addr1 Address; addr2 Address; wstrada VARCHAR2(15); BEGIN SELECT DEREF(adresa_dom) INTO addr1 FROM persons p WHERE p.nume=ION; SELECT p.adresa_dom.strada INTO wstrada FROM persons p WHERE p.prenume=ioana; Inserarea de obiecte INSERT INTO persons VALUES(Person(ION,ioana,)); Utilizam clauza RETURNING sa memoram referinte in variabile locale
182

Limbajul PL/SQL- Obiecte


DECLARE p1_ref REF person; p2_ref REF person; BEGIN INSERT INTO persons p VALUES(Person(IONESCU,dorin,)) RETURNING REF(p) INTO p1_ref; INSERT INTO persons1 SELECT VALUE(p) FROM persons p WHERE p.prenume LIKE A%; UPDATE persons p SET adresa_dom=Iasi. WHERE; DELETE FROM persons p WHERE ;
183

Limbajul PL/SQL- Obiecte


DECLARE p_ref REF Person; wprenume VARCHAR2(15); BEGIN wprenume:=bill; SELECT REF(p) INTO p_ref FROM persons p WHERE p.prenume = wprenume; UPDATE persons p SET p = Person('Jill', 'Anders', '11-NOV-67', ...) WHERE REF(p) = p_ref; END; /
184

Limbajul PL/SQL- Obiecte


Mostenirea tipurilor

CREATE TYPE T1 AS OBJECT () NOT FINAL; CREATE TYPE T2 UNDER T1() {NOT FINAL|FINAL}; T1- supertip(parinte) pentru T2, iar T2 subtip(fiu)al lui T1 FINAL- nu se pot deriva subtipuri din el Subtipul contine toate atributele si metodele tipului parinte si poate contine atribute si metode suplimentare care pot supraincarca metodele tipului parinte. FINAL MEMBER FUNCTION f () in tipul parinte implica imposibilitatea supraincarcarii lui f in orice subtip al celui curent. CREATE TYPE tip_persoana AS OBJECT ( nume VARCHAR2(20),cnp CHAR(13),adresa VARCHAR2(25)) NOT FINAL; CREATE TYPE tip_student UNDER tip_persoana (cod_fac NUMBER) NOT FINAL; CREATE TYPE tip_functionar UNDER tip_persoana(marca NUMBER); CREATE TYPE student1 UNDER tip_student (bursa NUMBER);
185

Limbajul PL/SQL- Obiecte


CREATE TYPE T AS OBJECT (,MEMBER PROCEDURE P1, FINAL MEMBER FUNCTION f1()) NOT FINAL; ----------------------------------------------------------------------------------CREATE TYPE tip_adresa AS OBJECT() NOT INSTANTIABLE NOT FINAL; CREATE TYPE tip_adresa1 UNDER tip_adresa(); CREATE TYPE tip_adresa2 UNDER tip_adresa(); ----------------------------------------------------------------------------------CREATE TABLE person_v OF tip_persoana Operatorul TREAT returneaza obiecte de un tip specificat SELECT TREAT(REF(p) AS REF tip_student); FROM Person_v p; --returneaza referintele persoanelor ce sunt --instante ale subtipului tip_student SELECT REF(p) FROM Person_v p WHERE VALUE(p) IS OF (tip_functionar, tip_student) ; SELECT REF(p) FROM Person_v p WHERE VALUE(p) IS OF(ONLY tip_student); 186

Limbajul PL/SQL- Obiecte


Constructor definit de utilizator CONSTRUCTOR FUNCTION tip_obiect( lista) RETURN SELF AS RESULT CREATE OR REPLACE TYPE paralelipiped AS OBJECT ( -- Tipul are 3 atribute lungime NUMBER, latime NUMBER, inaltime NUMBER,volum NUMBER, -- Definim un constructor cu 3 parametri. CONSTRUCTOR FUNCTION paralelipiped (plungime NUMBER, platime NUMBER,pinaltime NUMBER) RETURN SELF AS RESULT ); / CREATE OR REPLACE TYPE BODY paralelipiped AS CONSTRUCTOR FUNCTION paralelipiped (plungime NUMBER, platime NUMBER,pinaltime NUMBER) RETURN SELF AS RESULT 187

Limbajul PL/SQL- Obiecte


AS BEGIN SELF.lungime := plungime; SELF.latime:= platime; SELF.inaltime:=pinaltime; SELF.volum:=plungime*platime*pinaltime; RETURN; END; END; / DECLARE par1 paralelipiped; par2 paralelipiped; BEGIN par1:=NEW paralelipiped(10,20,30,6000); par2:= NEW paralelipiped(10,20,30);

188

Limbajul PL/SQL- Obiecte


Parametrul SELF Fiecare metoda are primul parametru cu numele SELF. In mod implicit orice atribut necalificat in functie membru sau procedura membru este calificat prin SELF. CREATE OR REPLACE TYPE cladire AS OBJECT ( Numecladire VARCHAR2(40), Adresacladire address, Managercladire INTEGER, MEMBER PROCEDURE SchimbareManager (SELF IN OUT cladire, NouManager IN INTEGER), ORDER MEMBER FUNCTION Comparare (SELF IN cladire, altacladire IN cladire) RETURN INTEGER ) / 189

Limbajul PL/SQL- Obiecte


CREATE OR REPLACE TYPE BODY cladire AS MEMBER PROCEDURE SchimbareManager(SELF IN OUT cladire, NouManager IN INTEGER) IS BEGIN SELF.Managercladire:= NouManager; END; ORDER MEMBER FUNCTION Comparare (SELF IN cladire, altacladire IN cladire) RETURN INTEGER IS Numecladire1 VARCHAR2(40); Numecladire2 cladire.Numecladire%TYPE; BEGIN Numecladire1 := upper(ltrim(rtrim(SELF.Numecladire))); Numecladire2:= upper(ltrim(rtrim(altacladire.Numecladire))); IF Numecladire1 = Numecladire2 THEN RETURN 0; ELSIF Numecladire1 < Numecladire2 THEN RETURN -1; ELSE RETURN 1; END IF; END; END; / 190

Limbajul PL/SQL- Tratarea erorilor


Tratarea erorilor In PL/SQL o eroare este numita exceptie. Exceptiile pot fi predefinite(interne) sau definite de utilizator. Exemple de exceptii predefinite: division by zero, out of memory . ZERO_DIVIDE and STORAGE_ERROR. Exceptiile interne sunt activate automat. Exceptiile utilizator sunt activate de instructiuni RAISE. SET SERVEROUTPUT ON; DECLARE pret_stoc NUMBER := 9.73; Pret_vinzare NUMBER := 0; Coeficient NUMBER; BEGIN coeficient:= pret_stoc / pret_vinzare; dbms_output.put_line('Pretul stoc/pret vinzare = ' ||coeficient); EXCEPTION prelucrarea exceptiilor BEGIN
191

Limbajul PL/SQL- Tratarea erorilor


WHEN ZERO_DIVIDE THEN --tratarea impartirii prin zero dbms_output.put_line(Pretul de vinzare este zero'); coeficient:= NULL; WHEN OTHERS THEN -- tratarea altor erori dbms_output.put_line(Alte tipuri de erori:'); coeficient := null; END; END;

/ BEGIN coeficient := CASE pret_vinzare WHEN 0 THEN NULL ELSE pret_stoc/ pret_vinzare END; END; /

192

Limbajul PL/SQL- Tratarea erorilor


Avantajele exceptiilor Fara rutina de prelucrare a exceptiilor, cind se executa o comanda trebuie sa vedem daca nu au aparut situatii de eroare: BEGIN SELECT INTO --verificarea daca nu a aparut eroare SELECT INTO --verificarea daca nu a aparut eroare END; BEGIN SELECT SELECT SELECT EXCEPTION WHEN NO_DATA_FOUND THEN --tratarea tuturor erorilor no data found 193

Limbajul PL/SQL- Tratarea erorilor


Exception Oracle Error 1.ACCESS_INTO_NULL ORA-06530 2.CASE_NOT_FOUND ORA-06592 3.COLLECTION_IS_NULL ORA-06531 4.CURSOR_ALREADY_OPEN ORA-06511 5.DUP_VAL_ON_INDEX ORA-00001 6.INVALID_CURSOR ORA-01001 7.INVALID_NUMBER ORA-01722 8.LOGIN_DENIED ORA-01017 9.NO_DATA_FOUND ORA-01403 10.NOT_LOGGED_ON ORA-01012 11.PROGRAM_ERROR ORA-06501 12.ROWTYPE_MISMATCH ORA-06504 13.SELF_IS_NULL ORA-30625 14.STORAGE_ERROR ORA-06500 SQLCODE Value -6530 -6592 -6531 -6511 -1 -1001 -1722 - 1017 +100 -1012 -6501 - 6504 -30625 194 -6500

Limbajul PL/SQL- Tratarea erorilor


15.SUBSCRIPT_BEYOND_COUNT ORA-06533 -6533 16.SUBSCRIPT_OUTSIDE_LIMIT ORA-06532 -6532 17.SYS_INVALID_ROWID ORA-01410 -1410 18.TIMEOUT_ON_RESOURCE ORA-00051 -51 19.TOO_MANY_ROWS ORA-01422 -1422 20.VALUE_ERROR ORA-06502 -6502 21.ZERO_DIVIDE ORA-01476 -1476 ------------------------------------------------------------------------------------1.Programul asigneaza valori la un atribut al unui obiect neinitializat. 2.Nu s-a selectat niciun WHEN din CASE si nu exista clauza ELSE. 3.Programul aplica o metoda(alta decit EXISTS) la o colectie neinitializata sau se asigneaza valori la elementele colectiei neinitializata. 4.Programul incearca sa deschida un cursor deja deschis. Un cursor FOR LOOP este deschis automat.
195

Limbajul PL/SQL- Tratarea erorilor


5.Programul incearca sa memoreze valori duplicate ale cimpului cu restrictia PRIMARY KEY sau UNIQUE KEY. 6.Programul incearca o operatie nepermisa pe un cursor, de ex. Inchiderea unui cursor nedeschis. 7.Conversia unui sir de caractere la un numar esueaza,deoarece sirul nu are numai caractere numerice(pentru instr.SQL).Pentru instructiuni procedurale eroarea:VALUE_ERROR. Exceptia apare si cind expresia LIMIT din FETCH cu BULK COLLECTION nu se evalueaza la un numar pozitiv. 8.Programul incearca o logare la Oracle cu nume sau password gresit. 9.Instr. SELECT INTO nu returneaza nicio linie sau programul refera un element sters dintr-o tabela nested sau un element neinitializat dintr-o tabela index by. 10.Programul face o chemare de baza de date fara a fi conectat la Oracle. 11.PL/SQL are o problema interna.
196

Limbajul PL/SQL- Tratarea erorilor


12.Variabila cursor intr-o asignare returneaza valori in variabile de tipuri diferite de elementele cursorului. 13.Programul incearca chemarea unei metode cu un obiect neinitializat. 14.PL/SQL executa in afara memoriei sau memoria a fost corupta. 15.Programul face referinta la un element al unei colectii folosind un indice mai mare decit numarul elementelor colectiei. 16. .Programul face referinta la un element al unei colectii folosind un indice in afara domeniului declarat pentru elementele colectiei. 17.Conversia unui sir de caractere la ROWID esueaza deoarece sirul nu este un ROWID corect. 18.S-a depasit timpul de cind Oracle asteapta o resursa. 19.O instructiune SELECT INTO returneaza cel putin 2 linii. 20.A aparut o eroare in evaluarea unei expresii aritmetice, de conversie, de trunchiere sau din cauza unei restrictii de dimensiune. 21.Programul incearca o impartire prin zero. 197

Limbajul PL/SQL- Tratarea erorilor


Definirea exceptiilor utilizator -Declararea in partea declarativa a unui bloc PL/SQL, subprogram sau pachet: DECLARE nume_exceptie EXCEPTION; --nume_exceptie nu poate sa apara in asignari sau instructiuni SQL. --nu se poate declara o exceptie de 2 ori in acelasi bloc, dar aceeasi exceptie poate sa apara in blocuri diferite. --exceptiile declarate intr-un bloc sunt locale acelui bloc si globale pentru toate subblocurile acelui bloc. --daca redeclaram exceptia globala intr-un subbloc, atunci cea locala are prioritate, subblocul va putea referi exceptia globala in forma : nume_bloc.nume_exceptie DECLARE excep1 EXCEPTION; nrcont NUMBER; BEGIN 198

Limbajul PL/SQL- Tratarea erorilor


DECLARE --inceput subbloc excep1 EXCEPTION; --are prioritate nrcont NUMBER; BEGIN IF THEN RAISE excep1; -- nu este prelucrata END IF; END; -sfirsitul subblocului EXCEPTION WHEN excep1 THEN --nu este prelucrata exceptia lansata de RAISE END; - -RAISE si WHEN se refera la nume diferite
199

Limbajul PL/SQL- Tratarea erorilor


Pragma EXCEPTION_INIT Pentru prelucrarea exceptiilor interne folosim WHEN OTHERS.. Sau pragma EXCEPTION_INIT. O pragma este o directiva de compilare. In PL/SQL pragma EXCEPTION_INIT asociaza un nume_exceptie cu un numar de eroare Oracle, ceeace permite referirea la exceptie prin nume. DECLARE nume_exceptie EXCEPTION; PRAGMA EXCEPTION_INIT(nume_exceptie,-50); BEGIN EXCEPTION WHEN nume_exceptie THEN --prelucrarea erorii END;
200

Limbajul PL/SQL- Tratarea erorilor


Definirea propriilor mesaje de eroare RAISE_APPLICATION_ERROR(numar_eroare,mesaj [,{TRUE|FALSE}]); numar_eroare [-20000,-20999], lungime(mesaj)<=2048. Apelul se realizeaza numai dintr-un subprogram memorat. Apelul ei determina terminarea subprogramului si returmarea unui numar de eroare si mesaj. CREATE PROCEDURE crestere_salariu (emp_id NUMBER,rata NUMBER) AS salariu_actual NUMBER; BEGIN SELECT sal INTO salariu_actual FRM emp WHERE empno=emp_id; IF salariu_actual IS NULL THEN RAISE_APPLICATION_ERROR(-20100,Lipseste salariul); ELSE 201

Limbajul PL/SQL- Tratarea erorilor


UPDATE emp SET sal=salariu_actual+rata WHERE empno=emp_id; END IF; END crestere_salariu; / Lansarea exceptiilor-RAISE DECLARE exceptie_stoc EXCEPTION; cantmin_stoc NUMBER(5); BEGIN IF cantmin_stoc <1000 THEN RAISE exceptie_stoc; END IF; EXCEPTION WHEN exceptie_stoc THEN --prelucreaza eroarea END; 202

Limbajul PL/SQL- Tratarea erorilor

Putem lansa explicit erorile predefinite prin: RAISE nume_exceptie: DECLARE nr1 INTEGER; BEGIN IF nr1 NOT IN (1,2,3,4) THEN RAISE INVALID_NUMBER; END IF: EXCEPTION WHEN INVALID_NUMBER THEN ROLLBACK; END;
203

Limbajul PL/SQL- Tratarea erorilor


Propagarea exceptiilor

204

Limbajul PL/SQL- Tratarea erorilor

205

Limbajul PL/SQL- Tratarea erorilor

206

Limbajul PL/SQL- Tratarea erorilor


Nu putem avea: EXCEPTION WHEN nume_exceptie. unde nume_exceptie este definit intr-un subbloc al blocului curent. Totusi daca folosim WHEN OTHERS THEN exceptia definita intr-un subbloc se propaga in blocul inclus. BEGIN DECLARE except1 EXCEPTION; BEGIN IF THEN RAISE except1; END IF; END; EXCEPTION WHEN OTHERS THEN ROLLBACK; END; 207

Limbajul PL/SQL- Tratarea erorilor


Relansarea unei exceptii: DECLARE eroare1 EXCEPTION; BEGIN BEGIN IF conditie THEN RAISE eroare1; END IF; EXCEPTION WHEN eroare1 THEN -- prelucrarea erorii RAISE; relansarea exceptiei curente END;

208

Limbajul PL/SQL- Tratarea erorilor


EXCEPTION WHEN eroare1 THEN --prelucrarea erorii altfel decit in subbloc. END; Prelucrarea lansarii exceptiilor: EXCEPTION WHEN eroare1 THEN sir1 WHEN eroare2 THEN sir2 WHEN OTHERS THEN sir
209

Limbajul PL/SQL- Tratarea erorilor


EXCEPTION WHEN eroare1 OR eroare2 OR OR VALUE_ERROR THEN Cind exceptia este ridicata in FOR cursorul este inchis. Exceptiile din declaratii: DECLARE constanta1 CONSTANT NUMBER(2):=200; BEGIN EXCEPTION WHEN OTHERS THEN -- nu poate capta exceptia Exceptiile ce apar in handleri EXCEPTION WHEN INVALID_NUMBER THEN INSERT INTO 210 WHEN DUP_VAL_ON_INDEX THEN--nu poate fi captata exceptia

Limbajul PL/SQL- Tratarea erorilor


GOTO nu poate face saltul spre un handler si nici din handler spre blocul curent. Totusi GOTO poate face salt de la un handler intr-un bloc superior. Folosirea lui SQLCODE si SQLERRM. Pentru exceptiile definite de utilizator, SQLCODE este +1 si SQLERRM da: User-Defined Exception, daca nu folosim pragma EXCEPTION_INIT. Daca nicio exceptie nu apare, SQLCODE este 0 si SQLERRM da ORA-0000:normal, successful completion. SQLERRM(cod_eroare)returneaza mesajul erorii. cod_eroare>0 User_Defined Exception - Nu putem folosi SQLCODE , SQLERRM direct in instructiuni SQL. DECLARE cod_er NUMBER; mesaj_er VARCHAR2(100); BEGIN EXCEPTION WHEN OTHERS THEN cod_er:=SQLCODE; mesaj_er :=SQLERRM;
211

Limbajul PL/SQL- Tratarea erorilor


Tehnici de crestere a flexibilitatii 1. Continuarea dupa ce apare exceptia. DECLARE coeficient NUMBER(3,1); BEGIN DELETE FROM stare WHERE symbol=XYZT; SELECT pret/NVL(cistig,0) INTO coeficient FROM stocuri WHERE symbol=XYZT; INSERT INTO stare(symbol, coeficient) VALUES (XYZT,coeficient); EXCEPTION WHEN ZERO_DIVIDE THEN -------------------------------------------------------------------------------DECLARE coeficient NUMBER(3,1); BEGIN 212

Limbajul PL/SQL- Tratarea erorilor


DELETE FROM stare WHERE symbol =XYZT; BEGIN SELECT pret/NVL(cistig,0) INTO coeficient FROM stocuri WHERE symbol =XYZT; EXCEPTION WHEN ZERO_DIVIDE THEN coeficient:=0; END; INSERT INTO stare(symbol,coeficient) VALUES (XYZT, coeficient); EXCEPTION
213

Limbajul PL/SQL- Tratarea erorilor


Reincercarea unei tranzactii: DECLARE nume CHAR(20); ans1 CHAR(5); ans2 CHAR(5); ans3 CHAR(5); I NUMBER :=1; BEGIN LOOP BEGIN SAVEPOINT start_transaction; DELETE FROM result WHERE raspuns=NO; INSERT INTO result VALUES (nume,ans1,ans2,ans3); COMMIT; EXIT; EXCEPTION WHEN DUP_VAL_ON_INDEX THEN ROLLBACK TO start_transaction; 214

Limbajul PL/SQL- Tratarea erorilor


nume:=nume||TO_CHAR(I); I:=I+1; END; END LOOP; END; Folosirea variabilelor locator. BEGIN SELECT SELECT SELECT EXCEPTION WHEN NO_DATA_FOUND THEN END;
215

Limbajul PL/SQL- Tratarea erorilor


DECLARE I INTEGER :=1; BEGIN SELECT I:=2; SELECT I:=3; SELECT EXCEPTION WHEN NO_DATA_FOUND THEN INSERT INTO errors VALUES(Eroare in instructiunea:||I); END; 216

Restrictii de integritate
ALTER TABLE Dept ADD PRIMARY KEY (Deptno); ALTER TABLE Emp ADD FOREIGN KEY (Deptno) REFERENCES Dept(Deptno); Crearea indecsilor. - Orice cheie unica sau primara cere un index. - Cheile unice sau primare pot folosi indecsi unici sau neunici. - Cel mult o cheie unica sau primara poate folosi un index neunic. - Ordinea coloanelor in index si ordinea coloanelor din restrictie nu trebuie sa fie aceeleasi. - Noi trebuie sa indexam cheile straine. NOT NULL - Implicit toate coloanele sunt de tip NULL. - Orice cimp din PRIMARY KEY trebuie sa fie cu NOT NULL.
217

Ex.

Restrictii de integritate
ALTER TABLE Emp MODIFY ename NOT NULL; Cheie primara: - Fiecare tabela trebuie sa aiba o cheie primara, ce identifica fiecare linie din tabela. - Folosim o coloana ce contine un numar de secventa. - Alegem o coloana pentru care valorile ei sunt unice. - Datele unei coloane ce defineste cheia primara trebuie sa fie neschimbabile. - O cheie primara nu contine valori nule. - Alegem o coloana care este de mica dimensiune si numerica. - Evitam folosirea cheilor primare compuse. Cheie unica: - Putem defini cheie unica pentru orice coloana care nu permite chei duplicate(dar ea poate fi de tip NULL).
218

Restrictii de integritate
- Nu putem avea valori identice in coloanele NOT NULL ale unei chei compuse UNIQUE - Restrictia de tip cheie unica permite NULL. Restrictii de integritate referentiala: Fie doua tabele T1 cu restrictia PRIMARY sau UNIQUE pe coloana col1 si tabela T2 cu restrictia FOREIGN pe cimpul col2. Cimpurile col1 si col2 echivalente semantic. - Pentru fiecare valoare v a lui col2 din tabela T2 trebuie sa existe o linie din T1 care are valoarea v in atributul col1. In cazul cheilor compuse, sirul de coloane din cheia primara sau unica trebuie sa aiba acelasi tip cu sirul de coloane din cheia FOREIGN. - Numarul atributelor din cheia compusa <=32. - Cheile FOREIGN permit valori toate NULL, deci in acest caz nu cupleaza cu o valoare a cheii unice sau primare.
219

Restrictii de integritate - Prin default(fara niciun NOT NULL sau CHECK) FOREIGN KEY
specifica regula fara cuplare pentru chei straine compuse in modul ANSI/ISO. - Regula cuplare completa pentru valori NULL in cheia compusa va cere ca toate componentele cheii sa fie NULL sau toate sa fie NOT NULL. Pentru aceasta vom folosi restrictia CHECK: CHECK ((cimp1 IS NULL AND cimp2 IS NULL) OR (cimp1 IS NOT NULL AND cimp2 IS NOT NULL)) Relatii intre tabelele T1 si T2. T1-parinte, T2-copil: 1)Fara restrictii pe cheia FOREIGN: Mai multe linii din tabela copil pot referi aceeasi linie din tabela parinte. Se permite valori NULL ale cheii FOREIGN. Rezulta o functie 1-n intre T1 si T2 . Fiecare departament are mai multi functionari, pot exista functionari pentru care nu se cunoaste 220 departamentul-are valoarea NULL in cheia FOREIGN.

Restrictii de integritate
2) Restrictia NOT NULL pe cheia FOREIGN: Fiecare linie din tabela copil trebuie sa refere o linie din tabela parinte. Un numar oarecare de linii din tabela copil pot referi aceeasi linie din tabela parinte. 3) Restrictia UNIQUE pe cheia straina: Se permite NULL pe cheia straina, dar o singura linie din tabela copil poate referi o linie data a tabelei parinte. Ex. CREATE TABLE Insurance(Memberno Number,, CONSTRAINT c3 PRIMARY KEY(Memberno)); CREATE TABLE Emp1(Memberno NUMBER,.. CONSTRAINT c1 UNIQUE KEY(Memberno), CONSTRAINT c2 FOREIGN KEY(Memberno) REFERENCES (Insurance.Memberno));
221

Restrictii de integritate
4) Restrictia UNIQUE si NOT NULL pe cheia straina: O singura linie din tabela copil refera o linie data din tabela parinte si fiecare linie din tabela copil trebuie sa refere o linie in tabela parinte. 5) Reguli pentru restrictii FOREIGN KEY multiple. - Cind o restrictie nu este satisfacuta se semnaleaza o eroare. Putem folosi SET CONSTRAINTS pentru realizarea verificarii restrictiei la sfirsitul tranzactiei. Operatia este numita aminarea verificarii restrictiei. SET CONSTRAINTS{ ALL/r1,r2,..rh} {IMMEDIATE/DEFERRED}; CREATE TABLE numet (,CONSTRAINT c1 DEFERRABLE,.. Asigurarea ca restrictiile au fost definite ca aminabile.(FOREIGN, UNIQUE, PRIMARY KEY).
222

Restrictii de integritate
CREATE TABLE dept ( deptno NUMBER PRIMARY KEY, dname VARCHAR2 (30) ); CREATE TABLE emp ( empno NUMBER, ename VARCHAR2 (30), deptno NUMBER REFERENCES (dept), CONSTRAINT epk PRIMARY KEY (empno) DEFERRABLE, CONSTRAINT efk FOREIGN KEY (deptno) REFERENCES (dept.deptno) DEFERRABLE); INSERT INTO dept VALUES (10, 'Accounting'); INSERT INTO dept VALUES (20, 'SALES'); INSERT INTO emp VALUES (1, 'Corleone', 10); INSERT INTO emp VALUES (2, 'Costanza', 20); COMMIT; SET CONSTRAINT efk DEFERRED;
223

Restrictii de integritate
UPDATE dept SET deptno = deptno + 10 WHERE deptno = 20; SELECT * from emp ORDER BY deptno; EMPNO ENAME DEPTNO ----- -------------- ------1 Corleone 10 2 Costanza 20 UPDATE emp SET deptno = deptno + 10 WHERE deptno = 20; SELECT * FROM emp ORDER BY deptno; EMPNO ENAME DEPTNO ----- -------------- ------1 Corleone 10 2 Costanza 30 COMMIT;

224

Restrictii de integritate
La crearea unei chei primare sau unice se verifica daca exista index, daca nu se creaza. Cind se foloseste un index pentru o restrictie si restrictia este eliminata, atunci se sterge si indexul. Pentru pastrarea indexului se da clauza KEEP INDEX in DROP.. Cind avem referinta la o cheie primara sau unica, nu putem sterge restrictia de cheie primara sau unica sau indexul. Cheile UNIQUE si PRIMARY cu restrictii aminabile trebuie sa folosesca indecsi neunici. Pentru reutilizarea indecsilor existenti cind se creaza restrictii de cheie unica sau primara, putem include clauza USING INDEX: CREATE TABLE b ( b1 INTEGER, b2 INTEGER, CONSTRAINT unique1 (b1, b2) USING INDEX (CREATE UNIQUE INDEX b_index on b(b1, b2), CONSTRAINT unique2 (b1, b2) USING INDEX b_index );
225

Restrictii de integritate
Restrictia de integritate CHECK: - Nu folosim CHECK atunci cind celelalte tipuri pot asigura verificarea necesara. - CHECK <expresie_booleana> - Evaluarea expresiei pentru linia care se adauga sau se modifica. - Expresia nu poate contine subinterogari - Expresia nu poate contine functiile SYSDATE, UID, USER, USERNV. - Expresia nu poate contine pseudocoloanele LEVEL, PRIOR, ROWNUM. - Expresia nu poate contine o functie utilizator. - Restrictia este violata daca conditia este FALSE, altfel nu. Ex. CHECK(Sal>0 AND Comm>=0) - O coloana poate avea multiple restrictii CHECK
226

Restrictii de integritate
O restrictie de tip NOT NULL este un exemplu de restrictie CHECK: CHECK(nume_col IS NOT NULL) Cind o cheie compusa permite toate valorile null sau toate valorile nenule, atunci folosim CHECK. CREATE TABLE Dept_tab ( Deptno NUMBER(3) CONSTRAINT Dept_pkey PRIMARY KEY, Dname VARCHAR2(15), Loc VARCHAR2(15), CONSTRAINT Dname_ukey UNIQUE (Dname, Loc), CONSTRAINT Loc_check1 CHECK (loc IN ('NEW YORK', 'BOSTON', 'CHICAGO'))); CREATE TABLE Emp_tab ( Empno NUMBER(5) CONSTRAINT Emp_pkey PRIMARY KEY, Ename VARCHAR2(15) NOT NULL, Job VARCHAR2(10), Mgr NUMBER(5) CONSTRAINT Mgr_fkey REFERENCES Emp_tab, Hiredate DATE, Sal NUMBER(7,2), Comm NUMBER(5,2), Deptno NUMBER(3) NOT NULL CONSTRAINT dept_fkey REFERENCES Dept_tab ON DELETE CASCADE);
227

Restrictii de integritate
CREATE UNIQUE INDEX I_dept ON Dept_tab(deptno); ALTER TABLE Dept_tab ADD CONSTRAINT Dept_pkey PRIMARY KEY (deptno); ALTER TABLE Emp_tab ADD CONSTRAINT Dept_fkey FOREIGN KEY (Deptno) REFERENCES Dept_tab; ALTER TABLE Emp_tab MODIFY (Ename VARCHAR2(15) NOT NULL); - Nu se poate crea o restrictie pe o tabela care contine linii ce violeaza restrictia. - Userul ce creaza o restrictie trebuie sa aiba privilegiul de a crea tabele, sau sa modifice tabele. CREATE TABLE Emp_tab ( FOREIGN KEY (Deptno) REFERENCES Dept_tab); CREATE TABLE Emp_tab ( FOREIGN KEY (Deptno) REFERENCES Dept_tab ON DELETE CASCADE); CREATE TABLE Emp_tab ( FOREIGN KEY (Deptno) 228 REFERENCES Dept_tab ON DELETE SET NULL);

Restrictii de integritate
Vizualizarea restrictiilor din dictionarul de date: ALL_CONSTRAINTS ALL_CONS_COLUMNS USER_CONSTRAINTS USER_CONS_COLUMNS DBA_CONSTRAINTS DBA_CONS_COLUMNS Operatiile de ENABLE sau DISABLE pentru restrictii: - La definirea unei restrictii(CREATE TABLE sau ALTER TABLE restrictia este automat ENABLE. CREATE TABLE Emp_tab ( Empno NUMBER(5) PRIMARY KEY DISABLE); ALTER TABLE Emp_tab ADD PRIMARY KEY (Empno) DISABLE;
229

Restrictii de integritate
ALTER TABLE Dept_tab ENABLE CONSTRAINT Dname_ukey; ALTER TABLE Dept_tab ENABLE PRIMARY KEY ENABLE UNIQUE (Dname) ENABLE UNIQUE (Loc); ALTER TABLE Dept_tab DISABLE CONSTRAINT Dname_ukey; ALTER TABLE Dept_tab DISABLE PRIMARY KEY DISABLE UNIQUE (Dname) DISABLE UNIQUE (Loc); ALTER TABLE Dept_tab DROP UNIQUE (Dname); ALTER TABLE Dept_tab DROP UNIQUE (Loc); ALTER TABLE Emp_tab DROP PRIMARY KEY, DROP CONSTRAINT Dept_fkey; DROP TABLE Emp_tab CASCADE CONSTRAINTS;
230

Tabele nested incluse


CREATE TYPE phone AS OBJECT (telephone NUMBER) / CREATE TYPE phone_list AS TABLE OF phone / CREATE TYPE my_customer AS OBJECT ( cust_name VARCHAR2(25), phones phone_list) / CREATE TYPE customer_list AS TABLE OF my_customer / CREATE TABLE business_contacts ( company_name VARCHAR2(25), company_reps customer_list) NESTED TABLE company_reps STORE AS outer_ntab (NESTED TABLE phones STORE AS inner_ntab);
231

Renumirea restrictiilor de integritate


prompt Enter table name to find its primary key: accept table_name select constraint_name from user_constraints where table_name = upper('&table_name.') and constraint_type = 'P'; prompt Enter new name for its primary key: accept new_constraint set serveroutput on declare -- USER_CONSTRAINTS.CONSTRAINT_NAME is declared as --VARCHAR2(30). -- Using %TYPE here protects us if the length changes in a future -- release. constraint_name user_constraints.constraint_name%type;
232

Renumirea restrictiilor de integritate


BEGIN select constraint_name into constraint_name from user_constraints where table_name = upper('&table_name.') and constraint_type = 'P'; dbms_output.put_line('The primary key for ' || upper('&table_name.') || ' is: ' || constraint_name); execute immediate 'alter table &table_name. rename constraint ' || constraint_name || ' to &new_constraint.'; END; /

233

Restrictii de integritate
Daca lista de coloane nu apare in cheia straina, atunci se presupune referinta la cheia primara. CREATE TABLE Dept_tab ( Deptno NUMBER(3) PRIMARY KEY, Dname VARCHAR2(15), Loc VARCHAR2(15), CONSTRAINT Dname_ukey UNIQUE (Dname, Loc), CONSTRAINT LOC_CHECK1 CHECK (Loc IN ('NEW YORK', 'BOSTON', 'CHICAGO'))) / CREATE TABLE Emp_tab ( Empno NUMBER(5) PRIMARY KEY, Ename VARCHAR2(15) NOT NULL, Job VARCHAR2(10), Mgr NUMBER(5) CONSTRAINT Mgr_fkey REFERENCES Emp_tab ON DELETE CASCADE, Hiredate DATE, Sal NUMBER(7,2), Comm NUMBER(5,2), Deptno NUMBER(3) NOT NULL, CONSTRAINT Dept_fkey REFERENCES Dept_tab) /
234

Restrictii de integritate
SELECT Constraint_name, Constraint_type, Table_name, R_constraint_name FROM User_constraints; CONSTRAINT_NAME C TABLE_NAME R_CONSTRAINT_NAME --------------- ---------------------------SYS_C00275 P DEPT_TAB DNAME_UKEY U DEPT_TAB LOC_CHECK1 C DEPT_TAB SYS_C00278 C EMP_TAB SYS_C00279 C EMP_TAB SYS_C00280 P EMP_TAB MGR_FKEY R EMP_TAB SYS_C00280 DEPT_FKEY R EMP_TAB SYS_C00275 ______________________________________________________ PRIMARY KEY - P FOREIGN -R 235 UNIQUE -U CHECK, NOT NULL C

Restrictii de integritate
SELECT Constraint_name, Search_condition FROM User_constraints WHERE (Table_name = 'DEPT_TAB' OR Table_name = 'EMP_TAB') AND Constraint_type = 'C'; CONSTRAINT_NAME SEARCH_CONDITION --------------- ---------------------------------------LOC_CHECK1 loc IN ('NEW YORK', 'BOSTON', 'CHICAGO') SYS_C00278 ENAME IS NOT NULL SYS_C00279 DEPTNO IS NOT NULL SELECT Constraint_name, Table_name, Column_name FROM User_cons_columns; CONSTRAINT_NAME TABLE_NAME COLUMN_NAME --------------- ----------- --------------DEPT_FKEY EMP_TAB DEPTNO DNAME_UKEY DEPT_TAB DNAME DNAME_UKEY DEPT_TAB LOC LOC_CHECK1 DEPT_TAB LOC MGR_FKEY EMP_TAB MGR 236

Trighere
CREATE OR REPLACE TRIGGER Print_salary_changes BEFORE DELETE OR INSERT OR UPDATE ON Emp_tab FOR EACH ROW WHEN (new.Empno > 0) DECLARE sal_diff number; BEGIN sal_diff := :new.sal - :old.sal; dbms_output.put('Old salary: ' || :old.sal); dbms_output.put(' New salary: ' || :new.sal); dbms_output.put_line(' Difference ' || sal_diff); END; / UPDATE Emp_tab SET sal = sal + 500.00 WHERE deptno = 10; Un trigher este :bloc PL/SQL, sau procedura PL/SQL sau C sau Java, asociat cu o tabela, view, schema sau baza de date.
237

Trighere
Trigherele pot fi lansate de una din urmatoarele: Instructiuni DML (DELETE, INSERT, UPDATE) Instructiuni DDL (CREATE, ALTER, DROP) Operatii asupra bazelor de date (SERVERERROR, LOGON, LOGOFF, STARTUP, SHUTDOWN) Un trigher se lanseaza pe baza unei instructiuni declansatoare, ce specifica: -Instructiunea SQL sau evenimentul sistem, sau evenimentul de baza de date, sau evenimentul DDL ce lanseaza corpul trigherului. Optiunile instructiunii includ DELETE, INSERT, sau UPDATE. Tabela, view, baza de date sau schema asociata cu trigherul. - O singura tabela poate fi specificata in trigher. - Daca se foloseste un view, atunci singura optiune este INSTEAD OF si invers folosirea lui INSTEAD OF implica un view. DELETE FROM Emp_tab; INSERT INTO Emp_tab VALUES ( ... ); INSERT INTO Emp_tab SELECT ... FROM ... ; UPDATE Emp_tab 238 SET ... ;

Trighere
O instructiune UPDATE poate include o lista de coloane. Trigherul se lanseaza numai cind coloana respectiva este actualizata. Daca triherul omite lista de coloane, atunci el este lansat cind se actualizeaza una din coloanele tabelei respective. Pentru instructiunile declansatoare INSERT sau DELETE, nu trebuie specificata lista de coloane. BEFORE DELETE OR INSERT OR UPDATE OF ename ON Emp_tab Nu putem specifica o lista de coloane pentru UPDATE cu trgherii INSTEAD OF. Daca coloana specificata in UPDATE OF este o coloana obiect, atunci trigherul este declansat daca oricare din atributele obiectului este modificat. Nu putem specifica clauze UPDATE OF pe coloane de tip colectie. Folosim BEFORE pentru a modifica linia inainte ca data respectiva sa fie scrisa pe disc. Folosim AFTER sa obtinem si sa realizam operatii, care utilizeaza ID 239 de linie.

Trighere
Nu este cunoscuta ordinea in care liniile sunt tratate de o comanda SQL, deci nu proiectam un trigher care sa depinda de ordinea liniilor din tabela respectiva. Cind o instructiune din corpul unui trigher implica lansarea unui alt trigher, atunci trigherii se numesc in cascada. Un cursor sistem este deschis pentru fiecare executie a unui trigher. Oracle executa toti trigherii de acelasi tip inainte de a executa trigherii de un tip diferit. Daca exista trigheri multipli de acelasi fel pe o aceeasi tabela, atunci ordinea de executie a lor este arbitrara. Daca dorim ca actiuni multiple sa apara intr-o anumita ordine, atunci trebuie sa dam aceste actiuni intr-un singur trigher(de ex. Trigherul apeleaza o serie de proceduri).

240

Trighere
- Un view nu poate fi modificat de instructiunile UPDATE, INSERT, sau DELETE daca interogarea view query contine una din urmatoarele constructii: Un operator de multime Un operator DISTINCT O functie de agregare sau analitica O clauza GROUP BY, ORDER BY, MODEL, CONNECT BY, sau START WITH O expresie colectie intr-o lista din SELECT O subinterogare intr-o lista SELECT O subinterogare cu WITH READ ONLY Joinuri, cu unele exceptii
241

Trighere

Trighere
CREATE TABLE Project_tab ( Prj_level NUMBER, Projno NUMBER, Resp_dept NUMBER) / CREATE TABLE Emp_tab ( Empno NUMBER NOT NULL, Ename VARCHAR2(10), Job VARCHAR2(9), Mgr NUMBER(4), Hiredate DATE, Sal NUMBER(7,2), Comm NUMBER(7,2), Deptno NUMBER(2) NOT NULL) / CREATE TABLE Dept_tab ( Deptno NUMBER(2) NOT NULL, Dname VARCHAR2(14), Loc VARCHAR2(13), Mgr_no NUMBER, Dept_type NUMBER) / CREATE OR REPLACE VIEW manager_info AS SELECT e.ename, e.empno, d.dept_type, d.deptno, p.prj_level, p.projno FROM Emp_tab e, Dept_tab d, Project_tab p WHERE e.empno = d.mgr_no AND d.deptno = p.resp_dept 243 /

Trighere
CREATE OR REPLACE TRIGGER manager_info_insert INSTEAD OF INSERT ON manager_info REFERENCING NEW AS n -- new manager information FOR EACH ROW DECLARE rowcnt number; BEGIN SELECT COUNT(*) INTO rowcnt FROM Emp_tab WHERE empno = :n.empno; IF rowcnt = 0 THEN INSERT INTO Emp_tab (empno,ename) VALUES (:n.empno, :n.ename); ELSE UPDATE Emp_tab SET Emp_tab.ename = :n.ename WHERE Emp_tab.empno = :n.empno; END IF; SELECT COUNT(*) INTO rowcnt FROM Dept_tab WHERE deptno = :n.deptno; IF rowcnt = 0 THEN INSERT INTO Dept_tab (deptno, dept_type) VALUES(:n.deptno, :n.dept_type); ELSE UPDATE Dept_tab SET Dept_tab.dept_type = :n.dept_type 244 WHERE Dept_tab.deptno = :n.deptno;

Trighere
END IF; SELECT COUNT(*) INTO rowcnt FROM Project_tab WHERE Project_tab.projno = :n.projno; IF rowcnt = 0 THEN INSERT INTO Project_tab (projno, prj_level) VALUES(:n.projno, :n.prj_level); ELSE UPDATE Project_tab SET Project_tab.prj_level = :n.prj_level WHERE Project_tab.projno = :n.projno; END IF; END; - Trighere pe tabele nested: CREATE OR REPLACE VIEW Dept_view AS SELECT d.Deptno, d.Dept_type, d.Dept_name, CAST (MULTISET ( SELECT e.Empno, e.Empname, e.Salary) FROM Emp_tab e WHERE e.Deptno = d.Deptno) AS Emplist 245 FROM Dept_tab d;

Trighere
CREATE OR REPLACE TRIGGER Dept_emplist_tr INSTEAD OF INSERT ON NESTED TABLE Emplist OF Dept_view REFERENCING NEW AS Employee PARENT AS Department FOR EACH ROW BEGIN -- The insert on the nested table is translated to an insert on the base table: INSERT INTO Emp_tab VALUES ( :Employee.Empno, :Employee.Empname,:Employee.Salary, :Department.Deptno); END; INSERT INTO TABLE (SELECT d.Emplist FROM Dept_view d WHERE Deptno = 10) VALUES (1001, 'John Glenn', 10000);
246

Trighere
insert into project_tab Values(10,10,10); insert into Emp_tab values(1,'A','X',10,'10-JAN-2006',100,10,10); insert into dept_tab values (10,'p1', 'iasi',1,2); insert into manager_info values('A',1,40,30,1,11); PRJ_LEVEL PROJNO RESP_DEPT ---------------------------10 10 10 1 11 -------------------------------------------------------------------------1A X 10 10-JAN-06 100 10 10 -----------------------------------------------------------------------------10 p1 iasi 1 2 247 30 40

Trighere
Optiunea FOR EACH CREATE TABLE Emp_log ( Emp_id NUMBER, Log_date DATE, New_salary NUMBER, Action VARCHAR2(20)); CREATE OR REPLACE TRIGGER Log_salary_increase AFTER UPDATE ON Emp_tab FOR EACH ROW WHEN (new.Sal > 1000) BEGIN INSERT INTO Emp_log (Emp_id, Log_date, New_salary, Action) VALUES (:new.Empno, SYSDATE, :new.SAL, 'NEW SAL'); END; / UPDATE Emp_tab SET Sal = Sal + 1000 WHERE Deptno = 20;
248

Trighere
CREATE OR REPLACE TRIGGER Log_emp_update AFTER UPDATE ON Emp_tab BEGIN INSERT INTO Emp_log (Log_date, Action) VALUES (SYSDATE, 'Emp_tab COMMISSIONS CHANGED'); END; / Accesul la valorile coloanelor in trigheri pentru linii. - Un trigher lansat de INSERT are acces numai la noile valori, vechile valori sunt considerate nule. - Un trigher lansat de UPDATE are acces la valoarea veche si noua pentru trigheri de linie cu BEFORE sau AFTER. - Un trigher lansat cu DELETE are acces numai la valorile vechi, noile valori sunt null. Nu putem modifica noile valori. Eroare ORA-4048. 249 IF :new.Sal > 1000 ... IF :new.Sal < :old.Sal ...

Trighere
Modificarea coloanelor LOB cu un trigher: drop table tab1; create table tab1 (c1 clob); insert into tab1 values (Sir de caractere'); create or replace trigger trg1 before update on tab1 for each row begin dbms_output.put_line('Old value of CLOB column: '||:OLD.c1); dbms_output.put_line('Proposed new value of CLOB column: '||:NEW.c1); /* Previously, we couldn't change the new value for a LOB. Now, we can replace it, or construct a new value using SUBSTR, INSTR... operations for a CLOB, or DBMS_LOB calls for a BLOB. */ :NEW.c1 := :NEW.c1 || to_clob(Alt sir de caractere'); dbms_output.put_line('Final value of CLOB column: '||:NEW.c1); 250 end; /

Trighere
set serveroutput on; update tab1 set c1 = 'Different Document || .Fragment</h1><p>Different text.'; select * from tab1; Detectarea operatiilor DML ce lanseaza un trigher: Daca una sau mai multe operatii DML(ON INSERT, ON DELETE, ON UPDATE), atunci trigherul poate folosi predicatele INSERING, DELETING, UPDATING pentru a verifica ce tip de instructiune a lansat trigherul. IF INSERTING THEN ... END IF; IF UPDATING THEN ... END IF; IF DELETING THEN ... END IF; CREATE OR REPLACE TRIGGER ... ... UPDATE OF Sal, Comm ON Emp_tab ... BEGIN ... IF UPDATING ('SAL') THEN ... END IF; 251 END;

Trighere
Vizualizarea restrictiilor: SELECT NAME, REFERENCED_OWNER, REFERENCED_NAME, REFERENCED_TYPE FROM ALL_DEPENDENCIES WHERE OWNER = 'SCOTT' and TYPE = 'TRIGGER'; ---------------------------------------------------------------------------------------OWNER NOT NULL VARCHAR2(30) NAME NOT NULL VARCHAR2(30) TYPE VARCHAR2(17) REFERENCED_OWNER VARCHAR2(30) REFERENCED_NAME VARCHAR2(64) REFERENCED_TYPE VARCHAR2(17) REFERENCED_LINK_NAME VARCHAR2(128 DEPENDENCY_TYPE VARCHAR2(4)
252

Trighere
USER_TRIGGERS ALL_TRIGGERS DBA_TRIGGERS RESTRICTII DE INTEGRITATE SI TRIGHERE: CREATE OR REPLACE TRIGGER Dept_del_cascade AFTER DELETE ON Dept_tab FOR EACH ROW -- Before a row is deleted from Dept_tab, delete all -- rows from the Emp_tab table whose DEPTNO is the same as -- the DEPTNO being deleted from the Dept_tab table: BEGIN DELETE FROM Emp_tab WHERE Emp_tab.Deptno = :old.Deptno; END;
253

Trighere
Pentru restrictia de integritate referentiala: - Un trigher se defineste pentru tabela copil, ce va asigura faptul ca valorile cheii straine corespund valorilor cheii primare din tabela parinte. - Se pot defini mai multi trigheri pentru tabela parinte. Acestia garanteaza actiunea referentiala dorita(RESTRICT, CASCADE, SET NULL) pentru valorile cheii straine cind se modifica sau sterg chei in tabela parinte. In cazul INSERT in tabela parinte nu se cere nicio actiune. CREATE OR REPLACE TRIGGER Emp_dept_check BEFORE INSERT OR UPDATE OF Deptno ON Emp_tab FOR EACH ROW WHEN (new.Deptno IS NOT NULL) -- Before a row is inserted, or DEPTNO is updated in the Emp_tab -- table, fire this trigger to verify that the new foreign -- key value (DEPTNO) is present in the Dept_tab table. DECLARE Dummy INTEGER; -- to be used for cursor fetch Invalid_department EXCEPTION; Valid_department EXCEPTION; Mutating_table EXCEPTION; PRAGMA 254 EXCEPTION_INIT (Mutating_table, -4091);

Trighere
/* Cursor used to verify parent key value exists. If present, lock parent key's row so it can't be deleted by another transaction until this transaction is committed or rolled back. */ CURSOR Dummy_cursor (Dn NUMBER) IS SELECT Deptno FROM Dept_tab WHERE Deptno = Dn FOR UPDATE OF Deptno; BEGIN OPEN Dummy_cursor (:new.Deptno); FETCH Dummy_cursor INTO Dummy; /* Verify parent key. If not found, raise user-specified error number and message. If found, close cursor before allowing triggering statement to complete:*/ IF Dummy_cursor%NOTFOUND THEN RAISE Invalid_department; ELSE RAISE valid_department; END IF; CLOSE Dummy_cursor;
255

Trighere
EXCEPTION WHEN Invalid_department THEN CLOSE Dummy_cursor; Raise_application_error(-20000, 'Invalid Department' || ' Number' || TO_CHAR(:new.deptno)); WHEN Valid_department THEN CLOSE Dummy_cursor; WHEN Mutating_table THEN NULL; END; Trigher pentru tabela parinte(UPDATE si DELETE) CREATE OR REPLACE TRIGGER Dept_restrict BEFORE DELETE OR UPDATE OF Deptno ON Dept_tab FOR EACH ROW /* Before a row is deleted from Dept_tab or the primary key (DEPTNO) of Dept_tab is updated, check for dependent foreign key values in Emp_tab; rollback if any are found.*/
256

Trighere
DECLARE Dummy INTEGER; -- to be used for cursor fetch Employees_present EXCEPTION; employees_not_present EXCEPTION; -- Cursor used to check for dependent foreign key values. CURSOR Dummy_cursor (Dn NUMBER) IS SELECT Deptno FROM Emp_tab WHERE Deptno = Dn; BEGIN OPEN Dummy_cursor (:old.Deptno); FETCH Dummy_cursor INTO Dummy; /* If dependent foreign key is found, raise user-specified error number and message. If not found, close cursor before allowing triggering statement to complete*/. IF Dummy_cursor%FOUND THEN RAISE Employees_present; -- dependent rows exist ELSE RAISE Employees_not_present; -- no dependent rows END IF; 257 CLOSE Dummy_cursor;

Trighere

EXCEPTION WHEN Employees_present THEN CLOSE Dummy_cursor; Raise_application_error(-20001, 'Employees Present in' || ' Department ' || TO_CHAR(:old.DEPTNO)); WHEN Employees_not_present THEN CLOSE Dummy_cursor; END; Trigheri UPDATE si DELETE SET NULL pentru tabela parinte. CREATE OR REPLACE TRIGGER Dept_set_null AFTER DELETE OR UPDATE OF Deptno ON Dept_tab FOR EACH ROW /*Before a row is deleted from Dept_tab or the primary key (DEPTNO of Dept_tab is updated, set all corresponding dependent foreign key 258 values in Emp_tab to NULL: */

Trighere
BEGIN IF UPDATING AND :OLD.Deptno != :NEW.Deptno OR DELETING THEN UPDATE Emp_tab SET Emp_tab.Deptno = NULL WHERE Emp_tab.Deptno = :old.Deptno; END IF; END; Trigher DELETE CASCADE pentru tabela parinte: CREATE OR REPLACE TRIGGER Dept_del_cascade AFTER DELETE ON Dept_tab FOR EACH ROW /*Before a row is deleted from Dept_tab, delete all rows from the Emp_tab table whose DEPTNO is the same as the DEPTNO being deleted from the Dept_tab table:*/ BEGIN DELETE FROM Emp_tab WHERE Emp_tab.Deptno = :old.Deptno; 259 END;

Trighere
Trigher UPDATE CASCADE pentru tabela parinte /*Generate a sequence number to be used as a flag for -- determining if an update has occurred on a column:*/ CREATE SEQUENCE Update_sequence INCREMENT BY 1 MAXVALUE 5000 CYCLE; CREATE OR REPLACE PACKAGE Integritypackage AS Updateseq NUMBER; END Integritypackage; CREATE OR REPLACE PACKAGE BODY Integritypackage AS END Integritypackage; -- create flag col: ALTER TABLE Emp_tab ADD Update_id NUMBER; CREATE OR REPLACE TRIGGER Dept_cascade1 BEFORE UPDATE OF Deptno ON Dept_tab DECLARE Dummy NUMBER;
260

Trighere
/*Before updating the Dept_tab table (this is a statement trigger), generate a new sequence number and assign it to the public variable UPDATESEQ of a user-defined package named INTEGRITYPACKAGE: */ BEGIN SELECT Update_sequence.NEXTVAL INTO Dummy FROM dual; Integritypackage.Updateseq := Dummy; END; CREATE OR REPLACE TRIGGER Dept_cascade2 AFTER DELETE OR UPDATE OF Deptno ON Dept_tab FOR EACH ROW /* For each department number in Dept_tab that is updated, cascade the update to dependent foreign keys in the Emp_tab table. Only cascade the update if the child row has not already been updated by this trigger: */
261

Trighere
BEGIN IF UPDATING THEN UPDATE Emp_tab SET Deptno = :new.Deptno, Update_id = Integritypackage.Updateseq --from 1st WHERE Emp_tab.Deptno = :old.Deptno AND Update_id IS NULL; /* only NULL if not updated by the 3rd trigger fired by this same triggering statement */ END IF; IF DELETING THEN /* Before a row is deleted from Dept_tab, delete all rows from the Emp_tab table whose DEPTNO is the same as the DEPTNO being deleted from the Dept_tab table:*/ DELETE FROM Emp_tab WHERE Emp_tab.Deptno = :old.Deptno; END IF; END; CREATE OR REPLACE TRIGGER Dept_cascade3 AFTER UPDATE OF Deptno ON Dept_tab BEGIN UPDATE Emp_tab SET Update_id = NULL 262 WHERE Update_id = Integritypackage.Updateseq; END;

Trighere
Dependente legate de trighere: Fie TR un trigher ce utilizeaza chemari de functii sau proceduri. Fie S o astfel de functie sau procedura. Daca S sufera o modificare, atunci TR devine invalid. La o noua lansare a lui TR, acesta se recompileaza. SELECT NAME, REFERENCED_OWNER, REFERENCED_NAME, REFERENCED_TYPE FROM ALL_DEPENDENCIES WHERE OWNER = 'SCOTT' and TYPE = 'TRIGGER'; VALID WITH ERRORS ALTER TRIGGER Print_salary_changes COMPILE; ALTER TRIGGER Reorder ENABLE; ALTER TABLE Inventory ENABLE ALL TRIGGERS; ALTER TRIGGER Reorder DISABLE; ALTER TABLE Inventory DISABLE ALL TRIGGERS; USER_TRIGGERS ALL_TRIGGERS DBA_TRIGGERS 263

Trighere
CREATE OR REPLACE TRIGGER Reorder AFTER UPDATE OF Parts_on_hand ON Inventory FOR EACH ROW WHEN(new.Parts_on_hand < new.Reorder_point) DECLARE x NUMBER; BEGIN SELECT COUNT(*) INTO x FROM Pending_orders WHERE Part_no = :new.Part_no; IF x = 0 THEN INSERT INTO Pending_orders VALUES (:new.Part_no, :new.Reorder_quantity, sysdate); END IF; END; SELECT Trigger_type, Triggering_event, Table_name FROM USER_TRIGGERS WHERE Trigger_name = 'REORDER';
264

Trighere
TYPE TRIGGERING_STATEMENT TABLE_NAME ---------------------------------------------------AFTER EACH ROW UPDATE INVENTORY SELECT Trigger_body FROM USER_TRIGGERS WHERE Trigger_name = 'REORDER'; TRIGGER_BODY -------------------------------------------DECLARE x NUMBER; BEGIN SELECT COUNT(*) INTO x FROM Pending_orders WHERE Part_no = :new.Part_no; IF x = 0 THEN INSERT INTO Pending_orders VALUES (:new.Part_no, :new.Reorder_quantity, sysdate); END IF; 265 END;

Trighere
CREATE OR REPLACE PACKAGE Auditpackage AS Reason VARCHAR2(10); PROCEDURE Set_reason(Reason VARCHAR2); END; CREATE TABLE Emp99 ( Empno NOT NULL NUMBER(4), Ename VARCHAR2(10), Job VARCHAR2(9), Mgr NUMBER(4), Hiredate DATE, Sal NUMBER(7,2), Comm NUMBER(7,2), Deptno NUMBER(2), Bonus NUMBER, Ssn NUMBER, Job_classification NUMBER); CREATE TABLE Audit_employee ( Oldssn NUMBER, Oldname VARCHAR2(10), Oldjob VARCHAR2(2), Oldsal NUMBER, Newssn NUMBER, Newname VARCHAR2(10), Newjob VARCHAR2(2), Newsal NUMBER, Reason VARCHAR2(10), User1 VARCHAR2(10), Systemdate DATE);
266

Trighere
CREATE OR REPLACE TRIGGER Audit_employee AFTER INSERT OR DELETE OR UPDATE ON Emp99 FOR EACH ROW BEGIN /* AUDITPACKAGE is a package with a public package variable REASON. REASON could be set by the application by a command such as EXECUTE AUDITPACKAGE.SET_REASON(reason_string). Note that a package variable has state for the duration of a session and that each session has a separate copy of all package variables. */ IF Auditpackage.Reason IS NULL THEN Raise_application_error(20201, 'Must specify reason' || ' with AUDITPACKAGE.SET_REASON(Reason_string)'); END IF; INSERT INTO Audit_employee VALUES (:old.Ssn, :old.Ename, :old.Job_classification, :old.Sal, :new.Ssn, :new.Ename, :new.Job_classification, :new.Sal, auditpackage.Reason, User, Sysdate ); 267 END;

Trighere
CREATE OR REPLACE TRIGGER Audit_employee_reset AFTER INSERT OR DELETE OR UPDATE ON Emp_tab BEGIN auditpackage.set_reason(NULL); END; CREATE TABLE Audit_table ( Seq NUMBER, User_at VARCHAR2(10), Time_now DATE, Term VARCHAR2(10), Job VARCHAR2(10), Proc VARCHAR2(10), enum NUMBER); CREATE SEQUENCE Audit_seq; CREATE TABLE Audit_table_values ( Seq NUMBER, Dept NUMBER, Dept1 NUMBER, Dept2 NUMBER); CREATE OR REPLACE TRIGGER Audit_emp AFTER INSERT OR UPDATE OR DELETE ON Emp_tab FOR EACH ROW DECLARE Time_now DATE; 268 Terminal CHAR(10);

Trighere
BEGIN -- get current time, and the terminal of the user: Time_now := SYSDATE; Terminal := USERENV('TERMINAL'); -- record new employee -- primary key IF INSERTING THEN INSERT INTO Audit_table VALUES (Audit_seq.NEXTVAL, User, Time_now, Terminal, 'Emp_tab', 'INSERT', :new.Empno); -- record primary key of the deleted row: ELSIF DELETING THEN INSERT INTO Audit_table VALUES (Audit_seq.NEXTVAL, User, Time_now, Terminal, 'Emp_tab', 'DELETE', :old.Empno); -- for updates, record the primary key -- of the row being updated: INSERT INTO Audit_table VALUES (audit_seq.NEXTVAL, User, Time_now, Terminal, 'Emp_tab', 'UPDATE', :old.Empno); 269 -- and for SAL and DEPTNO, record old and new values:

Trighere
IF UPDATING ('SAL') THEN INSERT INTO Audit_table_values VALUES (Audit_seq.CURRVAL, 'SAL', :old.Sal, :new.Sal); ELSIF UPDATING ('DEPTNO') THEN INSERT INTO Audit_table_values VALUES (Audit_seq.CURRVAL, 'DEPTNO', :old.Deptno, :new.DEPTNO); END IF; END IF; END;

270