Table of Contents

Laboratorul 01 - PL/SQL Introducere

Obiective

Noțiuni teoretice

PL/SQL este un limbaj structurat pe blocuri​. Are caracteristici de procesare procedurală și de tratare a erorilor​. Blocurile pot fi de două tipuri:​

Deoarece PL/SQL este o extensie pentru SQL, regulile sintactice de bază aplicabile în SQL sunt valabile și în PL/SQL:​

PL/SQL permite o varietate de tipuri de date ce pot fi folosite pentru declararea de variabile și constante​. Variabilele pot avea, opțional, atribuite valori la declarare și pot să-și schimbe valoarea prin atribuiri ulterioare în cadrul blocului. Constantele sunt identificatori care păstrează o valoare fixă ce trebuie atribuită în momentul declarării. Instructiunile PL/SQL nu sunt case sensitive. Setul de caractere este format din literele mari și mici, cifrele de la 0-9, spații, caractere de tabulare, carriage return și simboluri special.

Blocuri Anonime

Blocul anonim are cea mai simplă structură și este compus din trei părți:​

Fiecare bloc începe cu unul dintre cuvintele cheie DECLARE sau BEGIN. Cuvântul BEGIN este punctul de început al blocului ​de execuție. Înainte de executarea unui bloc se golește bufferul SQL​.

Structura logică a unui bloc PL/SQL anonim este:​

Ex. 1. Să se selecteze numele si functia unui angajat introducand id-ul acestuia de la tastatura (testați cu 1, 100 și 200).

Observații:

  • Pentru a afișa mesaje în SQL*Plus și SQL Developer se va folosi comanda:​ set serveroutput on​
  • Funcția care afișează mesaje în SQL*Plus și SQL Developer este:​ dbms_output.put_line(string);​
  • Concatenarea șirurilor de caractere se face folosind operatorul ||​, e.g., 'Numele angajatului este ' ||​ nume​
  • Pentru a folosi comanda SELECT într-un bloc se va folosi o structură de forma: SELECT COLOANA1, COLOANA2,… INTO VARIABILA1, VARIABILA2, … FROM TABEL1,…
  • Variabilele VARIABILA1, VARIABILA2, … sunt declarate în secțiunea DECLARE
  • Blocurile DECLARE și EXCEPTION nu sunt obligatorii
  • Pentru a da o variabilă de la tastatură se folosește &
  • O variabliă poate avea acea celași data tip ca o altă variabilă sau o coloană dintr-un tabel (ex. functie jobs.job_title%type; ).
  • Știind că variabila functie va trebui să fie de același tip precum coloana job_title din tabelul jobs, am folosit tipul de variabilă corelat %TYPE
  • Comentariile pe mai multe linii se delimitează cu /**/
  • Comentariile pe o singură linie se marchează cu două linii orizontale --​
  • Comentatiile pe o singură linie nu înhibă funționalitatea caracterelor, în schimb cele pe mai multe linii o fac.
    • Daca folosesc următorul comentariu --​acest & se va executa , atunci compilatorul va cere o valoare pentru variabila de substituție & din comentariu.
    • Dacă folosesc /* acest & nu se va executa */, atunci compilatorul nu va cere o valoare pentru variabila de substituție & din comentariu.

Blocuri Înlănțuite

Blocurile anonime pot fi înlănțuite. Execuția se face secvențial. Declararea variabilelor pentru toate blocurile înlănțuite se face o singură data în secțiunea DECLARE.

Structura logică pentru un bloc înlănțuit este:​

[<<label>>] -- etichetă bloc (opțional)
[DECLARE]  -- (opțional)​
  -- variabile pentru blocurile partinte și copii
BEGIN-- start bloc parinte
    [DECLARE] -- (opțional)​
      -- variabile pentru blocul copil_1
    BEGIN -- start blocul copil_1​
      -- accesibile variabilele declarate în blocurile
      -- parinte și copil_1
    [EXEPTION] -- (opțional)​
      -- interceptarea și tratarea excepțiilor blocul copil_1​
    END; -- sfârșit bloc copil_1​
 
    [DECLARE] -- (opțional)​
      -- variabile pentru blocul copil_2
    BEGIN -- start blocul copil_2​
      -- accesibile variabilele declarate în blocurile
      -- parinte si copil_2
    [EXCEPTION] -- (opțional)​
      -- interceptarea și tratarea excepțiilor bloc 2
    END; -- sfârșit bloc copil_2​
