This shows you the differences between two versions of the page.
bd2:laboratoare:02 [2020/10/06 11:52] apetrescu0506 |
— (current) | ||
---|---|---|---|
Line 1: | Line 1: | ||
- | ====== Laboratorul 02 - PL/SQL Structuri de control și tipuri compuse și colecții ====== | ||
- | |||
- | ===== Obiective ===== | ||
- | |||
- | * Instrucțiuni | ||
- | * Tipuri compuse și colecții | ||
- | |||
- | ===== Instrucțiuni ===== | ||
- | |||
- | Limbajul PL/SQL combină puterea de procesare a datelor, specifică limbajelor procedurale, cu puterea de manipulare a datelor, specifică instrucțiunilor. Structurile de control reprezintă cea mai importantă completare adusă de PL/SQL limbajului SQL prin introducerea instrucțiunilor de control condiționale, iterative, secvențiale și necondiționale. Toate structurile acceptă în clauzele lor instrucțiuni imbricate. | ||
- | |||
- | ==== Instrucțiuni condiționale ==== | ||
- | |||
- | === Instrucțiunea IF ... THEN === | ||
- | |||
- | Sintaxa instrucțiunii este: | ||
- | |||
- | <code sql> | ||
- | IF conditions THEN | ||
- | statements; | ||
- | END IF; | ||
- | </code> | ||
- | |||
- | Unde: | ||
- | * conditions – reprezintă condițiile cerute pentru execuția instrucțiunilor | ||
- | * statements – reprezintă secvența de instrucțiuni condiționale | ||
- | |||
- | <note> | ||
- | Instrucțiunile care urmează după **THEN** se execută numai dacă toate condițiile din **conditions** sunt îndeplinite. | ||
- | </note> | ||
- | |||
- | <color red>Ex. 1.</color> Pentru un angajat cu funcția 'FI_MGR' care nu primește comision să se modifice comisionul la 10% (.1). Testați cu id-ul 108. | ||
- | |||
- | {{:bd2:laboratoare:l02ex01.png?730|}} | ||
- | |||
- | === Instrucțiunea IF ... THEN ... ELSE === | ||
- | |||
- | Sintaxa instrucțiunii este: | ||
- | |||
- | <code sql> | ||
- | IF conditions THEN | ||
- | statements_1; | ||
- | ELSE | ||
- | statements_2; | ||
- | END IF; | ||
- | </code> | ||
- | |||
- | Unde: | ||
- | * conditions – reprezintă condițiile cerute pentru execuția statements_1 | ||
- | * statements_1 – reprezintă secvența de instrucțiuni atunci când conditions este TRUE | ||
- | * statements_2 – reprezintă secvența de instrucțiuni atunci când conditions este FALSE | ||
- | |||
- | <color red>Ex. 2.</color> Să se acorde un comision de 10% din salariu angajaților care au o vechime de cel puțin 15 de ani în companie. (testati cu 108 si 149). | ||
- | |||
- | {{:bd2:laboratoare:l02ex02.png?730|}} | ||
- | |||
- | === Instrucțiunea IF ... THEN ... ELSIF ... ELSE === | ||
- | |||
- | Sintaxa instrucțiunii este: | ||
- | |||
- | <code sql> | ||
- | IF conditions_1 THEN | ||
- | statements_1; | ||
- | ELSIF conditions_2 THEN | ||
- | statements_2; | ||
- | ... | ||
- | [ELSE statements_k;] | ||
- | END IF; | ||
- | </code> | ||
- | |||
- | Unde: | ||
- | * conditions_1 – reprezintă setul de condiții cerute pentru execuția statements_1 | ||
- | * statements_1 – reprezintă secvența de instrucțiuni executate atunci când conditions_1 = TRUE | ||
- | * conditions_2 – reprezintă setul de condiții cerute pentru execuția statements_2 | ||
- | * statements_2 – reprezintă secvența de instrucțiuni executate atunci când conditions_2 = TRUE | ||
- | * statements_k – reprezintă secvența de instrucțiuni executate dacă niciuna dintre conditions_1..k-1 nu sunt verificate | ||
- | |||
- | <note> | ||
- | Verificarea seturilor de condiții se face secvențial, în ordinea specificată și fiecare set poate conține condiții multiple. | ||
- | |||
- | Se acceptă mai multe clause ELSIF dar o singură clasuză ELSE. | ||
- | |||
- | Clauza ELSE este opțională, aceasta poate să lipsească din construcția instrucțiunii. | ||
- | </note> | ||
- | |||
- | |||
- | <color red>Ex. 3. </color> Să se acorde un comision de 10%, conducerii companiei care nu a primit comision, dar președintele să nu primească comision. | ||
- | |||
- | {{:bd2:laboratoare:l02ex03.png?600|}} | ||
- | |||
- | === Instrucțiunea CASE === | ||
- | |||
- | Sintaxa instrucțiunii este: | ||
- | |||
- | <code sql> | ||
- | [<<label_name>>] | ||
- | CASE expression | ||
- | WHEN value_1 THEN statements_1; | ||
- | WHEN value_2 THEN statements_2; | ||
- | ... | ||
- | [ELSE statements_k;] | ||
- | END CASE [label_name]; | ||
- | </code> | ||
- | |||
- | Unde: | ||
- | * expression – reprezintă expresia care se va evalua | ||
- | * statements_1 – reprezintă secvența de instrucțiuni executate în cazul în care expression = value_1 | ||
- | * statements_2 – reprezintă secvența de instrucțiuni executate în cazul în care expression = value_2 | ||
- | * statements_k – reprezintă secvența de instrucțiuni executate dacă expression <> value_1, value_2, ... | ||
- | |||
- | <color red>Ex. 4.</color> Să se calculeze impozitul pe salariu al unui angajat, după algoritmul: | ||
- | * Din tabela JOBS se află salariul minim, respectiv maxim, pentru funcția pe care o deține; | ||
- | * Dacă angajatul are salariul minim, atunci impozitul este de 10% din salariu. | ||
- | * Dacă angajatul are salariul maxim, atunci impozitul este de 30% din salariu. | ||
- | * Altfel impozitul este de 20% din salariu. | ||
- | * Se afișează numele și impozitul angajatului. | ||
- | |||
- | {{:bd2:laboratoare:l02ex04.png?730|}} | ||
- | |||
- | === Instrucțiunea SEARCHED CASE === | ||
- | |||
- | PL/SQL pune la dispoziția dezvoltatorilor **SEARCHED CASE**. Sintaxa instrucțiunii **SEARCHED CASE** este: | ||
- | |||
- | <code sql> | ||
- | [<<label_name>>] CASE | ||
- | WHEN search_condition_1 THEN sequence_of_statements_1; | ||
- | WHEN search_condition_2 THEN sequence_of_statements_2; | ||
- | ... | ||
- | WHEN search_condition_N THEN sequence_of_statements_N; | ||
- | [ELSE sequence_of_statements_N+1;] | ||
- | END CASE [label_name]; | ||
- | </code> | ||
- | |||
- | <color red>Ex. 5.</color> Folosirea instrucțiunii searched CASE: | ||
- | |||
- | {{:bd2:laboratoare:l02ex05.png?730|}} | ||
- | |||
- | <color red>Ex. 6.</color> Folosirea instrucțiunii CASE pentru inițializarea unei variabile și în clauza where a unei cereri: | ||
- | |||
- | {{:bd2:laboratoare:l02ex06.png?730|}} | ||
- | |||
- | <color red>Ex. 7.</color> Exemplu de folosire a instrucțiunii CASE în clauza SELECT. | ||
- | |||
- | {{:bd2:laboratoare:l02ex07.png?730|}} | ||
- | |||
- | <note important> | ||
- | Observații: | ||
- | * Clauza **ELSE** poate să lipsească din instrucțiunea **CASE**; | ||
- | * Dacă lipsește clauza **ELSE** și niciuna dintre clauzele **WHEN** nu se execută atunci apare eroarea **CASE_NOT_FOUND**. | ||
- | </note> | ||
- | |||
- | ==== Instrucțiuni de repetiție ==== | ||
- | |||
- | === Instrucțiunea LOOP === | ||
- | |||
- | Instrucțiunea LOOP este folosită pentru execuția ciclică a unei secvențe de instrucțiuni. | ||
- | |||
- | Sintaxa instrucțiunii este: | ||
- | |||
- | <code sql> | ||
- | [<<label_name>>] | ||
- | LOOP | ||
- | statements; | ||
- | [EXIT [WHEN conditions];] | ||
- | [CONTINUE [WHEN conditions];] | ||
- | END LOOP [label_name]; | ||
- | </code> | ||
- | |||
- | Unde: | ||
- | * statements – reprezintă secvența de instrcțiuni execuate în cadrul buclei | ||
- | * label_name – este eticheta următoarei instrucțiuni la care se forțează saltul, care poate să lipsească | ||
- | * conditions – reprezintă setul de condiții la care se forțează ieșirea din buclă și nu este obligatoriu, iar dacă lipsește atunci bucla are o singură iterație | ||
- | |||
- | <note> | ||
- | Observații | ||
- | * După fiecare procesare a unui ciclu, controlul revine la începutul ciclului și se reia execuția instrucțiunilor | ||
- | * Instrucțiunea **EXIT** este folosită pentru ieșirea din ciclu, cu sau fără verificare de condiție | ||
- | * **EXIT** poate fi executată fie ca o acțiune dintr-un **IF** în cadrul blocului **LOOP**, fie ca o instrucțiune individuală în cadrul unui ciclu | ||
- | * O clauză **WHEN** poate fi înlocuită de instrucțiunea **IF**, cum se vede în construcția următoare: | ||
- | |||
- | <code sql> | ||
- | LOOP | ||
- | statements; | ||
- | IF conditions THEN | ||
- | statements_in_if; | ||
- | EXIT; -- exit loop immediately | ||
- | END IF; | ||
- | END LOOP; | ||
- | </code> | ||
- | </note> | ||
- | |||
- | <color red>Ex. 8.</color> În exemplul următor se dorește să se facă o listă cu data angajării și veniturile angajaților care fac parte dintr-un departament specificat. | ||
- | |||
- | {{:bd2:laboratoare:l02ex08.png?730|}} | ||
- | |||
- | |||
- | === Instrucțiunea WHILE === | ||
- | |||
- | Instructiunea WHILE este folosită pentru realizarea unei structuri repetitive condiționate. | ||
- | |||
- | Sintaxa instrucțiunii este: | ||
- | <code sql> | ||
- | WHILE conditions | ||
- | LOOP | ||
- | statements; | ||
- | END LOOP; | ||
- | </code> | ||
- | |||
- | Unde: | ||
- | * conditions – reprezintă setul de condiții pentru execuția buclei | ||
- | * statements – reptezintă secvența de instrucțiuni executată în cadrul buclei | ||
- | |||
- | <color red>Ex. 9.</color> Să se modifice exercițiul precedent astfel încât să folosească instrucțiunea WHILE. | ||
- | |||
- | {{:bd2:laboratoare:l02ex09.png?730|}} | ||
- | |||
- | === Instrucțiunea FOR === | ||
- | |||
- | Instrucțiunea FOR este folosită pentru realizarea unei structuri repetitive. | ||
- | |||
- | Sintaxa instrucțiunii este: | ||
- | |||
- | <code sql> | ||
- | FOR contor IN [REVERSE] value1 .. value2 | ||
- | LOOP | ||
- | statements | ||
- | END LOOP; | ||
- | </code> | ||
- | |||
- | Unde: | ||
- | * contor – este contorul folosit pentru incrementarea (decrementarea) iterațiilor | ||
- | * value1 .. value2 – reprezintă valorile minime și maxime ale contorului (value1 <= value2) | ||
- | * statements – reprezintă secvența de instrucțiuni executate în cadrul buclei | ||
- | |||
- | <note> | ||
- | Observații: | ||
- | * Întotdeauna trebuie să se îndeplinească condiția **value1 < value2** pentru a se intra în bucla **FOR**, indiferent dacă se folosește **IN** sau **IN REVERSE** | ||
- | * Incrementarea (cazul cu **IN**) sau decrementarea (cazul **IN REVERSE**) contorului este făcută automat cu 1 (cu data tipul PLS_INTEGER) | ||
- | </note> | ||
- | |||
- | <color red>Ex. 10.</color> Să se modifice exercițiul precedent astfel încât să folosească instrucțiunea FOR. | ||
- | |||
- | {{:bd2:laboratoare:l02ex10.png?730|}} | ||
- | |||
- | <note> | ||
- | Observații: | ||
- | * Buclele pot fi imbricate pe mai multe niveluri | ||
- | * În general, o buclă internă nu termină execuția unui bucle care o include, exceptând cazul când este generată o excepție | ||
- | * Pentru salturi de instrucțiuni, se folosește instrucțiunea **GOTO** | ||
- | * **GO** poate fi folosit în oricare dintre instrucțiunile prezentate | ||
- | * Instrucțiunea **GOTO** poate fi folosită și să se iasă dintr-o buclă | ||
- | </note> | ||
- | |||
- | <color red>Ex. 11.</color>Exemplu de folosire a instrucțiunii GOTO. | ||
- | |||
- | {{:bd2:laboratoare:l02ex11.png?730|}} | ||
- | |||
- | <color red>Ex. 12.</color> Exeplu de ieșise dintr-o buclă folosind GOTO. | ||
- | |||
- | {{:bd2:laboratoare:l02ex12.png?730|}} | ||
- | |||
- | <color red>Ex. 13.</color> Să se scrie un bloc PL/SQL care face o listă cu numărul angajaților care au veniturile mai mici de 4000 (considerate venituri mici) și mai mari de 4000 (considerate venituri mari), pentru fiecare departament. Se va face o construcție folosind structuri de control și cicluri. Pentru departamentele care nu au niciun angajat se va afișa un mesaj. | ||
- | |||
- | {{:bd2:laboratoare:l02ex13.png?730|}} | ||
- | |||
- | ===== Tipuri compuse și colecție ===== | ||
- | |||
- | |||
- | ==== Tipul RECORD ==== | ||
- | |||
- | Tipurile scalare nu au componente interne, în timp ce tipurile compuse au componente interne care se pot manipula. | ||
- | |||
- | RECORD este un tip compus: | ||
- | * Folosit pentru a accesa liniile tabelelor sub formă de matrice | ||
- | * Asemănător cu o înregistrare a unei tabele cu excepția faptului că numele coloanelor sunt proprii fiecărei înregistrări | ||
- | |||
- | Declararea tipului RECORD se face conform următoarei sintaxe: | ||
- | |||
- | <code sql> | ||
- | TYPE nume_tip IS RECORD ( | ||
- | field_1 {datatype | variable%TYPE | table.column%TYPE | table%ROWTYPE} [ [NOT NULL] [{:= | DEFAULT} expression_1] ], | ||
- | field_2 {datatype | variable%TYPE | table.column%TYPE | table%ROWTYPE} [ [NOT NULL] [{:= | DEFAULT} expression_2] ], | ||
- | ... | ||
- | field_n {datatype | variable%TYPE | table.column%TYPE | table%ROWTYPE} [ [NOT NULL] [{:= | DEFAULT} expression_n] ] | ||
- | ); | ||
- | </code> | ||
- | |||
- | <note> | ||
- | Începând cu Oracle9i, pentru tipul RECORD sunt introduse câteva facilităţi: | ||
- | * Se poate insera (INSERT) o linie într-un tabel utilizând tipul RECORD | ||
- | * Se poate actualiza (UPDATE) o linie într-un tabel utilizând tipul RECORD (cu sintaxa SET ROW) | ||
- | * Se poate regăsi şi returna sau şterge informaţia din clauza RETURNING a comenzilor UPDATE sau DELETE | ||
- | * Dacă în comenzile UPDATE sau DELETE se modifică mai multe linii, atunci pot fi utilizate colecţii de înregistrări cu sintaxa BULK COLLECT INTO | ||
- | </note> | ||
- | |||
- | <color red>Ex. 14.</color> Un exemplu de utilizare a tipului RECORD. | ||
- | |||
- | {{:bd2:laboratoare:l02ex14.png?730|}} | ||
- | |||
- | <color red>Ex. 15.</color> Ex. 15. Folosindu-se tipul compus RECORD: | ||
- | * Să se creeze un record de forma tabelului dept | ||
- | * Să se insereze un nou departament folosind o variabilă de tip record | ||
- | * Să se selecteze înregistrarea inserată într-un record | ||
- | * Să se updateze înregistrarea inserată folosindu-se record și să se returneze într-un record informații | ||
- | * Să se șteargă departamentul creat și să se returneze într-un record informații. | ||
- | |||
- | {{:bd2:laboratoare:l02ex15.png?730|}} | ||
- | |||
- | ==== Tipuri colecție ==== | ||
- | |||
- | Tipurile colecție sunt: | ||
- | * Varrays | ||
- | * Index-by table | ||
- | * Nested tables | ||
- | |||
- | Tipurile colecție au **atribute** și **metode**. (În funcție de tip, atributele se comporta diferit). | ||
- | | ||
- | ^ Atribute și metode ^ Descriere ^ | ||
- | | COUNT | Numărul de componente din colecţie | | ||
- | | FIRST | Indicele primului element din tablou | | ||
- | | LAST | Indicele ultimului element din colecție | | ||
- | | EXISTS | Întoarce TRUE dacă există în coleție componenta cu indexul specificat | | ||
- | | NEXT | Întoarce indicele următoarei componente | | ||
- | | PRIOR | Întoarce indicele componentei anterioare | | ||
- | | DELETE | Șterge una sau mai multe componente | | ||
- | | EXTEND | Adaugă elemente la sfârşitul colecției | | ||
- | | LIMIT | Întoarce numărul maxim de elemente al unei colecţii (pentru vectori), null pentru tablouri imbricate | | ||
- | | TRIM | Șterge elementele de la sfârşitul unei colecţii | | ||
- | |||
- | | ||
- | === Tipul VARRAY === | ||
- | |||
- | Vectorii (varray) sunt structuri asemănătoare vectorilor din limbajele C sau Java. Vectorii au o dimensiune maximă (constantă) stabilită la declarare. Se utilizează pentru modelarea relaţiilor one-to-many, atunci când numărul maxim de elemente din partea "many" este cunoscut şi ordinea elementelor este importantă. Fiecare element are un index. **Indexarea începe de la 1**. | ||
- | |||
- | Tipul de date vector este declarat utilizând sintaxa: | ||
- | |||
- | <code sql> | ||
- | TYPE name IS {VARRAY | VARYING ARRAY} (max_length) OF element_type [NOT NULL]; | ||
- | </code> | ||
- | |||
- | <color red>Ex. 16.</color> Exemplul folosire varray. | ||
- | |||
- | {{:bd2:laboratoare:l02ex16.png?730|}} | ||
- | |||
- | === Tipul ASSOCIATIVE ARRAY === | ||
- | |||
- | Tipul ASSOCIATIVE ARRAY se mai numește și INDEX BY TABLE (tabel indexat). | ||
- | |||
- | Un table indexat în PL/SQL are două componente: | ||
- | * Coloană ce cuprinde cheia primară pentru a avea acces la liniile tabelului | ||
- | * O coloană care include valoarea efectivă a elementelor tabelului | ||
- | |||
- | Declararea tipului ASSOCIATIVE ARRAY se face cu următoarea sintaxă: | ||
- | |||
- | <code sql> | ||
- | TYPE name IS TABLE OF {data_type | variable%TYPE | table.column%TYPE [NOT NULL] | table%ROWTYPE} INDEX BY data_type_index; | ||
- | </code> | ||
- | |||
- | Unde: | ||
- | * data_type_index poate fi String sau Integer | ||
- | |||
- | <note important> | ||
- | Observații: | ||
- | * Elementele unui ASSOCIATIVE ARRAY nu sunt într-o ordine particulară şi pot fi inserate cu chei arbitrare | ||
- | * Deoarece nu există constrângeri de dimensiune, dimensiunea tabelului se modifică dinamic | ||
- | * Un ASSOCIATIVE ARRAY nu poate fi iniţializat în declararea sa | ||
- | * Un ASSOCIATIVE ARRAY neiniţializat este vid (nu conţine nici valori, nici chei) | ||
- | * Un element al unui ASSOCIATIVE ARRAY este nedefinit atâta timp cât nu are atribuită o valoare efectivă | ||
- | * Dacă se face referire la o linie care nu există, atunci se produce excepţia **NO_DATA_FOUND**. | ||
- | </note> | ||
- | |||
- | <color red>Ex. 17.</color> Exemplu de folosire ASSOCIATIVE ARRAY. | ||
- | |||
- | {{:bd2:laboratoare:l02ex17.png?730|}} | ||
- | |||
- | === Tipul Nested Table === | ||
- | |||
- | Un tablou imbricat este o mulţime neordonată de elemente de acelaşi tip. Valorile de acest tip: | ||
- | * Pot fi stocate în baza de date | ||
- | * Pot fi prelucrate direct în instrucţiuni SQL | ||
- | * Au excepţii predefinite proprii | ||
- | |||
- | Comanda de declarare a tipului de date tablou imbricat are sintaxa: | ||
- | <code sql> | ||
- | TYPE name IS TABLE OF {data_type | variable%TYPE | table.column%TYPE [NOT NULL] | table%ROWTYPE} [NOT NULL]; | ||
- | </code> | ||
- | |||
- | <note> | ||
- | Observații: | ||
- | * Pentru adăugarea de linii intr-un tablou imbricat, acesta trebuie sa fie inițializat cu ajutorul constructorului | ||
- | * PL/SQL apelează un constructor numai în mod explicit | ||
- | * Tabelele indexate nu au constructori | ||
- | * Constructorul primeşte ca argumente o listă de valori numerotate în ordine, de la 1 la numărul de valori date ca parametrii constructorului | ||
- | * Dimensiunea iniţială a colecţiei este egală cu numărul de argumente date în constructor, când aceasta este iniţializată | ||
- | * Pentru vectori nu poate fi depăşită dimensiunea maximă precizată la declarare | ||
- | * Atunci când constructorul este fără argumente va crea o colecție fără niciun element (vida), dar care are valoarea not null | ||
- | </note> | ||
- | |||
- | <color red>Ex. 18.</color> Exemplu de folosire al unui tabel imbricat. | ||
- | |||
- | {{:bd2:laboratoare:l02ex18.png?730|}} | ||
- | |||
- | ==== Colecții stocate ==== | ||
- | |||
- | Tipurile colecție pot fi definite direct în baza de date. | ||
- | |||
- | ^ Collection Type ^ Number of Elements ^ Subscript Type ^ Dense or Sparse ^ Where Created ^ Can Be Object Type Attribute ^ | ||
- | | Associative array (or index-by table) | Unbounded | String or PLS_INTEGER/BINARY_INTEGER | Either | Only in PL/SQL block | No | | ||
- | | Nested table | Unbounded | Integer | Starts dense, can become sparse | Either in PL/SQL block or at schema level | Yes | | ||
- | | Variable-size array (varray) | Bounded | Integer | Always dense | Either in PL/SQL block or at schema level | Yes | | ||
- | |||
- | |||
- | <color red>Ex. 19.</color> Definirea tipurilor direct în baza de date. | ||
- | |||
- | {{:bd2:laboratoare:l02ex19.png?730|}} | ||
- | |||
- | ==== BULK COLLECT ==== | ||
- | |||
- | Pentru a insera mai multe valori într-o variabilă de tip colecție se poate folosi BULK COLLECT INTO. | ||
- | |||
- | |||
- | <color red>Ex. 20.</color> Folosirea BULK COLLECT INTO cu varray. | ||
- | |||
- | {{:bd2:laboratoare:l02ex20.png?730|}} | ||
- | |||
- | <color red>Ex. 21.</color> Folosirea BULK COLLECT INTO cu index-by table. | ||
- | |||
- | {{:bd2:laboratoare:l02ex21.png?730|}} | ||
- | |||
- | <color red>Ex. 22.</color> Folosirea BULK COLLECT INTO cu nested table. | ||
- | |||
- | {{:bd2:laboratoare:l02ex22.png?730|}} | ||
- | |||
- | ==== Colecții de înregistrări ==== | ||
- | |||
- | Se poate crea un "tabel" care sa aibă coloane definite de dezvoltatori folosind un table(index-by sau nested) care să fie de tipul RECORD. | ||
- | |||
- | <color red>Ex. 23.</color> Crearea unui tabel cu coloanele definite de utilizator. | ||
- | |||
- | {{:bd2:laboratoare:l02ex23.png?730|}} | ||
- | |||