pl_sql
Guide Rapide Et Complet Sur PL/SQL
1. Qu’est-ce Que PL/SQL ?
- PL/SQL (Procedural Language extensions to SQL) : Langage procédural d’Oracle pour étendre SQL avec des structures de programmation.
- Caractéristiques :
- Exécuté directement dans la base Oracle.
- Optimise les performances en regroupant les requêtes SQL.
- Gère les transactions, les erreurs et la logique métier complexe.
- Compatible avec les types de données Oracle et les curseurs.
2. Structure De Base D’un Bloc PL/SQL
graph TD A[Start] --> B{DECLARE} B --> C{BEGIN} C --> D[Statements] D --> E{EXCEPTION} E --> F[Error Handling] F --> G[END] D --> G G --> H[End]
DECLARE
-- Section déclarative (variables, constantes, curseurs)
BEGIN
-- Section exécutable (logique principale)
EXCEPTION
-- Gestion des erreurs
END;
/
Exemple Simple :
DECLARE
message VARCHAR2(50) := 'Hello, World!';
BEGIN
DBMS_OUTPUT.PUT_LINE(message);
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Erreur : ' || SQLERRM);
END;
/
3. Variables Et Types De Données
-
Types scalaires :
nombre NUMBER := 10; texte VARCHAR2(100); date_actuelle DATE := SYSDATE; est_vrai BOOLEAN := TRUE;
-
Types composites :
- Record :
TYPE Employe_Record IS RECORD ( id NUMBER, nom VARCHAR2(50) ); emp Employe_Record;
- Tableau :
TYPE ListeNoms IS TABLE OF VARCHAR2(50); noms ListeNoms := ListeNoms('Alice', 'Bob');
4. Structures De Contrôle
Condition (IF-THEN-ELSE
) :
IF salaire > 5000 THEN
DBMS_OUTPUT.PUT_LINE('Salaire élevé');
ELSIF salaire BETWEEN 3000 AND 5000 THEN
DBMS_OUTPUT.PUT_LINE('Salaire moyen');
ELSE
DBMS_OUTPUT.PUT_LINE('Salaire bas');
END IF;
Exemples Détaillés de Structures de Contrôle
Condition (IF-THEN-ELSIF-ELSE
) :
DECLARE
note NUMBER := 75;
mention VARCHAR2(20);
BEGIN
IF note >= 90 THEN
mention := 'Excellent';
ELSIF note >= 80 THEN
mention := 'Très Bien';
ELSIF note >= 70 THEN
mention := 'Bien';
ELSIF note >= 60 THEN
mention := 'Passable';
ELSE
mention := 'Échec';
END IF;
DBMS_OUTPUT.PUT_LINE('Note : ' || note || ', Mention : ' || mention);
END;
/
Boucle (LOOP
, FOR
, WHILE
) :
-- Boucle simple avec EXIT WHEN
DECLARE
compteur NUMBER := 0;
BEGIN
LOOP
DBMS_OUTPUT.PUT_LINE('Compteur : ' || compteur);
compteur := compteur + 1;
EXIT WHEN compteur >= 5;
END LOOP;
END;
/
-- Boucle FOR sur une plage
BEGIN
FOR i IN 1..5 LOOP
DBMS_OUTPUT.PUT_LINE('Itération : ' || i);
END LOOP;
END;
/
-- Boucle FOR inversée sur une plage
BEGIN
FOR i IN REVERSE 5..1 LOOP
DBMS_OUTPUT.PUT_LINE('Itération inversée : ' || i);
END LOOP;
END;
/
-- Boucle FOR sur un curseur implicite
BEGIN
FOR emp_rec IN (SELECT nom, salaire FROM Employes WHERE salaire > 4000) LOOP
DBMS_OUTPUT.PUT_LINE('Employé : ' || emp_rec.nom || ', Salaire : ' || emp_rec.salaire);
END LOOP;
END;
/
-- Boucle WHILE
DECLARE
j NUMBER := 0;
BEGIN
WHILE j < 5 LOOP
DBMS_OUTPUT.PUT_LINE('J : ' || j);
j := j + 1;
END LOOP;
END;
/
5. Curseurs (Cursors)
Curseur Explicite :
DECLARE
CURSOR cur_employes IS SELECT nom, salaire FROM Employes;
emp_nom VARCHAR2(50);
emp_salaire NUMBER;
BEGIN
OPEN cur_employes;
LOOP
FETCH cur_employes INTO emp_nom, emp_salaire;
EXIT WHEN cur_employes%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(emp_nom || ' : ' || emp_salaire);
END LOOP;
CLOSE cur_employes;
END;
/
Curseur Implicite (FOR LOOP) :
BEGIN
FOR emp IN (SELECT nom, salaire FROM Employes) LOOP
DBMS_OUTPUT.PUT_LINE(emp.nom || ' : ' || emp.salaire);
END LOOP;
END;
/
#### Curseurs Implicites
PL/SQL utilise des curseurs implicites pour les requêtes `SELECT INTO`, `INSERT`, `UPDATE`, et `DELETE`. Vous pouvez accéder aux informations sur le résultat de ces opérations via des attributs de curseur implicite :
- `SQL%FOUND`: Attribut booléen qui est VRAI si la dernière commande SQL a affecté au moins une ligne.
- `SQL%NOTFOUND`: Attribut booléen qui est VRAI si la dernière commande SQL n'a affecté aucune ligne.
- `SQL%ROWCOUNT`: Attribut numérique qui contient le nombre de lignes affectées par la dernière commande SQL.
**Exemple avec curseur implicite :**
```sql
BEGIN
UPDATE Employes SET salaire = salaire * 1.05 WHERE departement_id = 10;
IF SQL%FOUND THEN
DBMS_OUTPUT.PUT_LINE('Salaires mis à jour pour ' || SQL%ROWCOUNT || ' employés.');
ELSE
DBMS_OUTPUT.PUT_LINE('Aucun employé trouvé dans ce département.');
END IF;
END;
/
6. Utilisation avec Collections
PL/SQL supporte les collections, qui sont des types de données composites permettant de stocker plusieurs éléments du même type. Les types de collections les plus courants sont les tables imbriquées (nested tables) et les VARRAYs.
Tables Imbriquées (Nested Tables)
Les tables imbriquées sont des collections non liées qui peuvent stocker un nombre illimité d’éléments.
DECLARE
TYPE ListeNoms IS TABLE OF VARCHAR2(50);
noms ListeNoms := ListeNoms('Alice', 'Bob', 'Charlie');
BEGIN
FOR i IN noms.FIRST..noms.LAST LOOP
DBMS_OUTPUT.PUT_LINE('Nom : ' || noms(i));
END LOOP;
END;
/
VARRAYs
Les VARRAYs (Variable-size Arrays) sont des collections liées qui ont une taille maximale prédéfinie.
DECLARE
TYPE NotesEtudiant IS VARRAY(5) OF NUMBER;
notes NotesEtudiant := NotesEtudiant(85, 92, 78);
BEGIN
FOR i IN notes.FIRST..notes.LAST LOOP
DBMS_OUTPUT.PUT_LINE('Note : ' || notes(i));
END LOOP;
END;
/
7. Gestion Des Exceptions
-
Exceptions prédéfinies :
NO_DATA_FOUND
,TOO_MANY_ROWS
,ZERO_DIVIDE
. -
Exceptions personnalisées :
DECLARE salaire_trop_bas EXCEPTION; PRAGMA EXCEPTION_INIT(salaire_trop_bas, -20001); BEGIN IF salaire < 1000 THEN RAISE salaire_trop_bas; END IF; EXCEPTION WHEN salaire_trop_bas THEN DBMS_OUTPUT.PUT_LINE('Erreur : Salaire insuffisant.'); WHEN OTHERS THEN ROLLBACK; END; /
9. Procédures Et Fonctions
Procédure Stockée :
CREATE OR REPLACE PROCEDURE AugmenterSalaire (
p_id Employes.id%TYPE,
p_pourcent NUMBER
) IS
BEGIN
UPDATE Employes
SET salaire = salaire * (1 + p_pourcent/100)
WHERE id = p_id;
COMMIT;
END AugmenterSalaire;
/
Fonction :
CREATE OR REPLACE FUNCTION CalculerSalaireAnnuel (
p_salaire_mensuel NUMBER
) RETURN NUMBER IS
BEGIN
RETURN p_salaire_mensuel * 12;
END CalculerSalaireAnnuel;
/
10. Packages
-
Spécification (déclaration) :
CREATE OR REPLACE PACKAGE GestionEmployes AS PROCEDURE AfficherInfos(p_id NUMBER); FUNCTION SalaireMoyen RETURN NUMBER; END GestionEmployes; /
- Corps (implémentation) :
CREATE OR REPLACE PACKAGE BODY GestionEmployes AS PROCEDURE AfficherInfos(p_id NUMBER) IS emp_nom VARCHAR2(50); BEGIN SELECT nom INTO emp_nom FROM Employes WHERE id = p_id; DBMS_OUTPUT.PUT_LINE('Nom : ' || emp_nom); END; FUNCTION SalaireMoyen RETURN NUMBER IS v_moyen NUMBER; BEGIN SELECT AVG(salaire) INTO v_moyen FROM Employes; RETURN v_moyen; END; END GestionEmployes; /
11. Déclencheurs (Triggers)
Trigger sur une Table :
CREATE OR REPLACE TRIGGER AvantInsertionEmploye
BEFORE INSERT ON Employes
FOR EACH ROW
BEGIN
:NEW.date_embauche := SYSDATE; -- Définit la date automatiquement
END;
/
12. Optimisation Et Bonnes Pratiques
-
Bulk Operations (
FORALL
,BULK COLLECT
) :DECLARE TYPE ListeIDs IS TABLE OF NUMBER; ids ListeIDs := ListeIDs(1, 2, 3); BEGIN FORALL i IN ids.FIRST..ids.LAST UPDATE Employes SET salaire = salaire * 1.1 WHERE id = ids(i); END; /
-
Éviter les boucles SQL : Préférer les opérations en masse.
-
Utiliser
%ROWTYPE
pour simplifier la gestion des enregistrements.
13. Outils Et Débogage
-
SQL Developer : Interface graphique pour écrire et déboguer du PL/SQL.
-
DBMS_OUTPUT : Afficher des messages de débogage.
-
Exceptions avec
RAISE_APPLICATION_ERROR
:IF salaire < 0 THEN RAISE_APPLICATION_ERROR(-20001, 'Salaire invalide'); END IF;
14. Exemple Complet
-- Création d'une procédure avec gestion d'erreurs
CREATE OR REPLACE PROCEDURE TransfertFonds (
p_source NUMBER,
p_destination NUMBER,
p_montant NUMBER
) IS
solde_insuffisant EXCEPTION;
BEGIN
-- Vérifier le solde
IF (SELECT solde FROM Comptes WHERE id = p_source) < p_montant THEN
RAISE solde_insuffisant;
END IF;
-- Mettre à jour les comptes
UPDATE Comptes SET solde = solde - p_montant WHERE id = p_source;
UPDATE Comptes SET solde = solde + p_montant WHERE id = p_destination;
COMMIT;
EXCEPTION
WHEN solde_insuffisant THEN
ROLLBACK;
DBMS_OUTPUT.PUT_LINE('Erreur : Solde insuffisant.');
WHEN OTHERS THEN
ROLLBACK;
RAISE;
END TransfertFonds;
/
15. Erreurs Courantes
- “PLS-00103: Encountered the symbol…” → Vérifiez la ponctuation ou les mots-clés manquants.
- “ORA-01403: no data found” → Utilisez
IF cur%FOUND
ou gérez l’exceptionNO_DATA_FOUND
. - “ORA-06502: PL/SQL: numeric or value error” → Vérifiez les types de données et les conversions.
📚 Ressources :
🚀 Astuce : Utilisez DBMS_PROFILER
pour analyser les performances de votre code PL/SQL et identifier les goulots d’étranglement !