Langage PL/SQL - WordPress.com
Transcription
Langage PL/SQL - WordPress.com
ISAMM Cours SGBD & L4G Oracle PL/SQL 1. INTRODUCTION • Les traitements complexes sont parfois très difficile à écrire si on ne peut utiliser des variables et les structures de programmation comme les boucles et les alternatives. On ressent vite le besoin d’un langage procédural pour lier plusieurs requêtes SQL avec des variables et dans les structures de programmation habituelles • PL/SQL : Langage procédural de 4ème génération (L4G). Il s’agit d’une extension du langage SQL avec des caractéristiques propres aux langages de programmation ¾ Déclaration de variables et de constants ¾ Types de données abstraits (collections, enregistrements, objets) ¾ Modularité (sous-programmes, packages) ¾ Gestion des erreurs à l'exécution (exceptions) ¾ Interaction étroite avec Oracle (avec SQL) Avantages de PL/SQL • Performance (traitements par lot) • Productivité (uniformité dans tous les outils) • Portabilité (sur tous systèmes Oracle) • Intégration étroite avec Oracle (mêmes types de données que SQL, par exemple) Structure d'un bloc PL/SQL [DECLARE -- Déclaration types, constantes et variables] BEGIN -- Instructions PL/SQL & Commandes SQL [EXCEPTION -- Traitement des erreurs] END; Types de blocs PL/SQL • Bloc Anonyme • Stocké en-dehors de la base de données • Compilé et exécuté à la volée • Procédure Stockée : • Compilée séparément • Stockée de façon permanente dans la BD • Déclencheur (Trigger) • Procédure stockée associée à une table • Exécution automatique sur événement 2. DECLARATIONS Variables et constantes • Déclaration dans la partie déclarative d’un bloc PL/SQL • Variables date_naissance DATE; compteur1 INTEGER:=0; compteur2 INTEGER DEFAULT 0; id VARCHAR2(5) NOT NULL := ‘AP001’; • Constantes pi CONSTANT REAL := 3.141592653; Référencement de type existant • Type d’une autre variable Credit REAL; Debit Credit%TYPE; • Type d'un attribut d'une table • Type d’un tuple d’une table num_emp Emp.empno%TYPE; un_client Client%ROWTYPE; 3. OPERATEURS Affectation • Affectation simple Numero := 0; Numero := numero + 1; • Valeurs issues d'une base de données si la requête ramène un et un seul enregistrement SELECT numcli INTO numero FROM Client WHERE numcli = 10; SELECT empno, ename INTO num, nom FROM Emp WHERE ename = 'KING'; -1- ISAMM Cours SGBD & L4G Expressions et comparaisons • Opérateurs arithmétiques : + - / * ** • Opérateur de concaténation : • Opérateurs de comparaison : • Opérateurs logiques : || = < > <= >= <> != IS NULL LIKE BETWEEN IN AND, OR, NOT Conversion de type de données • Fonctions de conversion : TO_CHAR, TO_DATE, TO_NUMBER v_date1 := to_date('01/01/1999’, ‘dd/mm/yyyy’); v_date2 := to_date(’01 janvier 1999’, ‘dd month yyyy’); v_date3 := to_date(’01-jan-1999’, ‘dd-mon-yyyy’); v_str_date_systeme := to_char(sysdate, ‘dd/mm/yyyy'); v_str_heure_systeme := to_char(sysdate, ‘hh24:mi:ss'); v_str_date_systeme_complete := to_char(sysdate, ‘dd/mm/yyyy hh24:mi:ss'); v_num_str := to_char(130); v_num := to_number('140'); 4. STRUCTURES DE CONTROLE Traitements conditionnels : • IF - THEN, IF - THEN - ELSE ou IF - THEN - ELSIF IF condition1 THEN -- Instructions [ELSIF condition2 THEN -- Instructions] [ELSE -- Instructions] END IF; Traitements itératifs • Boucle pour FOR compteur IN [REVERSE] borne_inf..borne_sup LOOP -- Instructions END LOOP; NB: borne_inf doit être inférieure à borne_sup • Boucle tant que WHILE condition LOOP -- Instructions END LOOP; • Boucle "infinie" LOOP -- Instructions END LOOP; • Sortie de boucle, uniquement autorisé pour sortir d'une boucle infinie EXIT WHEN condition; 5. AFFICHAGE • DBMS_OUTPUT.PUT_LINE('chaîne'); DBMS_OUTPUT.PUT_LINE('Bonjour'); DBMS_OUTPUT.PUT_LINE('nom='||nom); NB: Pour que l'affichage fonctionne, la variable d'environnement SERVEROUTPUT de SQL*Plus doit être à ON. SET SERVEROUTPUT ON • Exemple --Affichage en dinars tunisien du salaire de SCOTT qui stocké en euros --Salire en dinars tunisien = salaire en euros * 1.621 SET SERVEROUTPUT ON DECLARE Euro CONSTANT REAL := 1.621; Salaire emp.sal%TYPE; BEGIN --Affectation SELECT sal INTO Salaire FROM emp WHERE ename = 'SCOTT'; --Conversion Salaire := Salaire*Euro; --Affichage DBMS_OUTPUT.PUT_LINE(TO_CHAR(Salaire)||' DT'); END; / -2- ISAMM Cours SGBD & L4G 6. LES CURSEURS Définition et déclaration • Curseur : Structure de données permettant de stocker le résultat d’une requête qui retourne plusieurs tuples (lignes). • Déclaration : CURSOR nom_curs IS requêteSQL; CURSOR calcul IS SELECT NumProd, PrixUni*1.18 AS PrixTTC FROM Produit; NB: Un tuple du curseur sera de type nom_curs%ROWTYPE. Parcours personnalisé DECLARE CURSOR emp_cursor IS -- déclarer le curseur SELECT ename, dname FROM emp, dept WHERE emp.deptno = dept.deptno; emp_record emp_cursor%ROWTYPE; BEGIN OPEN emp_cursor; -- Ouvrir le curseur LOOP FETCH emp_cursor INTO emp_record; -- avancer au tuple suivant du curseur EXIT WHEN emp_cursor%NOTFOUND; -- sortir si la fin du curseur est détectée DBMS_OUTPUT.PUT_LINE('L''employé '|| emp_record.ename || ' travaille dans le département ' || emp_record.dname); END LOOP; CLOSE emp_cursor; -- fermer le curseur END; / Parcours complet (boucle pour) DECLARE CURSOR calcul IS SELECT EMPNO, SAL + nvl(COMM) AS Total_Salaire FROM Produit; tuple calcul%ROWTYPE; BEGIN FOR tuple IN calcul LOOP -- Ouverture, parcours et fermeture automatiquement effectués DBMS_OUTPUT.PUT_LINE('Employé numéro '||TO_CHAR(tuple.EMPNO) ||' a un salaire = '|| TO_CHAR(tuple.Total_Salaire)); END LOOP; END; / Attributs des curseurs • %NOTFOUND • %FOUND • %ROWCOUNT • %ISOPEN est égal à TRUE si le dernier FETCH n’a pas retourné un résultat est égal à TRUE si le dernier FETCH a retourné un résultat (opposé logique de %NOTFOUND) retourne le nombre de lignes lues est égal à TRUE si le curseur est ouvert 7. EXCEPTIONS Définitions • Une exception est une erreur déclenchée pendant l’exécution d’un bloc PL/SQL. • Une exception est déclenchée implicitement par une erreur Oracle ou explicitement par le programme Avantages • Traitement systématique des erreurs • Traitement groupé d'erreurs similaires • Lisibilité du code (traitement des erreurs séparé) Fonctions PL/SQL pour la gestion d’erreurs • SQLCODE : renvoie la valeur numérique associée à la dernière exception détectée • SQLERRM : renvoi le message associé au code de l’erreur Exceptions prédéfinies Nom Code erreur Sqlcode Description -------------------------------------------------------------------------------------------------NO_DATA_FOUND ORA-01403 -1403 SELECT mono-ligne retournant 0 ligne TOO_MANY_ROWS ORA-01422 -1422 SELECT mono-ligne retournant plus d’1 ligne DUP_VAL_ON_INDEX ORA-00001 -1 Insertion d’une ligne en doublon VALUE_ERROR ORA-06502 -6502 Erreur arithmétique, conversion ou limite de taille ZERO_DIVIDE ORA-01476 -1476 Division par zéro CURSOR_ALREADY_OPEN ORA-06511 -6511 Ouverture d’un curseur déjà ouvert INVALID_NUMBER ORA-01722 -1722 Echec sur une conversion d’un chaîne de caractères vers un nombre … -3- ISAMM Cours SGBD & L4G Exceptions personnalisées • Déclaration (section DECLARE) nom_exception EXCEPTION; • Lever l'exception (section BEGIN) IF condition THEN RAISE nom_exception; END IF; • Traitement de l'exception (section EXCEPTION) • Exemple 1 : WHEN nom_exception THEN ...; DECLARE c INTEGER; x_aucun EXCEPTION; BEGIN SELECT COUNT(*) INTO c FROM EMP; IF c=0 THEN RAISE x_aucun; ELSE DBMS_OUTPUT.PUT_LINE('La table EMP contient '||c||' employés'); END IF; EXCEPTION WHEN x_aucun THEN DBMS_OUTPUT.PUT_LINE('La table EMP est vide'); WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('Erreur inconnue numéro ' || SQLCODE); END; / • Exemple 2 : SET SERVEROUTPUT ON SET ECHO OFF -- Saisie du numéro, du nom et du salire du nouveau employé PROMPT Entrer le numéro de l'employé ACCEPT num_emp PROMPT 'numéro : ' PROMPT Entrer le nom de l'employé ACCEPT nom_emp PROMPT 'nom : ' PROMPT Entrer le salaire de l'employé ACCEPT sal_emp PROMPT 'salaire : ' Commande SQL*Plus -- Test de clé primaire sur la table emp DECLARE N number(2); cle_existe EXCEPTION; cle_nulle EXCEPTION; BEGIN -- Valeur nulle IF &num_emp IS NULL THEN RAISE cle_nulle; END IF; -- Existence de la clé primaire SELECT COUNT(empno) INTO n FROM emp WHERE empno = &num_emp; Bloc PL/SQL IF n>0 THEN RAISE cle_existe; ELSE insert into emp(EMPNO,ENAME,HIREDATE,SAL) values (&num_emp,'&nom_emp',sysdate,&sal_emp); END IF; EXCEPTION WHEN cle_existe THEN DBMS_OUTPUT.PUT_LINE('Clé primaire déjà utilisée!'); WHEN cle_nulle THEN DBMS_OUTPUT.PUT_LINE('La clé primaire doit avoir une valeur!'); WHEN others THEN DBMS_OUTPUT.PUT_LINE('Erreur inconnue : ' || SQLERRM); END; / -4-