[EXCEPTION] -- (opțional)​
  -- interceptarea și tratarea excepțiilor bloc principal 
  -- si orice alta exceptie netratata în blocurile copii 
END;​ -- sfârșit bloc parinte

Ex. 2. Să se insereze un nou angajat, astfel:

După insert să se adauge pentru acest angajat un punctaj pentru comision de 0.5.​

Blocuri Imbricate

Blocurile imbricate sunt blocuri care se execută în interiorul altui bloc. Se mai numesc și sub-blocuri. Variabile pot fi transmise de la bloc la sub-bloc, nu și invers.​

Structura logică pentru un bloc imbricat este:​

[<<label>>] -- etichetă bloc (opțional)
[DECLARE] -- (opțional)​
  --  variabile bloc principal, bloc 1, bloc 2, bloc 3​ 
BEGIN[DECLARE] -- (opțional)​
      --  variabile bloc 1, bloc 2, bloc 3​
    BEGIN -- bloc 1​
        [DECLARE]  -- (opțional)​
          --  variabile bloc 2, bloc 3​
        BEGIN -- bloc 2​
            [DECLARE]  -- (opțional)​
              --  variabile bloc 3​
            BEGIN -- bloc 3​
            [EXCEPTION] -- (opțional)​
              -- tratare erori bloc 3
            END; -- bloc 3​
        [EXCEPTION] -- (opțional)​
          -- tratare erori bloc 2
          -- tratarea erorilor propagate din blocul 3
        END; -- bloc 2​
    [EXCEPTION] -- (opțional)​
      -- tratare erori bloc 1​
      -- tratarea erorilor propagate din blocul 2 și 3
    END; -- bloc 1​
[EXCEPTION] -- (opțional)​
  -- tratare erori bloc principal
  -- tratarea erorilor propagate din blocurile 1, 2 și 3
END;​

Ex. 3. Să se rezolve exercițiul anterior folosind blocuri imbricate.​

Executarea blocurilor PL/SQL în SQL*Plus​ (Opțional)

În cazul în care nu aveți acces la un IDE, puteți să vă conectați la un Server ORACLE folosind utilitarul în linie de comandă SQL*Plus. (Mai multe dedalii în Laboratorul 2 - Baze de date)

Pentru a vă conecta la SQL*Plus în consolă comanda care se folosește este:

sqlplus [username[/password[@bazadate]]]

Blocurile PL/SQL pot fi editate direct în SQL*Plus (nerecomandat) sau pot fi editate în orice editor de text​. Pentru a executa un bloc în SQL*Plus folositi una din comenzile (comanda intreagă sau abrevierea):

Comandă Abreviere Utilizare
RUN​ R​ Afișează și execută blocul curent din buffer​
/​ Execută blocul curent din buffer​

În SQL*Plus

În SQL*Plus un bloc se poate executa astfel:​

Dacă executați sau copiați codul dintr-un fișer, se recomandă adaugarea unui forward slash (/) – comanda de executare a blocului – după ultimul END.

În linia de comandă se mai pot da și următoarele comenzi:

Comenzi SQL*Plus utile pentru formatare

Comandă​ Utilizare ​
set serveroutput on Permite afișarea în SQL*Plus​
set lines n​ Permite printarea a n caractere pe verticală​
set pages n​ Permite printarea a n coloane​

Tipuri variabile

PL/SQL acceptă toate tipurile de date din SQL. Nu sunt permise referințe anticipate, deci toate variabilele și constantele trebuie să fie declarate în secțiunea DECLARE înainte de utilizare. În secțiunea DECLARE trebuie declarate numele și tipul fiecărei variabile utilizate în cadrul blocului. Tipul specifică formatul de memorare, restricțiile și un domeniu valid de valori. Sintaxa declarării unei variabile este următoarea:​

