Skip to content
aliasbind edited this page Apr 21, 2012 · 9 revisions

I. Instrucțiuni PL/SQL. Blocuri

  1. Atribuire

    nume_variabila := expresie;
  2. Instrucțiunea IF

    IF conditie1 THEN
        secventa_de_comenzi_1
    [ELSIF conditie2 THEN
        secventa_de_comenzi_2]
    ...
    [ELSE
        secventa_de_comenzi_n]
    END IF;
  3. Instrucțiunea CASE

    CASE test_var
        WHEN valoare_1 THEN secventa_de_comenzi_1;
        WHEN valoare_2 THEN secventa_de_comenzi_2;
        ...
        WHEN valoare_k THEN secventa_de_comenzi_k;
        [ELSE alta_secventa;]
    END CASE;
    Sau următoarea formă, în care fiecare clauză WHEN conține o expresie booleană.
    CASE
        WHEN conditie_1 THEN secventa_de_comenzi_1;
        WHEN conditie_2 THEN secventa_de_comenzi_2;
        ...
        WHEN conditie_k THEN secventa_de_comenzi_k;
        [ELSE alta_secventa;]
    END CASE;
  4. Instrucțiuni iterative

    1. LOOP

      LOOP
          secventa_de_comenzi
      END LOOP;
    2. WHILE

      WHILE conditie LOOP
          secventa_de_comenzi
      END LOOP;
    3. FOR

      FOR contor_ciclu IN [REVERSE] lim_inf..lim_sup LOOP
          secventa_de_comenzi
      END LOOP;
  5. Declararea unui bloc

    [DECLARE
        instructiuni de declarare]
    BEGIN
        instructiuni executabile (SQL sau PL/SQL)
    END;
    Exemplu:
    -- Programul afiseaza suma a doua numere.
    SET SERVEROUTPUT ON;
    DECLARE
        a	number;
        b	number;
        rez	number;
    BEGIN
        rez := a + b;
        dbms_output.put_line(rez);
    END;

