In acest unit vom discuta tipurile de date suportate de PL/SQL, variabile scalare, si cum pot fi manipulate datele si expresiile. Acest unit introduce de asemenea modul de utilizare al PL/SQL cu SQL*Plus, care este o cale interactiva convenabila pentru testarea blocurilor pe care le veti scrie.
/* Acesta comentariu se prelungeste pe mai multe linii. Orice secventa de cod aflata aici este considerata comentariu. */ COMMIT; --Aici se termina transferul
Simboluri simple - Acestea sunt formate dintr-un singur caracter ------------------------------------------------------------------ + operatorul de adunare - operatorul de scadere/negare * operatorul de multiplecare / operatorul de impartire = operator relational > operator relational < operator relational ) delimitator de lista sau expresii ( -||- ; delimitator de instructiuni , separator de obiect . selector de componenta @ delimitator de access la distanta ' delimitator de sir : delimitator de masina Simboluri Compuse - Sunt formate din doua caractere --------------------------------------------------------------------- ** exponential <> relational != -||- ^= -||- <= -||- >= -||- := asignare => asociere .. rang || concatenare << eticheta >> -||- -- comentariu /* -||- */ -||-
BEGIN -- actiuni in bucla principala DECLARE -- declaratii de obiecte BEGIN -- actiuni ale blocului EXCEPTION -- ce'i de facut daca apare o eroare in acest bloc. END; -- alte actiuni in blocul principal EXCEPTION WHEN errors_trickle_through THEN BEGIN -- minuire a erorilor in blocul propriu EXCEPTION -- ce'i de facut daca tratarea unei erori -- merge gresit !! END; END;
Domeniul unui obiect este blocul complet in care obiectul este declarat,
inclusiv oricare sub-bloc inclus in acest bloc. Obiectele declarate in
sub-blocuri sunt valabile pina cind sub-blocul se termina.
Exemplu:
DECLARE X NUMBER; ----------------| BEGIN | | ... | domeniul | lui DECLARE | x Y NUMBER; -----| | | domeniul lui y | BEGIN | | ... | | END; -----| | | ... | END; ---------------|
Retineti ca pe timpul 'Timpului de viata' al lui y, suntem tot in domeniul lui 'x', si putem defini expresii care sa foloseasca ambele variabile.
Sa presupunem ca variabila din sub-bloc nu se numeste 'y' ci 'x'.
Cu alte cuvinte, are acelasi nume ca si variabila din sub-bloc.
DECLARE x NUMBER; -- variabila x din blocul principal BEGIN ... DECLARE x NUMBER; -- variabila x din sub-bloc BEGIN ... END; ... END;
TIPUL NUMERIC NUMBER Valoare numerica cu precizia de 38 de cifre. Valorile sunt rotunjite la numere intregi mai putin atunci cind este data scala.( ex. NUMBER(7,2) inseamna 7 cifre, cu 2 zecimale. Implicit precizia este de 38 cifre.) TIPUL CARACTER VARCHAR2 Folosit pentru a memora variabile de tip caracter.Lungime implicita 1 caracter. Maxima permisa 32767. ex. VARCHAR2(30) CHAR PL/SQL Versiunea 1:la fel ca VARCHAR2, dar cu lungimea maxima de 255 PL/SQL Versiunea 2:Lungimea poate fi mai mare de 32767 caractere. TIPUL BOOLEAN BOOLEAN Pentru minuirea valorilor booleene TRUE si FALSE. Rezultatul expresiilor booleene poate fi asignat acestor variabile si testat mai tirziu in instructiuni conditionale. TIPUL DATA DATE Datele valide sunt intre 4712 BC si 4712AD.
indentificator tipdata [(precizia,scala)] [NOT NULL] [ := expresie ] ;
Unde 'expresie' poate fi o alta variabila, sau o expresie cu functii si
operatori. Daca o valoare initiala nu este asignata, atunci variabila va
contine o valoare nula pina cind ii va fi asignata ulterior o valoare.
Constanta NOT NULL nu mai este permisa in aceasta situatie.
Exemple:
v_count NUMBER NOT NULL := 0; v_salary NUMBER(7,2); v_annsal NUMBER(9,2) := month_sal * 12; -- mount_sal trebuie sa existe deja postcode CHAR(7); surname VARCHAR2(25) := 'Skywalker' ; v_message VARCHAR2(80) := 'May the course be woth you!' ; married BOOLEAN := FALSE; today DATE := SYSDATE;
Este indicat sa nu alegeti acelasi nume (identificator) pentru o variabila ca
nume pentru coloanele din tabela folosite in cadrul blocului. Daca
variabilele PL/SQL apar in instructiuni SQL si au acelasi nume ca coloana,
atunci ORACLE considera ce se refera coloana.
identificator CONSTANT tipdata [(precision,scala)] := expresie ;
pi CONSTANT NUMBER(9,5) := 3.14159 ; vat CONSTANT NUMBER(4,2) := 17.5 ;
identificator := expresie ;
'Expresie' poate fi literal, numele unei alte variabile existente, sau
alta expresie necesara pentru a determina valoarea ce va fi asignata.
De obicei, cele mai multe din expresiile disponibile in inderogarile SQL
, clauza SELECT sunt disponibile aici. Functiile si expresiile permise
in PL/SQL vor fi discutate mai tirziu in acest UNIT.
Exemple:
v_count := v_count +1; ann_sal := mount_sal * 12 +NVL(comm,0); lev := 6; mess := 'The current level is ' || TO_CHAR(lev) ; v_ename := 'KING';
overpaid := ann_sal > 35000 ; male := UPPER(title) == 'MR' ; salary_ok := NOT overpaid ; female := NOT male ; switch1 := TRUE; switch2 := FALSE;
:screen_field1 := ann_sal ; :warp_factor := 9 ; :global.var1 := 'YES' ;
Detalii despre modul de minuire al variabilelor NON PL/SQL sunt descrise
in cursuri ORACLE special destinate acestor variabile.
sal_message VARCHAR2(12) := 3500;
salary NUMBER(12,2) := sal_message;
salary := 'King earns $5000'; -- eroare
today VARCHAR2(9) := SYSDATE ; hired DATE := '21-JAN-1992' ;
In cadrul expresiilor trebuie sa va asigurati ca tipurile de date sunt
aceleasi. Daca apar tipuri diferite de date in aceiasi expresie, atunci
se foloseste cea mai potrivita functie de conversie:
TO_CHAR TO_DATE TO_NUMBER
PL/SQL va incerca sa faca conversia, daca este posibil. De obicei, PL/SQL
este mai pretentios decit SQL daca tipurile de date sunt mixate in cadrul
unei expresiilor. Deci daca nu sunteti sigur, folositi cea mai potrivita
functie de conversie.
Exemplu:
v_message VARCHAR2(80) := 'SCOTT earns' || TO_CHAR (month_sal*12) ;
Ordinea in care operatiile sunt realizate poate fi controlata folosind paranteze, ca in SQL.
Reamintim ordinea naturala a operatiilor in cadrul unei expresii:
Ordinea de evaluare a operatorilor -----------------------------------------------------------------------------| | | OPERATOR | OPERATIE | |----------------------------------------------------------------------------| |Primul | ** , NOT | exponential, negatie logica| | | + , - | identitate, negatie | | | * , / | inmultire, impartire | | | + , - , || | adunare, scadere, | | | | concatenare | | | = , != , < , > , <= , >= | comparatie | | | IN NULL, LIKE, BETWEEN, IN | | | | AND | conjunctie | |Ultimul| OR | incluziune | |----------------------------------------------------------------------------|
In plus PL/SQL ofera doua functii pentru minuirea raportatea erorilor denumite SQLCODE si SQLERRM care vor fi discutate in unitul urmator.
Functii nedisponibile in instructiuni structurale sunt:
GREATEST and LEAST AGV, MIN, MAX, COUNT, SUM, STDDEV si VARIANCE
|-----------------------------------------------------------------| | SQL> DECLARE | | 2 x NUMBER(7,2); | | 3 BEGIN | | 4 SELECT sal INTO x FROM emp WHERE empno= &&n; | | 5 IF x<3000 THEN | | 6 UPDATE emp SET sal=3000; | | 7 WHERE empno = &&n; | | 8 END IF; | | 9 END; | | 10. | | SQL> | |-----------------------------------------------------------------|
Procedural Option (Oracle7 Server)
SQL*Plus este un bun instrument pentru testarea blocurilor PL/SQL,de aceea il vom folosi si noi pentru partea practica a cursului.
Sunt doua cai pentru a prelucra blocuri PL/SQL in SQL*Plus:
SQL*Plus detecteaza inceputul unui bloc PL/SQL dupa introducerea cuvintelor
cheie DECLARE si BEGIN la promptul 'SQL >'.Bufferul poate fi inchis fara
a executa blocul sau programul prin introducerea unui '.' la prompt.
Exemplu:
SQL> DECLARE 2 x NUMBER(7,2); 3 BEGIN 4 SELECT sal INTO x FROM emp WHERE empno = 7788; 5 IF x < 3000 THEN UPDATE emp SET sal = 3000 6 WHERE empno = 7788; 7 END IF; 8 END; 9 .
Continutul bufferului poate fi editat in maniera obisnuita sau salvat intr-un fisier folosind comanda SQL*Plus "SAVE".
Pentru a rula buffer-ul PL/SQL, tastati comanda RUN sau '/' la promptul
SQL. Daca executia reuseste fara tratari de eroare atunci singurul mesaj
care apare ar trebuie sa fie:
'PL/SQL procedure seccessfully completed'
Retineti ca comenzile SQL*Plus nu pot apare in interiorul blocului PL/SQL
dar pot fi incluse ori unde in alta parte in fisier. Variabilele de
substitutie din SQL*Plus pot fi referite din cadrul blocului, dar retineti
ca ele sunt inlocuite cu continutul variabilelor INAINTE ca codul sa fie
complet interpretat sau executat.
Exemplu:
SET ECHO OFF BEGIN INSERT INTO dept ( deptno, dname ) VALUES ( &1, ' &2 ' ); COMMIT; EXCEPTION WHEN dup_val on index THEN INSERT INTO tav VALUES (' Duplicate departament No.'); END; / SELECT * FROM error tab; SET ECHO ON
Oricum, continutul variabilelor si al tabelelor bazei de date nu pot fi afisate pe ecran in timpul executiei blocurilor PL/SQL in sesiuni SQL*PLus (cel putin pina cind nu sunt folosite procedurile pachetului DBMS_OUTPUT). Trebuie sa scrieti orice rezultat pe care doriti sa-l afisati intr-o tabela in baza de date si dupa executie sa parcurgeti tabela. Aceasta parcurgere poate fi facuta in acelasi fisier care cuprindea si blocul, ca in exemplul anterior.
Situatia este diferita in aplicatii cum ar fi SQL*Forms, unde blocurile
PL/SQL pot afisa variabile direct pe ecran prin folosirea unor functii
interne.
nume-Procedura [ ( param1, param2, param3, ... ) ];
La apelare, parametrii trebuie pusi in ordinea de definire. Aceasta inseamna si tipurile de date trebuie sa fie aceleasi cu cele definite. Anumiti parametrii pot avea valori implicite, dar daca o valoare este data ca parametru atunci toti parametrii anteriori trebuie folositi.
In exemplul urmator, procedura CLEAR_DEPT are doi parametrii disponibili.
Primul parametru DEPARTAMENT_NAME ( datatype VARCHAR2 ) si al doilea
parametru DELETE_DEPARTAMENT ( datatype BOOLEAN cu valoarea implicita FALSE ).
CLEAR_DEPT( `ACCOUNTING' ); -- al doilea parametru este implicit CLEAR_DEPT ( `ACCOUNTING', TRUE);
Parametrii pot fi folositi alternativ impreuna cu numele formal, prin
folosirea operatorului de asociere. In acest caz pozitia lor nu mai este
importanta:
CLEAR_DEPT ( DELETE_DEPARTAMENT => TRUE, DEPARTAMENT_NAME => `ACCOUNTING' ) ;
In final, deoarece sub-programele trebuie apelate din blocuri PL/SQL, se
poate apela din promptul SQL in SQL*Plus prin impachetarea apelului cu
BEGIN si END. Aceasta poate fi realizata prin comanda EXECUTE din SQL*Plus.
SQL> EXECUTE CLEAR_DEPT( `ACCOUNTING' );
BEGIN CLEAR_DEPT( `ACCOUNTING '); END;
In multe din exercitii, aveti nevoie de inregistrarea rezultatelor intr-o
tabela. Vom folosi pentru aceasta tabela MESSAGES. Definirea acesteia este
urmatoarea:
Table MESSAGES Coloana Descrierea ------------ ------------------------------------- NUMCOL1 NUMBER (9,2) NUMCOL2 NUMBER (9,2) CHARCOL1 VARCHAR2(60) CHARCOL2 VARCHAR2(60) DATECOL1 DATE DATECOL2 DATE
Variabila Valoare ------------- ----------------------------------------- V_CHAR Literar `42 este raspunsul' V_NUM Primele doua caractere din V_CHAR V_BOOL1 TRUE si FALSE functie de cum este V_NUM fata de 100 V_BOOL2 Opus lui V_BOOL1
DECLARE V_BOOL1 BOOLEAN; V_BOOL2 BOOLEAN; V_CHAR VARCHAR2(16); -- cel putin 16 caractere V_NUM NUMBER(2); BEGIN V_CHAR := '42 este raspunsul'; V_NUM := SUNSTR(V_CHAR,1,2); -- conversie dinamica la mumar V_BOOL1 := V_NUM < 100; V_BOOL2 := NOT V_BOOL1; END;
DECLARE V_RESULT NUMBER(9,2); BEGIN V_RESULT := &main_var ** &exponent ; -- sau POWER(&main_var,&exponent); INSERT INTO messages(numcol1) VALUES ( V_RESULT ) ; END;
BIND VARIABILES ............. VARIABILE V_RESULT NUMBER BEGIN :V_RESULT := &main_var ** &exponent; END; PRINT V_RESULT