nume_var [CONSTANT]{tip_de_date|identificator%TYPE|identificator%ROWTYPE}[NOT NULL][{:=|DEFAULT} expresie_PL/SQL];​

Tipuri de date scalare​

Tipurile de date scalare​ nu au componente interne (conţin valori atomice).

Tipurile de date ce stochează valori numerice cuprind:​

Tipurile de date ce stochează caractere cuprind:​

Tipurile de date ce stochează data calendaristica si ora cuprind tipurile:

Tipurile de date ce stochează date în format unicode includ tipurile

Tipul de date BOOLEAN stochează valori logice (true, false sau null)

Exemple:

v_valoare NUMBER(15) NOT NULL := 0;​
v_data_achizitie DATE DEFAULT SYSDATE;​
v_material VARCHAR2(15) := 'Matase';​
c_valoare CONSTANT NUMBER := 100000;​
v_stare VARCHAR2(20) DEFAULT 'Buna';​
v_clasificare BOOLEAN DEFAULT FALSE;​
int_an_luna INTERVAL YEAR TO MONTH :=INTERVAL '3-2' YEAR TO MONTH; --interval de 3 ani si 2 luni​

Ex. 4. Să se scrie un bloc PL/SQL care primește de la tastatură un id de angajat și va afișa un mesaj cu forma: 'nume_angajat are un venit orar de venit_orar și face parte din departamentul denumire_departament. A lucrat în firma un număr total de zile_lucrate zile'. În caz că angajatul nu există să se trateze eroarea.

Tipuri de date corelate​

Tipurile corelate sunt folosite pentru a declara variabile de tipul unui rând de tabel sau al unei coloane de tabel. Avantajul folosirii unor astfel de tipuri este că atunci când se modifică structura coloanelor dintr-un tabel nu mai trebuie să fie modificat și codul PL/SQL.

Tipuri corelate:​

Ex. 5. Să se scrie un bloc PL/SQL care primește de la tastatură un id de angajat și afișează numele, funcția acestuia, departamentul și locația departamentului. Locația deopartamentului va cuprinde orașul, statul/județul, țara și regiunea.​

Tipuri de date LOB

Tipuri LOB (Large OBject) sunt folosite pentru stocarea de date binare, text, imagini și fișiere video de dimensiuni mari (până la 4GB).​

Data Type​ Description​
CLOB​ A character large object containing single-byte or multibyte characters. Both fixed-width and variable-width character sets are supported, both using the database character set. Maximum size is (4 gigabytes - 1) * (database block size).​
NLOB​ A character large object containing Unicode characters. Both fixed-width and variable-width character sets are supported, both using the database national character set. Maximum size is (4 gigabytes - 1) * (database block size). Stores national character set data.​
BLOB​ A binary large object. Maximum size is (4 gigabytes - 1) * (database block size).​
BFILE​ Contains a locator to a large binary file stored outside the database. Enables byte stream I/O access to external LOBs residing on the database server. Maximum size is 4 gigabytes.​

Tipuri de Operatori

Operatori aritmetici

Operatori aritmetici​ Descriere
+​ Adunare​
- Scădere ​
* Multiplicare​
/ Împărțire ​
** Exponențial

Operatorii de comparație

Operatorii de comparație pot fi feluri: operatori logici și operatori SQL

Operator LogicSemnificație
= Egal
> Mai mare decât
>= Mai mare sau egal decât
< Mai mic decât
<= Mai mic sau egal decât
Operator SQLSemnificație
val BETWEEN val1 AND val2 Verifică daca o valoare se află între două valori date (inclusiv). Echivalent cu val >= val1 AND val <= val2
IN (list) Compară dacă valoarea se află în lista de valori list. val IN (a,b,c) este echivalent cu val = a OR val = b OR val = c
LIKE string Compară cu un model de tip caracter/șir de caractere
IS NULL Verifică dacă o valoare este NULL

Operatori de negație

Operatorii de negație pot fi de două feluri: operatori logici și operatori SQL.

