Sunteți pe pagina 1din 81
ee Viad DIACONITA lon LUNGU Anda VELICANU BAZE DE DATE Bye Bea INTRODUCERE iN PL/SQL (PROCEDURAL LANGUAGE EXTENSION TO SQL) L1 Introducere PL/SQL este un limbaj procedural structurat pe bloc, programele putand fi imparfite in blocuri logice, constructiile PL/SQL continand structuri de control procedurale si comenzi descriptive SQL. Blocurile PL/SQL sunt procesate de motorul PL/SQL care poate fi rezident pe serverul ORACLE sau pe un alt instrument de dezvoltare (ex.: Oracle Forms, Reports, JDeveloper etc.). Programarea in PL/SQL este modularizata, in acest sens se utilizeazi blocurile care grupeaza instructiunile. Tipurile de date din SQL pot fi folosite in PL/SQL. Pentru a putea lucra cu limbajul PL/SQL avem nevoie in primul rand de o conexiune la o bazi de date Oracle si de un instrument de dezvoltare prin care si interactionim cu serverul Oracle. Pentru instalarea si configurarea instantei bazei de da date se poate utiliza ghidul electronic pus la dispozitie de catre compania Oracle odata cu kit-ul de instalare. Ca instrument de dezvoltare se poate utiliza SQL*plus care se instaleazi impreund cu instanfa Oracle sau se poate utiliza SQL Developer, un mediu de dezvoltare mai prietenos disponibil gratuit pe site-ul companiei Oracle (www. oracle .com). Schema bazei de date pe care se bazeazi exemplele din aceasta carte se poate vedea in figura 1. Scriptul pentru crearea acestor tabele este redat in Anexa 1 si se poate descirea de pe site-ul http://bd.ase.ro impreuni cu scriptul pentru adiugarea inregistrarilor. Baze de date, Limbajul PL/SQL | Introducere in PL/SQL (Procedural Language Extension to SQL) 11 1.2 Blocuri PL/SQL | Orice unitate PL/SQL contine unul sau mai multe blocuri, complet separate sau imbricate. Fiecare bloc este compus din sectiuni care pot fi obligatorii sau optionale. Componentele unui bloc PL/SQL | Un bloc PL/SQL este compus din pana la 3. sectiuni: declarativa (optionald), executabilé (obligatorie) si de tratare a exceptiilor (optionala). Structura unui bloc PL/SQL poate fi prezentata astfel: DECLARE (Optional) 2 | variabile, cursori, exceptii e BEGIN (Obligatoriu) i g comenzi SQL (asigura accesul la baza de date) z & structuri de programare procedurala PL/SQL 82 3 EXCEPTION (Optional) 2 actiuni ce se executi cfnd apare o eroare 5 END; (Obligatoriu) = z fn cadrul blocului pot aparea instructiuni SQL care asigurai accesul la baza | 3 de date, de exemplu pentru efectuarea unor actualizari, dar operatiile efectuate cu : 3 | variabilele PL/SQL in cadrul instructiunilor procedurale nu presupun accesarea - | bazei de date. 5 3 Observatii: Lt * se foloseste (;) dupa fiecare instructiune SQL sau instructiune de £ control PL/SQL; Se = + blocul PL/SQL se termina cu (;); * comentariile se pot realiza folosind (--) pentru fiecare linie de cod comentata sau (/* */) pentru mai multe linii comentate; * se foloseste (/) pentru a lansa un bloc anonim in bufferul SQL; * — instructiunile nu sunt CASE SENSITIVE. Blocurile PL/SQL pot fi executate 0 singuré dat& (cazul blocurilor anonime), pot fi stocate in baza de date pentru a fi apelate ulterior (cazul funetiilor, Tipe ‘MuweeR IREGIUNE VAnCHAPZa procedurilor si pachetelor stocate) sau pot fi realizate si apelate la nivelul programelor de aplicatii (functii, proceduri, triggeri de aplicatii). in paragrafele DEHN Toc nEGiNE urmatoare ne vom referi pe scurt la fiecare dintre aceste tipuri de blocuri, urménd si le detaliem in capitole separate. 12 Baze de date. Limbajul PL/SQL Blocurile anonime prezintd urmiatoarele caracteristici: * nu sunt stocate in baza de date; * se declara inline, in locul in care se doreste executia lor; * se executé in momentul rularii; Daca dorii si reutilizati un bloc anonim va sféituim s& salvati codul sursi pe hard disk intr-un fisier de tip .sql sau xt. La modul general un bloc PL/SQL anonim poate avea urmittoarea forma: DECLARE eventualele initializari; ~ de exemplu: v_variabila tip_de_date; BEGIN -- instructiuni executabile; EXCEPTION WHEN exceptie THEN actiune; END; / pentru a putea fi ulterior accesate variabilele, adresare lor fiind realizata astfel: eticheta_bloc.variabila DECLARE << eticheta_bloc >> DECLARE BEGIN END eticheta_bloc; END; -- declararea variabilelor se face precizand tipul de date si realizandu-se Blocurile PL/SQL se pot imbrica gi se pot eticheta cu <> Introducere in PL/SQL (Procedural Language Extension to SQL) 13 Proceduri si functii Sunt blocuri PL/SQL care au nume si pot fi stocate la nivelul bazei de date sau la nivel de aplicatie (de exemplu in mediul de dezvoltare Oracle Developer Suite — Forms si Reports). in cazul procedurilor si functiilor sectiunea DECLARE este inlocuita de definitia acesteia prin sintaxa CREATE [or replace] PROCEDURE/FUNCTION (lista parametrilor $i tipul acestora), de exemplu: CREATE [OR REPLACE] PROCEDURE nume > procedura (lista parametri) Is CREATE [OR REPLACE] FUNCTION nume_functie (lista parametri) RETURN tip_data RETURN valoare [EXCEPTION] END; / Pachetele de subprograme sunt utilizate pentru a grupa mai multe proceduri si functii utilizate pentru un anumit tip de prelucrari. Declansatorii pe baza de date sunt blocuri PL/SQL asociate tabelelor (de baz& sau virtuale) si lansate automat in executie cand are loc 0 comanda de manipulare (insert/update/delete). 14 Baze de date. Limbajul PL/SQL Declansatorii de aplicatie sunt blocuri PL/SQL asociate unor evenimente din cadrul aplicatiei (de exemplu: deplasarea mouse-ului, apasarea unui buton) si lansate in executie automat la aparitia acestor evenimente. 13 Utilizarea operatorilor si functiilor in PL/SQL Operatorii utilizagi In cadrul blocurilor PL/SQL se pot utiliza aceiasi operatori ca gi in cazul limbajului SQL. In plus fafa de acestia apare operatorul de atribuire (: | Operator Caracteristici +5%4, ** (op. Operatori aritmetici exponential) AND, OR, NOT Operatori logici | _S>=>5< numeric gi caracter <->data. Pentru conversii explicite se utilizeaza funcfiile TO_DATE, TO_NUMBER, TO_CHAR in mod aseminator cu limbajul sau. Afisarea pe ecran a valorilor variabilelor sau a mesajelor in PL/SQL se realizeazi prin apelarea functiilor PUT LINE sau PUT din pachetul standard DBMS_OUTPUT. Aceste doua functii primesc ca parametru un sir de caractere gi- | afigeazi. Diferenta dintre cele doua functii este aceea c& prima afiseazi mesajul dupa care trece la linia urmitoare, iar cea de a doua afigeazi mesajul pe linia curent, Functiile PUT_LINE si PUT sunt necesare deoarece nu putem accesa variabilele declarate in blocurile PL/SQL direct din mediul SQL (pentru a le afiga cu PROMPT). in unele medii de dezvoltare, ca de exemplu in SQL*Plus, trebuie utilizata la inceputul sesiunii comanda SET SERVEROUTPUT ON care activeazi bufferul pentru afisare. SET SERVEROUTPUT ON DBMS_OUTPUT.PUT_LINE ('... DBMS_OUTPUT.PUT ( END; 1 De exemplu, vom realiza un bloc PL/SQL care si afigeze un mesaj. Pentru a executa blocul utilizim mediul de dezvoltare SQL Developer. Mai intai este hecesara stabilirea conexiunii cu serverul Oracle: click dreapta pe eticheta Connections din stanga ecranului si completim detaliile referitoare la conexiune: ume utilizator si parola, adresa IP a serverului si portul, numele instantei bazei de date, , Introducere in PL/SQL (Procedural Language Extension to SQL) 17 4 oa Oza TY TEESE ea Mow tore het Sapce Ys Bhratin Tee ep o (St Yew Honote Bin Saye Verney Mein Toe BO G58a 9 xem 0-0-5. Goa 9° kam 0-0-5. — : vss ‘ et 1 Oe Baze de date. Limbajul PL/SQL = 9 4 [pi omor.ror unm (tesbeat USL ete taba) precedes ee he [Prfenas sort one, WQerpan|fprniace | owns cam | Cov cape eae crew et ap sept mh ene om ab) proce! cenit comune tet secs DECI, ECU, 96 TATA A ecEEIOR | Figura 2 Executia blocurilor PL/SQL in SQL. Developer Figura 1 Realizarea conexiunii cu serverul Oracle Codul sursa al blocului este redat mai jos: SET SERVEROUTPUT ON Dupi conectare apare fereastra in care putem serie si executa blocurile, in ~-INTRODUCEM COMENTARII: in acest caz sectiunea mod asemanator cu modul de lucru cu instructiunile SQL. Pentru executia a ¢ DECLARE lipsegte blocurilor se da click pe unul dintre butoanele Execute Statement (F9) sau Run --blocul afigeaz& un mesaj Script (F5). BEGIN DBMS_OUTPUT.PUT_LINE ('Limbajul PL/SQL este un limbaj procedural!') ; DBMS_OUTPUT.PUT_LINE('Un bloc PL/SQL contine trei seciuni: DECLARATIVA, EXECUTABILA, DE TRATARE A EXCEPTIILOR') ; END; / Baze de date. Limbajul PL/SQL ~S Exercitii propuse 1. Recapitulati notiunile de baz ale limbajului SQL, precum si comenzile utilizate. 2. Creati o conexiune noua in SQL Developer si testati programul clasic Hello World! VARIABILE PL/SQL IL1 Declarare si initializare Declararea variabilelor se realizeazi in zona declarativa delimitata prin DECLARE a blocului sau sub-blocului. Initializarea variabilelor se poate face la declarare sau in zona de executie intre BEGIN si END. Variabilele vor fi vizibile si in blocurile imbricate, incluse in el, mai putin in sub-blocurile in care numele lor este redefinit, la fel ca in cazul limbajelor de Programare structurate, unde semnificatia unui nume definit de utilizator intr-un bloc/sub-bloc este data de cea mai apropiata declaratie anterioara locului folosirii. La declararea variabilelor PL/SQL se precizeaza obligatoriu tipul de dat si optional anumite restrictii si un sir valid de valori. Declararea si initializarea se realizeaza astfel: nume_variabila [CONSTANT] TIP_DATA [NOT NULL] [:= | DEFAULT expresie]; Constantele in PL/SQL trebuie obligatoriu initializate, iar ulterior nu isi vor putea schimba valoarea. Variabilele pentru care se precizeaza restrictia NOT NULL trebuie obligatoriu initializate, iar ulterior nu vor putea primi valoarea NULL. Pentru a putea urmari mai usor codul sursi se foloseste urmatoarea conventie de notare: ¢_nume Constanta - pentru declararea constantelor; v_nume Variabila - pentru declararea variabilelor; _nume Variabila_globala —pentru variabilele globale definite in zona de specificatii a unui pachet de subprograme si valabile pentru toate procedurile si functiile pachetului. eee 20 Baze de date. Limbajul PL/SQL 11.2. Tipuri de variabile Variabile PL/SQL = Scalare = Compozite + Referinti + LOB (Large Objects): NCLOB, CLOB, BLOB, BFILE + Obiect Variabile non-PL/SQL: variabile de mediu (BIND VARIABLES) 11.2.1 Variabile scalare Tipurile scalare contin valori simple, o variabila scalara poate confine la un moment dat 0 singura valoare si corespunde in principal tipurilor de date Oracle. Cele mai cunoscute si utilizate tipuri de date sunt prezentate in tabelul urmator: char (lung_max) - lungime fix de max 32.767 bytes = varchar? (lung_max) — lungime variabild de max 32.767 bytes = long [sir de caractere de lungime variabili 2GB] = number (precizie,scala) = boolean (true, false, null) = date = binary_integer si pls_integer (numere intregi intre - 2147483647 $i 2147483647) = binary_float si binary_double (pentru numere reale in varianta Oracle 10g) = timestamp (pentru fractiuni de secunda) Pentru alte tipuri de date puteti consulta capitolul 3 din [ORAPL]. Exemple: v_functie varchar2 (9); v_numar binary integer v_totalsal number (9,2) v_datainceput date:=sysdate+7; c_taxa constant number (3,2) :=8.25; v_valid boolean not null:=true; Variabile PL/SQL 21 Afisarea variabilelor PL/SQL se realizeaza prin intermediul functiei PUT_LINE din pachetului DBMS OUTPUT. Se poate utiliza operatorul de concatenare ( || ) pentru a afiga mai multe mesaje sau variabile pe aceeasi linie, de exemplu: DBMS_OUTPUT.PUT_LINE ('VALOAREA VARIABILEI ESTE: |\variabila); Popularea variabilelor cu valori din tabelele bazei de date Se utilizeazi comanda SELECT cu clauza INTO pentru popularea variabilelor PL/SQL cu valori ale atributelor din tabele, insd pentru aceasta cererile SELECT din cadrul blocurilor PL/SQL trebuie si furnizeze o singura linie rezultat, in caz contrar se va semnala o eroare. Pentru a putea accesa o anumit inregistrare sau valoare a unei coloane dintr-o tabeld este obligatoriu s& utilizim variabile PL/SQL, aga cum se observa si in exemplul urmator: Exemplu: Sd se afiseze numele angajatului cu codul 100: SET SERVEROUTPUT ON DECLARE --declaram variabila v_nume in care vom returna numele angajatului: v_nume VARCHAR2 (20) ; BEGIN -- utilizam instructiunea SELECT cu clauza INTO pentru a popula variabila: SELECT nume INTO v_nume FROM angajati WHERE id_angajat = 100; -- afisam valoarea varibilei: DBMS_OUTPUT. PUT_LINE('NUMELE ANGAJATULUI ESTE: ' || v_nume) ; END; / Rezultatele executiei blocului sunt prezentate in figura 2.1 _— 22 Baze de date. Limbajul PL/SQL Variabile PL/SQL 23 oe Ss Exemple: 2500 9¢ xan 0-0-5- eee ‘Sd se afiseze numele si prenumele angajatului cu codul 100: ae 1a. DECLARE Sree --declaram doua variabile pentru nume si 2G we come YOR): — i v_nume angajati.nume%TYPE; rae suai ir v_prenume angajati.prenume%TYPE; | aa [ BEGIN paar Figura 2.1 Executia blocului PL/SQL 1. Atributul %TYPE Pentru a declara o variabili PL/SQL care sa aiba acelasi tip de date cu o anumit& coloana dintr-o tabeli sau cu o alti variabilé declarati anterior putem: folosi atributul %TYPE. Declararea unei variabile cu % TYPE se face astfel: variabila sau variabilal tip_data; variabila2 _variabilal%TYPE; tabela.nume_coloani%TYPE; -- populam si afisam variabilele: SELECT nume, prenume INTO v_nume, v_prenume FROM angajati WHERE id_angajat = 100; DBMS_OUTPUT. PUT_LINE('NUMELE ANGAJATULUI ESTE:' || v_nume||' '| |v_prenume) ; END; Observatie: Restrictia NOT NULL a unei coloane nu se aplica si variabilei declarate prin folosirea atributului %TYPE. 2. Variabile de mediu sau variabile de legdtura ale aplicatiilor gazdi (BIND VARIABLES) Acestea sunt variabile de legaturi cu aplicatia in care ruleazi motorul PL/SQL si trebuie declarate in aplicatie (in mediul gazda), putand fi accesate i modificate in cadrul blocurilor PL/SQL. Dupa terminarea executiei blocului PL/SQL, variabila rimane in mediul gazdi cu valoarea primité in urma rul&rii blocului si poate fi pasati altui bloc, realizind astfel transmiterea de valori intre blocurile PL/SQL. Variabilele de mediu nu pot fi utilizate in cadrul procedurilor, functiilor sau pachetelor. Variabilele de mediu se declara in afara blocului PL/SQL cu ajutorul cuvantului cheie VARIABLE: VARIABLE g_numevariabili TIP Observagie: pentru declararea unei variabile de mediu de tip NUMBER nu se specifica precizia si scala; "4 Baze de date. Limbajul PL/SQL Variabilele de mediu se utilizeaza in cadrul unui bloc PL/SQL sau intr-o instructiune SQL din afara blocului prefixate cu (:) astfel: shost_variabila:=v_variabila; Variabilele de mediu se afigeazi fn afara blocului cu ajutorul comenzii PRINT (la afigare variabila nu se va prefixa cu “:”); PRINT g_numevariabili Exemple: 1. St se afigeze mesajul: Bloc PL/SQL cu ajutorul unei variabile de mediu: --declaram variabila de mediu: VARIABLE g _mesaj varchar2 (30) BEGIN -- atribuim mesajul variabilei "Bloc PL/SQL'; -- afisam valoarea variabilei in afara blocului: PRINT g_mesaj 2. Séi se afiseze numarul de comenzi a cdror modalitate de completare este online: SET SERVEROUTPUT ON -- declaram variabila de mediu: VARIABLE g_comenzi varchar2 (30) BEGIN -- utilizam o cerere SQL pentru a calcula si popula variabila cu numarul de comenzi: select count(*) into :g comenzi from comenzi where modalitate END; a -- afisam variabila: PRINT g_comenzi ‘online! ; Variabile PL/SQL 25 | Observatie: Se poate auto-afisa variabila prin setarea AUTOPRINT ON Exemplu: Sa se selecteze produsele si pretul acestora pentru acele produse care au prepul < preful mediu al produsului cu codul 3133 faré a utiliza 0 cerere imbricaté: SET SERVEROUTPUT ON SET AUTOPRINT ON VARIABLE g pret number BEGIN select avg(pret) into :g pret from rand_comenzi where id _produs = 3133; END; / --utilizam variabila de mediu intr-o interogare SQL: select * from rand_comenzi where pret< :g_pret; Figura 2.2 Executia blocului PL/SQL 26 Baze de date. Limbajul PL/SQL 3. Variabile de substitutie De regula, variabilele de substitutie sunt folosite pentru a transmite valori dinspre mediul SQL*Plus spre comenzile SQL sau blocurile PL/SQL, in timp ce variabilele de legatura (bind variables) sunt folosite pentru a transmite valori in sens invers sau pentru a transfera valori intre blocuri PL/SQL lansate succesiv (primul bloc seteaz variabila, urmatorul o consult). Prin variabilele de substitutie se pot transmite valori comenzilor SQL sau blocurilor PL/SQL lansate (folosind "&" sau "&&"). Se pot utiliza in comenzile SQL sau in blocurile PL/SQL prin "&nume_variabila" sau "&&nume_variabila". Variabilele de substitutie sunt locale sesiunii SQL in care au fost declarate. in mediul SQL variabilele de substitutie pot fi usor utilizate prin introducerea de valori de Ja tastatura utilizind ACCEPT, se pot defini cu DEFINE sau afisa pe ecran cu PROMPT; Exemplu: Sa se afigeze numarul de comenzi ale angajatului al cérui cod este introdus de la tastaturé de cdtre utilizator prin intermediul variabilei de substitutie &id_angajat: DECLARE v_nr_comenzi number (2) ; BEGIN --introducem id-ul angajatului cu ajutorul variabilei &id_angajat select count (nr_comanda) into v_nr_comenzi from comenzi where id_angajat=&id_angajat; dbms_output.put_line('Angajatul are: '| | v_nr_comenzi||' comenzi') ; END; / Variabile PL/SQL 27 (ea i f i 3 STR ml = Figura 2.3 Executia blocului PL/SQL fntr-un bloc PL/SQL se pot utiliza toate tipurile de variabile, respectind ins caracteristicile si regulile de utilizare ale acestora. in exemplul urmator se utilizeazi atat variabila de substitutie s_mume definita si initializata prin comanda DEFINE, cat si variabila de legatura g_salariul, dar si variabila local v_prenume de acelasi tip cu coloana nume din tabela Angajati. Variabila de substitutie definita cu DEFINE va fi implicit de tipul CHAR. Exemplu: Si se afiseze salariul si prenumele angajatului cu numele Abel: SET SERVEROUTPUT ON -- definim variabila de mediu VARIABLE g_salariul number -- definim variabila de substitutie DEFINE s_nume=Abel DECLARE --declaram variabila locala PL/SQL v_prenume angajati.nume%type; BEGIN select prenume,salariul into v_prenume, | salariul from angajati where nume='&s_nume'; 28 Baze de date. Limbajul PL/SQL Variabile PL/SQL 29 DBMS_OUTPUT.PUT_LINE ('Prenumele angajatului rE St ie = = a : este: '||v_prenume) ; foae 90 xe END; aio is EA ; aay Z | commas print g salariul 11.2.2 Tipuri de date compuse u radu eve Span di3138; 1. Tipul RECORD Reprezinti un grup de date logic corelate (de exemplu, datele despre un client: code, nume, adresa sunt diferite ca tip dar corelate logic). Atunci cand se declard un PL/SQL record pentru aceste cimpuri, ele pot fi manipulate ca o unitate, ficcare cémp (element al structurii) avand un nume si un tip de data, Atributele unui record sunt referite astfel: nume_record.nume_cémp. Declarea unui tip record se face astfel: | TYPE nume record IS RECORD (numecimp TIP_DATA [,nume_cimp TIP_DATA:=|DEFAULT valoare]...); Tar declararea unei variabile de acest tip: Variabili. NUME_RECORD; Figura 2.4 Executia blocului PL/SQL Exemplu: Utilizand un tip de data record definit de utilicator sd se afiseze ' Pretul minim al produsului cu codul 3133. Pentru a defini un record pe baza coloanelor unei tabele se foloseste : Yorowtype . In acest caz numele elementelor din record au acelagi nume ca si coloanele tabelei, acelasi tip de date si se gisesc in aceeasi ordine. NUME_RECORD tabelaY%SROWTYPE; DECLARE TYPE tip _produse IS RECORD (v_cod produse.id produsttype NOT NULL:=3000, v_den produse.denumire_produs%type, Exemplu: Sa se rescrie exemplul de mai sus utilizand atributul v_pret_min produse.pret_minttype) ; YROWTYPE:. vrec_prod tip _produse; a eS DECLARE dusetrowtype; SELECT id_produs, denumire produs, pret_min — prod produ; ‘YP! into vrec_prod from produse where id_produs=3133; dbms_output .put_line('Produsul: | II vrec_prod.v_den|| ' are pretul minim: "| |vrec_prod.v_pret_min) ; END; / SELECT * into vrec_prod from produse where id_produs=3133; dbms_output .put_line('Produsul: '| | vrec_prod.denumire produs|| ' are pretul minim: "| |vrec_prod.pret_min) ; END; / 30 Baze de date. Limbajul PL/SQL Variabile PL/SQL at 2. Specificati ce se va afiga la rularea urmatorului bloc PL/SQL (care contine blocuri imbricate, ilustrand domeniul de vizibilitate al unor variabile care au acelasi nume): DECLARE EXERCITI PROPUSE var NUMBER; BEGIN var 1; . DBM: , 1. Specificati ce se va afisa la rularea urmiitorului bloc PL/SQL: S_OUTPUT. PUT_LINE (var) ; ‘bli DECLARE see a v_varl NUMBER :=100; nae v_var2 NUMBER; | NUMBER ; 7 BEGIN v_var3 NUMBER := v_var2; | 3 7 : : var :=2; v_var4 VARCHAR (20) : 'variabila PL/SQL'; a our v_var5 NUMBER NOT NULL := v_varl; | _ OUTPUT. PUT_LINE (var) ; Ee END bloc1; c_const1 CONSTANT DATE TO_DATE ('12/02/2007', 'dd/mm/yyyy') + | DBMS_OUT: A c¢_const2 CONSTANT NUMBER NOT NULL := 2; }_OUTPUY. PUT_LINE (var) ; c_const3 CONSTANT NUMBER := NULL; | v_var6é NUMBER DEFAULT NULL; } ee - | DECLARE var NUMBER; BEGIN a2 ER; DBMS_OUTPUT. PUT_LINE('variabila 1 = '||v_varl); a DBMS_OUTPUT. PUT_LINE('variabila 2 "| |v_var2) ; oe ae DEMS_OUTPUT. PUT_LINE('variabila 3 = '||v_var3); s_OUTPUT. PUT_LINE (var) ; DBMS_OUTPUT.PUT_LINE('variabila 4 = ' | |v_var4); I DBMS OUTPUT. PUT LINE('variabila 5 = '||v_var5); <> 7 7 DECLARE DBMS_OUTPUT. PUT_LINE('constanta 1 = | |e_const1) ; var NUMBER; 7 BEGIN DBMS_OUTPUT. PUT_LINE('constanta 2 = var :=4; "| |c_const2) ; i DBMS_OUTPUT.PUT_LINE('constanta 3 = DBMS_OUTPUT. PUT_LINE (var) ; ‘| |e_const3) ; DBMS_OUTPUT. PUT_LINE (bloc2.var) ; DBMS_OUTPUT.PUT_LINE('variabila 6 = '||v_var6); END b1OSeiToe STU ., END; DBMS_ouUTPYfePUT_LINE (var) ; a DEPARTAMENTU BIBLIOTECA = atl Te Baze de date. Limbajul PL/SQL 32 DBMS_OUTPUT . PUT_LINE (var) ; END; / 3. Specificati ce se va afiga la rularea urmitorului bloc PL/SQL: DECLARE stoc NUMBER (3) :=600; mesaj VARCHAR2 (50) :='Produsul 101'; BEGIN DECLARE stoc NUMBER (3) :=10; mesaj VARCHAR2 (50) :='Produsul 102'; um VARCHAR2(10):= ' bucati '; BEGIN stoc:= stoc+l; mesaj:='Stocul pentru ' | |mesaj||' este de: '||stoc| |um; DBMS_OUTPUT. PUT_LINE (mesaj) ; END; stoc:= stoc+100; mesaj:='Stocul pentru '| |mesaj||' este de: '||stoc| |um; DBMS_OUTPUT. PUT_LINE (mesaj) 7 END; i 4, Sa se calculeze suma a doua numere, iar rezultatul si se divid’ cu 3. ‘Numerele se vor introduce de la tastatura: 5, S& se afigeze salariul marit cu un procent. Salariul si procentul se introduc de la tastatura. INTERACTIUNEA CU SERVERUL ORACLE PRIN COMENZI SQL Interactiunea se realizeazi prin intermediul comenzilor de definire a datelor - DDL (Data Definition Language), limbajul de gestiune a utilizatorilor - DCL (Data Control Language), limbajul de manipulare a datelor - DML (Data Manipulation Language), limbajul de control al tranzactiilor - TPL (Transaction Processing Language) astfel: ° PL/SQL suport toate comenzile din limbajul de manipulare a datelor (DML) si din cel de control al tranzactiilor (TPL). Un bloc PL/SQL nu e o tranzactie, comenzile Commit/ Rollback/ Savepoint sunt independente de bloc dar pot sa apara in interiorul sau. Comenzi DMI/TPL Execufie SELECT, INSERT, UPDATE, Se execut normal in cadrul bloculul DELETE, MERGE COMMIT, ROLLBACK, Pot aparea in bloc dar au efect asupra SAVEPOINT tuturor —tranzacfiilor din _interiorul si din afara acestuia. * PL/SQL nu suporti comenzi de definire a datelor sau de gestiune a utilizatorilor (DDL sau DCL) in cadrul unui bloc. Pentru executarea acestor comenzi se utilizeaz’ comanda EXECUTE IMMEDIATE ‘comanda DDL’: Comenzi DDL/DCL Execujie CREATE, ALTER, DROP EXECUTE IMMEDIATE ' CREATE GRANT, REVOKE TABLE.... ' Exemple: 1. Sa se creeze tabela PROD in cadrul unui bloc PL/SQL: SET SERVEROUTPUT ON BEGIN EXECUTE IMMEDIATE 'CREATE table prod AS SELECT * FROM produse where 1=2'; END; / 34 Baze de date. Limbajul PL/SQL i " 1 a) uegepaBy p =50; i410; end loop; END; / 48 Baze de date, Limbajul PL/SQL (5 ec SOL Botner orca = — ere Gcad 9e-¥GG O-0- 8. i Figura 4.3 Execufia blocului PL/SQL Structura WHILE.....LOOP....END LOOP are urmdtoarea structuré WHILE cond LOOP Secventa comenzi 1; Secventa comenzi 2; EXIT [WHEN cond] ; END LOOP; Exemple: 1. Sa se afiseze pe ecran utilizand structura WHILE LOOP...END LOOP numerele 9,7, 4, 0. set serveroutput on DECLARE v_nr number (2) i number (2 BEGIN while v_nr > 0 loop v_nr:=v_nr-i; itl; dbms_output .put_line(v_nr) ; end loop; = END; / 0; Structuri fundamentale de programare 49 2. Sa se afigeze in ordine angajatii cu codurile in intervalul 100-110 atét timp cat salariul acestora este mai mic decat salariul mediu: DECLARE v_sal angajati.salariulstype; v_salMediu v_sal%type; i number (4) 00; BEGIN --calculam salariul mediu: SELECT avg(salariul) into v_salmediu from angajati; dbms_output .put_line('Salariul mediu este: "| |v_salmediu) ; while i<=110 loop select salariul into v_sal from angajati where id_angajat: dbms_output .put_line('Salariatul cu codul "| [4] |" ave salariul: '||v_sal); 41; --iesim din ciclul WHILE la indeplinirea conditiilor exit when v_sal> LOOP v_var:=v_var+tl; 52 Baze de date. Limbajul PL/SQL EXIT WHEN v_var>10; <> LOOP EXIT LOOP_EXTERN WHEN condi; EXIT WHEN cond2; _—— Exercifii propuse 1. Utilizand structuri alternative, rezolvati ecuatia de gradul 2. 2, Afisati numele si telefonul aferente fiec&rui client cu id-ul numar par. 3. Construiti un bloc anonim pentru a exemplifica structurile LOOP imbricate, CURSORI $I TABELE INDEX BY Cursorul reprezinté 0 variabila PL/SQL speciala utilizata atunci cand se executi 0 comand SQL, iar Oracle Server deschide 0 zona de memorie (context area) in care comanda este executatd. Cursorul este un pointer catre aceasti zona. in PL/SQL se utilizeazi doua tipuri de variabile de tip cursor: cursorul implicit declarat pentru toate instructiunile de manipulare (INSERT/UPDATE/ DELETE); cursorul explicit declarat si gestionat de programator pentru utilizarea comenzii SELECT in cazul in care aceasta returneaza mai multe inregistrari. V.1 Cursorul implicit Cursorul implicit este declarat de Oracle Server pentru toate comenzile de manipulare a datelor (INSERT, UPDATE, DELETE) prezente jntr-un bloc PL/SQL. Daca o instructiune DML nu afecteaz& nicio linie a tabelei nu se genereazd eroare, insd exceptia trebuie tratati folosind atributele speciale ale cursorilor. Cursorul implicit prezinta o serie de atribute care pot fi utilizate intr-un bloc PL/SQL pentru verificarea executiei instructiunilor DML. Aceste atribute sunt: ¥ SQL%ROWCOUNT- reprezinté numiarul liniilor returnate pana in momentul curent; vy SQL%NOTFOUND - evaluat la TRUE in cazul in care cea mai recenta instructiune de manipulare nu a afectat nicio linie; ¥ SQL%FOUND - opusul lui SQL%NOTFOUND. 54 Baze de date. Limbajul PL/SQL. Exemple: 1. Sé se steargd un produs din tabela PRODUSE si sd se contorizeze numarul de randuri sterse. SET SERVEROUTPUT ON DECLARE v_rez NUMBER (2) ; BEGIN DELETE FROM produse WHERE id _produs=111; }QLROWCOUNT ; DBMS_OUTPUT.PUT_LINE (v_rez || ' randuri sterse') ; COMMIT ; END; / 2. Sa se incerce modificarea denumirii produsului cu codul 3, in cazul in care acest produs nu existd (comanda update nu afecteazétnicio inregistrare) va fi Gfisat un mesaj corespunzdtor. BEGIN UPDATE produse SET denumire_produs='cafea' WHERE id_produs=3; IF SQL&NOTFOUND THEN DBMS_OUTPUT.. PUT_LINE('Nu exista produsul cu acest cod') ; END IF; END; / Cursori si tabele index BY 55 ce es Ta =EaE ag et Bow Deter bn Se You Wow Tew bo G58 9% X85 0-0- 8- kk aul OG) asic: Deerteire soi aS eS, Op ney DEGRS UN ¢ amu soc J 2 Ge gaa ‘lod complete : = | Figura 5.1 Executia blocului PL/SQL 3. Sai se steargd din tabela EMP_SAL salariatul al caérui ID este introdus de utilizator prin intermediul variabilei g_angid: ACCEPT g_angid PROMPT 'Introduceti id-ul salariatului:' VARIABLE nr_sters varchar2 (100) DECLARE BEGIN DELETE FROM emp_sal WHERE id_angajat-&g_angid; imr_sters:=TO_CHAR(SQL%ROWCOUNT) | |! INREGISTRARI STERSE END; i PRINT nr_sters Rollback; 56 Baze de date, Limbajul PL/SQL 4m O-G: 8- Denne Denes 014 FT neces Sal aloe" seca varchar) PLETE Fa eap_el ERE 14 ages Figura 5.2 Executia blocului PL/SQL V.2. Cursorul explicit Cursorul explicit se utilizeaz& pentru a procesa individual fiecare linie Ginregistrare) returnati de o instrucfiune SELECT ce returneazi mai multe inregistriri, Multimea inregistrarilor returnate de o cerere este numit& mulfime rezultat. Cursorul pastreaz& un pointer citre linia curenta in cadrul unei multimi rezultat. Verificarea stiri unui cursor explicit se realizeazi prin intermediul urmitoarelor atribute: v nume_cursor%ISOPEN - evaluat la TRUE in cazul in care cursorul este deschis; ¥ nume_cursor %NOTFOUND - evaluat la TRUE in cazul in care cel mai recent citire a valorilor din cursor nu a returnat nicio linie; ¥ nume_cursor %FOUND - opusul lui %NOTFOUND; ¥ nume_cursor %ROWCOUNT - are ca valoare numarul liniilor returnate pana in momentul curent. Cursori gi tabele index BY 57 Prelucrarea cursorului explicit presupune parcurgerea urmatoarelor etape: © se declara variabilele in care vor fi incarcate valorile corespunzatoare unei linii din cursor; © se declara cursorul explicit, specificdndu-se un nume pentru acesta gi definindu-se interogarea de procesat in cadrul lui: nume_cursor IS SELECT. © se deschide cursorul prin intermediul instructiunii OPEN, care executi interogarea si legarea tuturor variabilelor referite. fnregistririle returnate de interogare sunt desemnate drept set activ de date, care pot fi de acum incarcate. OPEN nume_cursor; ¢ —utilizéndu-se instructiunea FETCH, se citeste linia curenta din cursor si se atribuie valorile variabilor. Fiecare inc&rcare determina mutarea pointerului cursorului la linia urmatoare din setul activ de date. FETCH nume_cursor INTO varl, var2,.. ; este inchis cursorul prin instructiunea CLOSE, care dezafecteazi setul activ de lini. Cursorul poate fi din nou deschis pentru a stabili un now set activ de lini. CLOSE nume_cursor; Pentru a procesa liniile unui cursor explicit se utilizeazi de obicei o structur’ repetitiva pentru executarea unei inc&rciri a variabilor pe baza valorilor din cursor (FETCH) in fiecare iteratie. fn final, toate liniile din setul activ sunt procesate si o comand’ FETCH executatd fara succes pozitioneazi atributul °%~NOTFOUND pe TRUE. inaintea primei citiri din cursor (prima comandi FETCH) valoarea cursor%NOTFOUND se evalueazi la NULL, ca si in cazul in care comanda FETCH nu se executi niciodat cu succes. Exemple: 1. Sa se afiseze lista cu numele $i salariul angajatilor din departamentul 60 folosind un cursor explicit: set serveroutput on DECLARE cursor ang cursor is select id_angajat, nume, salariul from angajati where id_departament=60; ang_id angajati.id_angajat%type; ang_nume angajati.numestype; 58 Baze de date. Limbajul PL/SQL, ang_sal angajati.salariulttype; BEGIN dbms_output .put_line('Lista cu salariariile angajatilor din departamentul 60'); open ang cursor; loop fetch ang_cursor into ang_id, ang_nume, ang_sal; exit when ang_cursor%not found; dbms_output .put_line('Salariatul '| |ang_nume||' are salariul: '||ang_sal); end loop; close ang_cursor; end; / [+ Orde SOC Deir erate = ‘ie Eat Ve Undone an Soute Versioning Morton Te He 3580 9% xamO-o 8 fet sogcatsoc into op $4) ang, esas * idee it en oy uttoteatad: | tae (Haart “Vmg.mae "ce edesels “tants 3 Bee a asa | eacteal Laces cee ealetul 200, Figura 5.3 Executia blocului PL/SQL Cursori si tabele index BY 59. Pentru o flexibilitate mai mare se poate utiliza o variabila de tip record pentru fnedrcarea valorilor din cursor. Aceasti variabila de tip record poate avea aceleasi atribute ca si cursorul prin specificarea proprietitii %ROWTYPE. in acest caz incitcarea din cursor se va face direct prin instructiunea FECH var_cursor INTO var_record. Exemplul de mai sus poate fi rescris astfel: set serveroutput on declare cursor ang cursor is select id_angajat, nume, salariul from angajati where id_departament=60; --tipul record pt incarcarea valorilor cursorului ang_rec ang_cursortrowtype; begin dbms_output .put_line('hista cu salariariile angajatilor din departamentul 60') ; open ang_cursor; loop fetch ang cursor into ang_rec; exit when ang_cursor%not found; dbms_output .put_line('salariatul ‘| Jang_xec.nume||' are salariul: '| |ang_rec.salariul) ; end loop; close ang_cursor; end; / 2. Sti se incarce in tabela T_ANG primii 5 angajati (id si nume) -- se creeazi tabela mesaje CREATE TABLE T_ANG (cod varchar2 (7), nume varchar2 (20) ) ; DECLARE v_id angajati.id_angajat%type; 60 Baze de date. Limbajul PL/SQL. v_nume angajati.nume%type; CURSOR cl IS SELECT id angajat, nume FROM angajati; BEGIN OPEN cl; FOR i IN 1..5 LOOP FETCH cl INTO v_id, v_nume; INSERT INTO t_ang VALUES(v_id, v_nume) ; END LOOP; CLOSE cl; END; / SELECT * FROM T_ANG; [wader See 5 ae tae © Eat Yew Uoote bm Sore Vows town Tole Dp 7 BO8e 9e:XG 0-9: 4- Qi 1D ODewke Pawnee | oe Bay DOSES UR G wemnnne i occ *gucu ag. 3 Dams Figura 5.4 Executia blocului PL/SQL Cursor! si tabele index BY 61 Testul de iesire din ciclul LOOP in acest caz se poate face gi cu ajutorul atributului %ROWCOUNT: --se gterg inregistr&rile din tabela T_ANG: Delete from T_ANG; DECLARE v_id angajati.id_angajat%type; v_nume angajati.numestype; CURSOR cl IS SELECT id angajat, nume FROM angajati; BEGIN OPEN cl; LOOP FETCH cl INTO v_id, v_nume; EXIT WHEN c1%ROWCOUNT>5 OR c1%NOTFOUND; INSERT INTO T_ANG VALUES (v_id, v_nume) ; END LOOP; CLOSE cl; END; / SELECT * FROM T_ANG; 3. Sai se afiseze primele 3 comenzi care au cele mai multe produse comandate. In acest caz inregistrarile vor fi ordonate descrescditor in functie de numérul produselor comandate: SET SERVEROUTPUT ON DECLARE CURSOR c_com IS select c.nr_comanda, count (r.id_produs) Numar from comenzi c, rand_comenzi r where c.nr_comanda=r.nr_comanda group by c.nr_comanda order by count (r.id_produs) desc; xec_com c_comtrowtype; BEGIN DBMS_OUTPUT. PUT_LINE('Numarul de produse pentru fiecare comanda:') ; IF NOT c_com%ISOPEN THEN 02 Baze de date. Limbajul PL/SQL OPEN c_com; END IF; LOOP FETCH c_com INTO rec_com; EXIT WHEN c_com%NOTFOUND OR c_com%ROWCOUNT>3 ; DBMS_OUTPUT. PUT_LINE('Comanda ‘| |xec_com.nr_comanda||' are: ‘| |zec_com.numar||' produse') ; END LOOP; CLOSE ¢c_com; END; / [erate Sax Oeveloper orate Ip = ene Pern (Eo Mew Bite fn Sees versiing Wiraion Toco Hep 308d 9= KON 0-0-8. @ 5k Obes Bar 2 Qos ise 5 Sree arity ens GlsettOunt enka: ga] Sonacag Figura 5.5 Executia blocului PL/SQL Cursori si tabele index BY 63 4, Sié se afiseze cota de impozitare si valoarea impozitului platit de primi n angajati. Se va utiliza un cursor, iar n se citeste de la tastatura. set serveroutput on; DECLARE CURSOR c is select nume,salariul from angajati; var cérowtype; imp number (4,2) ; val angajati.salariulttype; BEGIN OPEN c; LOOP FETCH c INTO var; imp:= CASE when var.salariul<1000 THEN 0.5 when var.salariul between 1000 AND 3000 then 1.25 when var.salariul between 3000 and 5000 then 1.5 when var.salariul between 500 and 7000 then 1.75 else 2 END; val:=imp*var.salariul; DBMS_OUTPUT.PUT_LINE('Angajatul '||var.nume||' are impozitul pe salariu de '||imp||'% - "| |val|[ |" RON'); EXIT WHEN c%rowcount>&n OR c%notfound; END LOOP; CLOSE c; END; Z 64 [Foret ewe oad a (le Kat ow teiote a Sogee erry ton Toa Bp BeBe 9e Rao .9-9-°5- Baze de date. Limbajul PL/SQL © Der DEGAS ORO tumeme ny _OUTPC. POT AEA “Ilva ae ape pe estat Ss {DOT Wen eteoromen Ot cottons Sei |epraanes | eeiscupe| Gove aane [cpus ios eepletad 1 Arpjetal King ate toperita pe satan se 2 } opteal Hoeae ee gota pe alas de 2 = 3609 FOE Jogeata be Bann ace Sapocttal pe selects ae 28 = 3400 Ra | Jangeatal Binal wresaprsca pe sunt e 24 ~ 1600 ba JnogeeeatEeve ee apeeeut pe selesu 61758 ~ 10560 Rat | I Inge atten ce sopersel pe snags de 1.58 ~ 70 Jageaca Peaella xe sopesscal pe onli Go 1.56 = 7200 Rl Joga Loent ace ingoeteal pe seas de 1-54 ~ 6200 Rab Figura 5.6 Executia cursorului pentru n=7 Gestiunea implicité a cursorului prin utilizarea unui ciclu FOR FOR nume_record IN nume_cursor LOOP In acest caz, tipul RECORD nu trebuie declarat. Se realizeazi in mod implicit deschiderea (OPEN), incdrcarea (FETCH) gi inchiderea cursorului (CLOSE). Exemplu: Si se afiseze printr-un ciclu FOR numele si salariile angajagilor din departamentul 50: set serveroutput on declare Cursori si tabele index BY 65 cursor ang_cursor is select id_angajat, nume, salariul from angajati where id_departament=50; begin dbms_output .put_line('Lista cu salariariile angajatilor din departamentul 50') ; for ang_rec in ang cursor loop dbms_output .put_line('Salariatul "| |ang_xec.nume||' axe salariul: "| |ang_rec.salariul) ; end loop; end; 8289 9% ¥BO OS 8- Ig © Doaciiy | DEAS BBG came eres ee - ——— i {3 00.00 ‘set serveroutput ox EB wr cresor eogousoe is select AA aaj, nant, sali fem engejeh wee 1 depactmen $0; ¥: 21D ett sin F = See eee ee i cone fe oes nog Io t = orem Gropp ie lene sme ccs ‘Ihe aais ' BiBven ‘end Loop: 6 Lindos em; © (Greingns t Breese © rectors i Bowes Baan ~ - SSomm tier (pats Biowomd (ean gatiee|Seasae| Connoae e re aa ‘a S ee 2 p_val i ie Os eatin aad | _—— [Pin produsui 289, RB 101/25, s-m ORDER BY total desc; Seen ieugtit rom, tone CE, os var HL test 1G Bee is ssama ste, ner may 0 so ae nes 2 iBReeSimavme on pvaual ZBL, Ps 20" st, 991 stats v_val NUMBER (5) ; eee ag: Pix Petal 225, Manes Soc ty orn ene 942 tant xrec_prod c_prod%rowtype; BEGIN v_val:=500; DBMS_OUTPUT. PUT_LINE('Produsele al caror cantitate vanduta este mai mare decat '| | v_val); IF NOT c_prod’ISOPEN THEN OPEN ¢ prod (v_val); END IF; LOOP FETCH c_prod into rec_prod; EXIT WHEN c_prod%not found; DBMS_OUTPUT.PUT_LINE('Din produsul "| |xec_prod.id_produs||', '| |xec_prod.denumire_produs||', s-au vandut ' | |zec_prod.total||' unitati'); END LOOP; CLOSE c_prod; END; / Figura 5.9 Executia blocului PL/SQL 2. Sai se afiseze pentru fiecare comandé produsele comandate. in acest caz se utilizeazé doud variabile de tip cursor: SET SERVEROUTPUT ON DECLARE --cursorul care va prelua comenzile incheiate CURSOR c_com IS SELECT nr_comanda, data FROM comenzi Where modalitate= ‘online! ORDER BY nr_comanda; --cursorul care, pentru fiecare comanda, va afisa produsele din cadrul acesteia, ordonate descrescator CURSOR c_prod (p_nr_comanda NUMBER) IS 70 Baze de date. Limbajul PL/SQL SELECT r.id_produs, p.denumire_produs, x.cantitate FROM produse p, rand_comenzi r WHERE p.id_produs=r.id_produs AND r.nr_comanda=p_nr_comanda ORDER BY r.id_produs desc; rec_com c_comtrowtype; --variabila record pentru campurile din primul cursor xrec_prod c_prod%rowtype; --variabila record pentru campurile din al doilea cursor BEGIN OPEN c_com; LOOP FETCH c_com into rec_com; EXIT WHEN c_com*not found; DBMS_OUTPUT. PUT_LINE('Comanda ' | | rec_com.nr_comanda ||! incheiata la data de "| |rec_com. data) ; OPEN c_prod (rec_com.nr_comanda); --cursorul primeste drept parametru numarul comenzii care a fost afisata LOOP FETCH c_prod into rec_prod; EXIT WHEN c_prod%not found; DBMS_OUTPUT. PUT_LINE('Din produsul ‘| |rec_prod.id_produs||', '| |rec_prod.denumire_produs||', s-au comandat ' | |rec_prod.cantitate||' bucati'); END LOOP; CLOSE c_prod; DBMS_OUTPUT. PUT_LINE(' END LOOP; CLOSE c_com; END; Z Cursori si tabele index BY 7 7 Oracle 5 Developer Feracie - 7 (Be (Ot Low Wvowe Bm Soe Veegnny Mraon Teele te 8589 9° XGRe@ @ 48- REO ¢ prod ite Teepe, Pin protusa 7300, Yee Cat [fos produ 225, @ 10, ex conta 195 cath comstat 200 eB on ‘BOY WHO ¢ prodiesttoud; eo eo An et“ eyo, tpt dea yo, 8 ores ‘a Loop} BG bet jainse ¢ prods et he) eon one sre em 2 Bie ‘mir Sane SRhreciages © WB Proceases || erections gone — © Bonet LLL BR tapes Denas (Bs Oded. teria |Sreaeoe | Goens 044] owe cunt & —— 78a fae | ——-—__ er Be caiet Eaten [ec 0 aa 2-9 0.2.5.9800 | ite i etn 259 Ra Hm emma Zt ane i ea 299, tere nn cma ea, BAB Ate Sponms: | Eeskonar os pe te, noe serps ema te See Pix ened ent, vara ememroe sie tia [bin prodasul 2323, Screws &n; END LOOP; ‘Be Em ew lvoe Bin Segre Verna Mawes Joa be Gada 9° xan 6-o Beals jaay [P Ghormies S Gum Ben euroment) ont 8 Omran OTT. SE Hate in epee veh. eae, epee: 8 Bree ‘Bo ir * orca Yc tet) om : 2 Screen see fitted ace fmceiaPresidest | BB Pde Somme yajatul :Rechhar seleriul :17000 | | @iosimut Joon i aqeeencrnccnis |; Sibert Ii oneennteeacen ct Pst | eee fer oe sce ese im sepacemnnuneestive ace cwscesetnnsetation Vise Peesldene "Figura 5.11 Executia cursorului pentru n=5 CURSOR c1(id_¢ clienti.id_client%type) is select ¢.nr_comanda,c.modalitate,p.denumire_produs, r.cantitate from comenzi c, rand_comenzi r, produse p where id_c=c.id client and r.nr_comanda= c.nr_comanda and r.id_produs= p.id_produs order by c.modalitate; BEGIN FOR var IN c LOOP DBMS_OUTPUT. PUT_LINE('Clientul: '| |var.nume_client||! a achizitionat urmatoarele produse: FOR varl IN cl(var.id_client) LOOP DBMS_OUTPUT. PUT_LINE(varl.denumire_produs| | ' '||varl.modalitate||' '||varl.cantitate) ; END LOOP; EXIT WHEN c%notfound; END LOOP; END; i 74 Baze de date. Limbajul PL/SQL Cursori gi tabele index BY 5 (Be ft Yew ovowo Bin Soy Vermenea Wordnet top 354d 9¢ XG @-0-.3- 7 aod a gay { 8 comectons: secon 7H 20am pi perey tore. rot cers “iar eet «seein mute ps * Bee | bere imrcne | Sams en, GOPT.e Iaceneepod' vataiatel ileum): eae bo inn; 1 Bow {at wet enn 5 Larson ‘Bo ua; I 5 Orton Be; k Wrenn ; Spee E Bone Pi orn crea or — SEC [bres Bonawe Goan lean Ganc onal Gowan I |) 2 Bee Cy | 8 Gi seemoe [Ciientul: Hasan e achisitionat uzaatoarele mo Rice rst

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