II. Tipuri de date

  1. Înregistrări (RECORD)

    TYPE nume_tip IS RECORD
    (
        nume_camp1 tip_camp1;
        nume_camp2 tip_camp2;
        ...
    );
    Exemplu:
    -- Declararea tipului
    TYPE individ IS RECORD
    (
        cnp number;
        nume varchar2(100);
        prenume varchar2(100);
    );
    
    -- Declararea unei variabile de tipul <individ>
    v_angajat individ;
  2. Colecții

    1. Index-by table

      TYPE nume_tip IS TABLE OF tip INDEX BY tip_indexare
      Exemplu:
      SET SERVEROUTPUT ON;
      DECLARE
          -- Declar tipul elementelor din tabel.
          TYPE pereche is RECORD
          (
              num number,
              some_date date
          );
      
          -- Declar tabelul de elemente de tipul definit mai sus.
          -- Il voi indexa in functie de intregi astfel incat sa ma refer la
          -- elemente prin numere. (ex: v_tab(1), v_tab(2)).
      
          -- Poate fi folosit si BINARY_INTEGER pentru aceeasi cauza. De
          -- mentionat ca elementele dintr-un INDEX-BY Table NU pot fi
          -- indexate dupa tipuri standard precum INTEGER, NUMBER, etc. In
          -- schimb pot fi indexate dupa string-uri (VARCHAR2 etc.)
          TYPE valori is TABLE OF pereche INDEX BY PLS_INTEGER;
      
          -- Declar o variabila de tipul tabelului definit mai sus.
          v_tab valori;
          
          -- Declar o variabila de tipul structurii definite mai sus in care
          -- voi stoca informatiile ce vor fi puse ulterior in tabel.
          v_pereche pereche;
          v_start_date date := to_date('01-01-1970', 'dd-mm-yyyy');
      BEGIN
          for i in 1..5 loop
              -- Adaug in campul 'num1' pe i si in campul 'some_date' a "i"-a
              -- zi dupa 01.01.1970.
              v_pereche.num := i;
              v_pereche.some_date := v_start_date + i;
      
              -- Adaug in tabel structura realizata mai sus.
              v_tab(i) := v_pereche;
          end loop;
      
          -- Afisez elementele vectorului, separand fiecare camp prin spatiu.
          for i in 1..v_tab.COUNT loop
              dbms_output.put_line(v_tab(i).num || ' ' ||
                  to_char(v_tab(i).some_date, 'dd-mm-yyyy'));
          end loop;
      END;
      Output-ul pentru aceste instrucțiuni este următorul:
      1 02-01-1970
      2 03-01-1970
      3 04-01-1970
      4 05-01-1970
      5 06-01-1970
    2. Vectori

      TYPE nume_tip IS VARRAY(lungime_maxima) OF tip_elemente;
      Exemplu
      SET SERVEROUTPUT ON;
      DECLARE
          -- Declar tipul elementelor din vector.
          TYPE pereche is RECORD
          (
              num1 NUMBER,
              num2 NUMBER
          );
      
          -- Declar array-ul de elemente definite mai sus si initializez
          -- acest array.
          TYPE valori is VARRAY(256) OF pereche;
          v_vec valori := valori();
          
          -- Declar o variabila de tipul structurii definite mai sus in care
          -- voi stoca informatiile ce vor fi puse ulterior in vector.
          v_pereche pereche;
      BEGIN
          -- Adaug 5 de elemente in vector dupa regula descrisa mai jos.
          for i in 1..5 loop
              -- Maresc capacitatea de stocare a vectorului.
              v_vec.EXTEND;
      
              -- Regula: Adaug in campul 'num1' pe i si in campul 'num2' pe i-1.
              v_pereche.num1 := i;
              v_pereche.num2 := i - 1;
      
              -- Adaug in vector structura realizata mai sus.
              v_vec(v_vec.COUNT) := v_pereche;
          end loop;
      
          -- Afisez elementele vectorului, separand fiecare camp prin spatiu.
          for i in 1..v_vec.COUNT loop
              dbms_output.put_line(v_vec(i).num1 || ' ' || v_vec(i).num2);
          end loop;
      END;
      .
      /
      -- NOTA: Spre deosebire de INDEX-BY table, nu pot fi adaugate
      -- valori pe orice pozitie. Vectorul are initial lungimea 0,
      -- iar la fiecare apel al metodei EXTEND, el isi creste lungimea
      -- cu 1.
      Output-ul comenzii de mai sus va arăta în felul următor:
      1 0
      2 1
      3 2
      4 3
      5 4
    3. Nested tables (Tablouri imbricate)

      TYPE nume_tip IS TABLE OF tip_elemente;
      Exemplu
      SET SERVEROUTPUT ON;
      DECLARE
          -- Declar tipul elementelor din tabel.
          TYPE pereche is RECORD
          (
              num number,
              some_date date
          );
      
          -- Declar tabelul de elemente de tipul definit mai sus.
          TYPE valori is TABLE OF pereche;
      
          -- Declar o variabila de tipul tabelului definit mai sus.
          v_tab valori := valori();
          
          -- Declar o variabila de tipul structurii definite mai sus in care
          -- voi stoca informatiile ce vor fi puse ulterior in tabel.
          v_pereche pereche;
          v_start_date date := to_date('01-01-1970', 'dd-mm-yyyy');
      BEGIN
          for i in 1..5 loop
              -- Adaug in campul 'num1' pe i si in campul 'some_date' a "i"-a
              -- zi dupa 01.01.1970.
              v_pereche.num := i;
              v_pereche.some_date := v_start_date + i;
      
              -- Adaug in tabel structura realizata mai sus.
              v_tab.EXTEND;
              v_tab(v_tab.COUNT) := v_pereche;
          end loop;
      
          -- Afisez elementele vectorului, separand fiecare camp prin spatiu.
          for i in 1..5 loop
              dbms_output.put_line(v_tab(i).num || ' ' ||
                  to_char(v_tab(i).some_date, 'dd-mm-yyyy'));
          end loop;
      END;
      .
      /
      Executând blocul de mai sus, vom obține următorul rezultat (identic cu cel de la "Index-by" table)
      1 02-01-1970
      2 03-01-1970
      3 04-01-1970
      4 05-01-1970
      5 06-01-1970

      De menționat este faptul că există diferențe între "Index-By Table" și "Nested Table" și anume:

      • Nested Table

        -- Trebuie initializat
        -- tabelul cu un constructor.
        v_tab valori := valori();
        -- Nu este mentionat tipul dupa care se face
        -- ordonarea elementelor
        TYPE valori is TABLE OF pereche;
      • Index-by Table

        -- Initializarea se face implicit.
        v_tab valori;
        -- Este mentionat tipul in functie de care
        -- este determinata pozitia elementului in tabel
        TYPE valori is TABLE OF pereche INDEX BY PLS_INTEGER;
        Totodată, următorul tabel descrie diferențele semnificative dintre tipul de colecții:
        Nested Table Varray Index-by Table

        Nu are lungime maximă

        Are lungime maximă

        Nu are lungime maximă

        Elementele pot fi așezate în așa fel încât să existe elemente lipsă între oricare două elemente atunci când în acele spații s-au aflat alte elemente care au fost scoase ulterior. Nu pot fi adăugate elemente într-un mod împrăștiat ca la Index-by Table.

        Nu există locuri libere între elemente. Componentele unui Varray pot fi scoase doar de la sfârșitul vectorului.

        Elementele sunt aranjate într-un mod "împrăștiat" (ex: pot fi adăugate elemente pe pozițiile 1, 2, 4, iar pe poziția 3 să nu fie nimic).

        Poate fi stocat într-o bază de date.

        Poate fi stocat într-o bază de date.

        Nu poate fi stocat într-o bază de date.

        Inițializarea se face prin constructor.

        Inițializarea se face prin constructor.

        Inițializarea se face la declarare (implicit).

  3. Cursoare (CURSOR)

    CURSOR nume_cursor IS
        SELECT ...
    Cursoarele sunt folosite pentru a itera peste (a parcurge) rezultatele query-urilor (SELECT-urilor) executate asupra tabelelor. Fie configurația bazei de date generată de următorul script:
    CREATE TABLE myTable (
        id_info number primary key,
        country varchar2(50) default NULL,
        date_something varchar2(50) default NULL
    );
    
    INSERT INTO myTable (id_info,country,date_something) VALUES ('1','Bulgaria','15-07-10');
    INSERT INTO myTable (id_info,country,date_something) VALUES ('2','Gabon','21-08-12');
    INSERT INTO myTable (id_info,country,date_something) VALUES ('3','Morocco','17-06-12');
    INSERT INTO myTable (id_info,country,date_something) VALUES ('4','Thailand','09-08-12');
    INSERT INTO myTable (id_info,country,date_something) VALUES ('5','Hong Kong','06-08-10');
    INSERT INTO myTable (id_info,country,date_something) VALUES ('6','Saint Vincent and The Grenadines','18-09-11');
    INSERT INTO myTable (id_info,country,date_something) VALUES ('7','Mauritius','21-01-13');
    INSERT INTO myTable (id_info,country,date_something) VALUES ('8','Sudan','14-12-10');
    INSERT INTO myTable (id_info,country,date_something) VALUES ('9','Belize','04-12-11');
    INSERT INTO myTable (id_info,country,date_something) VALUES ('10','Afghanistan','22-05-11');
    Cursoarele pot fi declarate explicit (ca în definiția de mai sus) sau pot fi considerate implicite în urma unui query peste un tabel. Exemplu pentru declararea explicită:
    SET SERVEROUTPUT ON;
    DECLARE
        cursor curr is
            select * from myTable;
    BEGIN
        for i in curr loop
            dbms_output.put_line(i.id_info || ' ' || i.country);
        end loop;
    END;
    .
    /
    Exemplu pentru cursorul implicit:
    SET SERVEROUTPUT ON;
    BEGIN
        for i in (select * from myTable) loop
            dbms_output.put_line(i.id_info || ' ' || i.country);
        end loop;
    END;
    .
    /
    Ambele exemple produc următorul output:
    1 Bulgaria
    2 Gabon
    3 Morocco
    4 Thailand
    5 Hong Kong
    6 Saint Vincent and The Grenadines
    7 Mauritius
    8 Sudan
    9 Belize
    10 Afghanistan