Operator LogicSemnificație
!= Diferit de (Unix, Windows)
^= Diferit de (IBM)
<> Diferit de (Toate OS)
NOT val { = | > | >= | < | <= } Neagă operatorul de comparație
Operator SQLSemnificație
NOT BETWEEN val1 AND val2 Verifică daca o valoare nu se află între două valori date (inclusiv)
NOT IN (list) Compară dacă valoarea nu se află în lista de valori list.
NOT LIKE string Compară cu un model de tip caracter/șir de caractere
IS NOT NULL Verifică dacă o valoare nu este NULL

Precedența operatorilor logici este următoarea:

  1. Operatorii de comparație și operatorii SQL au precedență egală (=,<,<=,>,>=,<>,!=,^=, BETWEEN, IN, LIKE, IS NULL)
  2. NOT (pentru inversarea rezultatului unei expresii logice)
  3. AND
  4. OR

Pentru a fi siguri de ordinea de execuție a operațiilor se recomandă folosirea parantezelor rotunde. Ordinea naturală a operațiilor în cadrul unei expresii este următoarea:​

Ordine​Operație​Descriere​
1​ ** exponențial
2​ +, -​ identitate, negație​
3​ *, /​ înmulțire, împărțire​
4​ +, -, ||​ adunare, scădere, concatenare​
5 =, !=, <, >, %⇐%, >=, IS NULL, LIKE, BETWEEN, IN​ comparație​
6 NOT negație ​
7 AND​ conjuncție​
8 OR​ incluziune​

Tipuri de simboluri

Tipuri de simboluri simple

Simbol​Descriere​
( )​Delimitator de listă sau expresii​
;Delimitator de instrucțiuni​
,​Separator de obiect​
.Selector de componentă​
@Delimitator de acces la baza de date​
'Delimitator de șir​
:Delimitator de server​
$Format de afișare în USD​
&Variabilă substituită​

Tipuri de simbiluri compuse

Simbol​Descriere​
:=​Asignare​
=>​Asociere​
..​Rang​
||​Concatenare​
<< >>​Etichetă​
--​Comentariu pe o singură linie​
/* */Comentatiu pe mai multe linii​

Nu sunt permise spații între cele două caractere ale simbolurilor compuse.​

Domeniul variabilelor și constantelor​

Domeniul de valabilitate al variabilelor reprezintă zona unui program în care acestea pot fi folosite. Variabilele și constantele pot fi declarate în cadrul blocului în care au fost definite sau în orice sub-bloc inclus în acesta. Variabilele declarate într-un sub-bloc pot fi folosite doar în acesta sau în sub-blocurile acestuia. Variabilele se pot transmite de la un bloc la sub-bloc, dar nu și invers. Aceste constrângeri se aplică tuturor obiectelor declarate, inscusiv cursoare, constante și excepții definite de utilizator.​

În sub-bloc se pot folosi atât variabilele definite local cât și cele din blocul superior. Dacă într-un sub-bloc se definește o variabilă cu același nume ca una dintr-un bloc superior atunci are prioritate cea locală, dezactivându-se variabila definită în blocul superior. Se recomandă să se evite astfel de situații pentru a nu crea confuzii.​

Exerciții rezolvate

Ex. 6. Să se afișeze informațiile despre ultimul angajat care a venit în firmă în anul 2001.​

Ex. 7. Să se găsească care angajat are o vechime de peste 19 de ani si 5 luni in firmă.​

Ex. 8. Să se facă o verificare a numărului de angajări pentru un an introdus de la tastatură. Dacă există o angajare, atunci se va afișa mesajul 'In anul [an] au avut loc [numar angajari] angajare'. Dacă nu există nicio angajare, se va declanșa o excepție no_data_found și se va afișa mesajul 'Nu exista angajari in anul [an]'. Dacă sunt mai mulți angajați, se va declanșa excepția too_many_rows și se va afișa mesajul 'Sunt [numar angajari] angajari in anul [an]'.

Ex. 9. Să să selecteze departamementul, numele, data angajării și comisionul unui angajat introducând id-ul angajatului de la tastatură.​ În cazul în care angajatul nu are departament, se afișează N/A. Testați cu valorile 100 si 178

Ex. 10. Să se calculeze suma veniturilor angajaților care au aceeași funcție și lucrează în același departament. Testați cu