III. Proceduri și funcții

  1. Proceduri

    CREATE OR REPLACE PROCEDURE nume_procedura [(lista parametrii)] AS
        [declaratiile variabilelor locale]
    BEGIN
        instructiuni
    END;
    Parametrii se scriu sub forma nume_parametru [scop] tip_parametru, unde [scop] poate fi: in, out, sau ambele (in out). Implicit, parametrii sunt de tipul in. Dacă se dorește memorarea unei valori într-o variabilă dată ca parametru, se folosește out, însă valoarea acestei variabile nu va putea fi citită decât dacă este însoțită de cuvântul cheie in.

    Exemplu de procedură:

    -- Tabel in care retin numerele pare.
    CREATE TABLE pare (
        nr number
    );
    
    -- Tabel in care retin numerele impare.
    CREATE TABLE impare (
        nr number
    );
    
    -- Procedura primeste ca parametru un numar pe care il introduce in
    -- tabelul 'pare' daca numarul introdus este 'par', altfel este introdus
    -- tabelul 'impare'.
    CREATE OR REPLACE PROCEDURE my_procedure(val number) AS
    BEGIN
        if val mod 2 = 0 then
            insert into pare values (val);
        else
            insert into impare values (val);
        end if;
    END;
    .
    /
    În urma execuției următoarei secvențe de instrucțiuni, vor fi introduse numărul 2 în tabelul par și 3 în tabelul impar.
    call my_procedure(2);
    call my_procedure(3);
  2. Funcții

    CREATE OR REPLACE FUNCTION nume_functie [(lista parametrii)]
        RETURN tip_valoare_returnata AS
    BEGIN
        instructiuni
    END;
    Funcțiile sunt asemănătoare procedurilor, singura diferență fiind faptul că ele trebuie să returneze și o valoare de tipul menționat în declarația funcției, conform definiției de mai sus.

    Exemplu:

    CREATE OR REPLACE FUNCTION prim(n number) RETURN number AS
        divisor number := 2;
    BEGIN
        while divisor <= n/2 loop
            if mod(n, divisor) = 0 then
                return 0;
            end if;
            divisor := divisor + 1;
        end loop;
    
        return 1;
    END;
    .
    /
    Funcția de mai sus primește un număr n și returnează 1 în cazul în care n este prim, 0 altfel. Iată un mod de utilizare al funcției:
    SET SERVEROUTPUT ON;
    BEGIN
        dbms_output.put_line(prim(6));
        dbms_output.put_line(prim(7));
        dbms_output.put_line(prim(9));
    END;
    .
    /
    În urma executării acelor instrucțiuni, se va produce următorul output:
    0
    1
    0