FIP PL-SQL
FIP PL-SQL
FIP PL-SQL
Procédures Stockées
Bases de Données
Nicolas Travers
Équipe Vertigo - Laboratoire CEDRIC
Conservatoire National des Arts & Métiers, Paris, France
Contenu du cours
• PL/SQL
▫ Variables
▫ Structures de contrôle
▫ Interaction avec la base et Curseurs
▫ Sous-programmes, paquetages
▫ Exceptions
▫ Transactions
Bibliographie
PL/SQL
• Procedural Language / Structured Query Language
▫ PL/SQL : langage propriétaire Oracle
▫ Language procédural :
Variables, boucles, tests, curseurs, fonctions/procédures,
exceptions
• Syntaxe de PL/SQL inspirée du langage Ada (Pascal)
▫ Avantages de SQL
▫ Programmation en plus
• PL/SQL n est pas très éloigné du langage normalisé
Persistent Stored Modules (PSM)
PL/SQL
• Qui ?
▫ DBA
▫ Programmeur d’application de BD
• Existe dans d autres SGBDR
▫ MySQL : PL/SQL like
▫ Sybase et Microsoft SQL server : Transact-SQL
▫ PostgreSQL : PL/pgSQL
▫ DB2 (IBM) : SQL Procedural Language
• Documentation Oracle (en anglais)
http://download.oracle.com/docs/cd/B10501_01/appdev.920/a96624/toc.htm
• Documentation MySQL
http://dev.mysql.com/doc/refman/5.0/fr/stored-procedure-syntax.html
PL/SQL - Modes
• Interactif :
▫ Exécution de code
par exemple, contrôler ou corriger des données
• Stocké :
▫ Procédures, fonctions ou de triggers
▫ Appel interne
• Programme :
▫ Appel depuis langages généralistes (JDBC)
Architecture
1
Connexion Requête 1
Analyse SQL Connexion
+ Appel
+ +
Plusieurs PL/SQL
Compilation Appel de
requêtes
requête procédure
SQL Résultats
4
3 Accès 2 3 Accès 2
Appels : Appels :
(1, 2, 3, 4), (1, 2, 3, 4) 1, (2, 3), (2, 3), (2, 3)
… …
BD BD
Structure d un programme
• Programme PL/SQL = bloc (procédure
anonyme, procédure nommée, fonction
nommée) :
DECLARE
-- section de déclarations
-- section optionnelle
…
BEGIN
-- traitement, avec d éventuelles directives SQL
-- section obligatoire
…
EXCEPTION
-- gestion des erreurs retournées par le SGBDR
-- section optionnelle
…
END;
/ ← lance l exécution sous SQL*Plus
Exemple
DECLARE
-- Quelques variables
v_nbFilms INTEGER;
v_nbArtistes INTEGER;
BEGIN
-- Compte le nombre de films
SELECT COUNT(*) INTO v_nbFilms FROM Film;
-- Compte le nombre d'artistes
SELECT COUNT(*) INTO v_nbArtistes FROM Artiste;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE ('Problème rencontré dans StatsFilms');
END;
Identificateurs, commentaires
• Identificateur :
▫ Variable, curseur, exception, etc.
▫ Commence par une lettre
▫ Peut contenir : lettres, chiffres, $, #, _
▫ Interdits : &, -, /, espace
▫ Jusqu’à 30 caractères
▫ Insensible à la casse !
(nompilote = NomPILOTE)
• Commentaires :
-- Commentaire sur une seule ligne
/* Commentaire sur plusieurs
lignes */
Variables
• Toute variable PL/SQL :
▫ Obligatoirement défini dans DECLARE avant utilisation
• Types de variables PL/SQL :
▫ Types Scalaires (Oracle) :
NUMBER(5,2),
VARCHAR2,
DATE,
BOOLEAN, …
▫ Composites :
%TYPE (schéma d’un attribut),
%ROWTYPE (schéma d’une table ou résultat de requête),
RECORD (type complexe dérivé),
TABLE (tables dynamiques)
▫ Référence :
REF
▫ Large Object :
LOB (jusqu’à 4 Go ; pointeur si externe)
Introduction aux Bases de Données N. Travers 13
Variables scalaires
• Syntaxe de déclaration :
Identificateur [CONSTANT] type [[NOT NULL] {:= |
DEFAULT} expression];
▫ CONSTANT :
c’est une constante (doit être initialisée)
▫ NOT NULL :
on ne peut pas lui affecter une valeur nulle (sinon exception
VALUE_ERROR)
▫ Initialisation :
:= (affectation)
DEFAULT
• Pas de déclaration multiple dans PL/SQL !
number1, number2 NUMBER;← déclaration incorrecte !
Variables et SQL
• Possibilité d affecter une valeur grâce à une requête SQL
Variables composites
• TYPE adresse IS RECORD
(no INTEGER,
rue VARCHAR(40),
ville VARCHAR(40),
codePostal VARCHAR(10) ;
• titre Film.titre%TYPE;
▫ Même type qu’un attribut ou autre variable ;
▫ Préserve des modifications de tables ;
• artiste Artiste%ROWTYPE
▫ Contraintes NOT NULL de la table non transmises ;
▫ un seul tuple affecter à une variable %ROWTYPE !
• Schéma :
▫ Film (id_film, titre, id_mes, année, coût, recette)
▫ Artiste (id, nom, prenom, date_naiss)
Conversions implicites
▫ Lors du calcul d’une expression ou d’une affectation
▫ Exception si conversion non autorisée
BINARY_ NUMBE
De A CHAR VARCHAR2 LONG DATE RAW ROWID
INTEGER R
BINARY_
OUI OUI OUI OUI
INTEGER
Conversions explicites
DATE TO_CHAR
RAW RAWTOHEX
ROWID ROWIDTOHEX
Variables TABLE
• Tableaux dynamiques, composé de :
▫ Clé primaire
▫ Colonne de type scalaire
%TYPE, %ROWTYPE ou RECORD
Affectation de Variables :
ligne de commande
SQL> ACCEPT s_titre PROMPT Titre Film :
SQL> ACCEPT s_annee PROMPT Année de sortie :
SQL> ACCEPT s_MES PROMPT Metteur en scène :
DECLARE
id_film NUMBER(6,2) DEFAULT 1;
BEGIN
INSERT INTO Film VALUES
(id_film, &s_titre , &s_annee, &s_MES, 0, 0);
END;
/
Entrées et Sorties
• Paquetage DBMS_OUTPUT :
▫ Sortie d’une valeur :
PUT(valeur IN {VARCHAR2 | DATE | NUMBER});
▫ Sortie d’une valeur suivie de fin de ligne :
PUT_LINE(valeur IN {VARCHAR2 | DATE |
NUMBER});
▫ Entrée d’une valeur :
GET_LINE(ligne OUT VARCHAR2(255), statut OUT
INTEGER);
Structures de contrôle
• Structures Conditionnelles
▫ If then else
▫ Case when
• Structures Répétitives
▫ While
▫ Loop
▫ For
Structures conditionnelles
▫ IF <condition> THEN ▫ CASE <variable>
<instructions> ; WHEN <value> THEN
ELSIF <condition> THEN <instructions> ;
<instructions> ;
…
ELSE
WHEN <value> THEN
<instructions> ;
<instructions> ;
END IF;
ELSE
<instructions> ;
END CASE;
IF : exemple
DECLARE
titre Film.titre%TYPE;
BEGIN
IF episode = 4 THEN
DBMS_OUTPUT.PUT_LINE ( A new Hope );
ELSIF episode = 5 THEN
DBMS_OUTPUT.PUT_LINE ( Empire strikes Back );
ELSIF episode = 7 THEN
DBMS_OUTPUT.PUT_LINE ( The Force Awakens );
END IF;
END;
/
CASE
• Seul le cas valide est traité
• Si aucun cas valide : exception CASE_NOT_FOUND
• Exemple :
DECLARE
titre Film.titre%TYPE;
BEGIN
CASE episode
WHEN 1 THEN DBMS_OUTPUT.PUT_LINE ( The Fantom Menace );
WHEN 2 THEN DBMS_OUTPUT.PUT_LINE ( The Clone Wars );
WHEN 3 THEN DBMS_OUTPUT.PUT_LINE ( Revange of the Siths );
WHEN 4 THEN DBMS_OUTPUT.PUT_LINE ( A new Hope );
WHEN 5 THEN DBMS_OUTPUT.PUT_LINE ( Empire strikes Back );
WHEN 6 THEN DBMS_OUTPUT.PUT_LINE ( Return of the Jedi );
WHEN 7 THEN DBMS_OUTPUT.PUT_LINE ( The Force Awakens );
ELSE
DBMS_OUTPUT.PUT_LINE ( Unkown episode );
END IF;
END;
/
Introduction aux Bases de Données N. Travers 33
Structures répétitives
▫ WHILE <condition> LOOP
<instructions> ;
END LOOP;
▫ LOOP
<instructions> ;
EXIT WHEN <condition> ;
<instructions>
END LOOP;
DECLARE
a INTEGER := 1;
b INTEGER := 1;
BEGIN
FOR b IN 1..10 LOOP
a := a * b;
END LOOP;
END;
Boucles imbriquées
• Chaque structure répétitives peut avoir une étiquette :
<<étiquette>>
DECLARE
…
BEGIN
…
<<boucleExterne>>
LOOP
…
LOOP
…
EXIT boucleExterne WHEN …;
/* quitter boucle externe */
…
EXIT WHEN …;
-- quitter boucle interne
END LOOP;
…
END LOOP;
…
END;
Curseurs
• Problème :
▫ Accès direct : ne prend qu’un seul tuple
▫ Comment récupérer plusieurs tuples ?
Ø curseur parcourt un par un chaque tuple résultat
(‘pointeur’ sur résultats).
Chaque tuple récupéré pourra être mis dans une
variable
Curseurs : instructions
DECLARE
-- Définition du curseur sur tous les films
CURSOR lesFilms IS SELECT * FROM Film;
BEGIN
-- Ouverture du curseur et exécution de la requête
OPEN lesFilms;
Curseur : Exercice
• Programme avec curseur
▫ Récupérer tous les films dont ‘Georges Lucas’ est
le metteur en scène (MES)
▫ Afficher pour chaque film le titre et l’année
▫ Bonus: Afficher le gain total de tous les films
Somme(recette) - somme(cout)
• Schéma :
▫ Film (id_film, titre, id_mes, année, coût, recette)
▫ Artiste (id, nom, prenom, date_naiss)
Curseur paramétré
• Objectif :
▫ paramétrer la requête associée à un curseur
Provient d’une variable temporaire, paramètre du programme
• Syntaxe :
CURSOR nomCurseur(param1[, param2, …]) IS …;
Paramètres :
nomPar [IN] type [{:= | DEFAULT} valeur];
(nomPar est inconnu en dehors de la définition !)
• Utilisation :
OPEN nomCurseur(valeurPar1[, valeurPar2, …]);
• Fermeture (CLOSE) avant d utiliser avec d autres
paramètres
• Schéma :
▫ Film (id_film, titre, id_mes, année, coût, recette)
▫ Artiste (id, nom, prenom, date_naiss)
Programmes et Sous-Programmes
• Nommage et paramétrage de Blocs
▫ Procédure
Eventuellement retourne DES résultats
▫ Fonction
Résultat unique obligatoire
Appel possible dans une requête SQL
• Programmes stockés dans la base
▫ Modularité (conception et maintenance),
▫ Réutilisation
▫ Intégrité (regroupement de traitements dépendants)
▫ Sécurité (gestion des droits/contraintes sur données)
• Récursivité autorisée (à utiliser avec précaution) !
• Sous-Programmes
▫ Défini dans le DECLARE
Appel de programme
• Appel de procédure/fonction depuis un bloc PL/SQL :
nomProcedure(listeParEffectifs);
Procédures
• Syntaxe :
CREATE [OR REPLACE] PROCEDURE nomProcedure
[(par1 [IN | OUT | IN OUT] [NOCOPY] type1
[{:= | DEFAULT} expression]
[, par2 [IN | OUT | IN OUT] [NOCOPY] type2
[{:= | DEFAULT} expression … )]
{IS | AS} [declarations;]
BEGIN
<instructions>;
[EXCEPTION
<traitementExceptions>;
]
END [nomProcedure];
Paramètres
• Types de paramètres :
▫ Entrée (IN)
Valeur constante (pas d’affectation)
Toujours passé par référence !
▫ Sortie (OUT)
Valeur de retour
Ne peut être qu’affecté (pas utilisé)
Par défaut (sans NOCOPY) passé par valeur !
▫ Entrée et sortie (IN OUT)
Passé en référence
Valeur de retour
Peut être utilisé et affecté
Par défaut (sans NOCOPY) passé par valeur !
• NOCOPY
▫ Données retours par référence (paramètres volumineux)
END;
Fonctions
• Syntaxe :
CREATE [OR REPLACE] FUNCTION nomFonction
[(par1 [IN | OUT | IN OUT] [NOCOPY] type1
[{:= | DEFAULT} expression]
[, par2 [IN | OUT | IN OUT] [NOCOPY] type2
[{:= | DEFAULT} expression … )]
-- OUT a éviter (effets de bords)
RETURN typeRetour
{IS | AS} [declarations;]
BEGIN
<instructions>;
…
RETURN varRetour;
-- return obligatoire
[EXCEPTION
<traitementExceptions>;
]
END[nomFonction];
Introduction aux Bases de Données N. Travers 54
Procédures stockées : PL/SQL
Fonctions : Exemple
DECLARE
FUNCTION nbFilms (idMES Film.MES%TYPE)
RETURN INTEGER
IS
nbFilm INTEGER;
BEGIN
SELECT COUNT(*) INTO nbFilm FROM Film
WHERE MES = idMES;
RETURN nbFilm;
END nbFilms;
CURSOR mes IS
SELECT * FROM Artiste where id in (select MES from Film);
leMes Film%ROWTYPE;
nbFilm INTEGER;
BEGIN
FOR leMes IN mes() LOOP
nbFilm := nbFilms(leMes.id);
DBMS_OUTPUT.PUT_LINE(leMes.prenom|| ||leMes.nom|| : ||nbFilm);
END LOOP;
END;
Manipulation de programme
• Création ou modification de sous-programme :
CREATE [OR REPLACE] {PROCEDURE | FUNCTION} nom …
• Recompilation automatique lors d une modification
▫ Pour une compilation manuelle :
ALTER {PROCEDURE | FUNCTION} nom COMPILE
▫ Affichage des erreurs de compilation sous SQL*Plus :
SHOW ERRORS
• Suppression de sous-programme :
DROP {PROCEDURE | FUNCTION} nom
Paquetages
• Paquetage
▫ Regroupement variables, curseurs, fonctions, procédures,
etc.
▫ Ensemble cohérent de services
• Encapsulation
▫ Accès extérieurs
▫ Accès privés (internes au paquetage)
• Structure
▫ Section de spécification
Déclaration des variables et curseurs,
Déclaration sous-programmes accessibles depuis l’extérieur
▫ Section d’implémentation
Code des sous-programmes accessibles depuis l’extérieur
Sous-programmes accessibles en interne (privés)
Section de spécification
• Syntaxe :
CREATE [OR REPLACE] PACKAGE nomPaquetage {IS | AS}
[declarationTypeRECORDpublique …; ]
[declarationTypeTABLEpublique …; ]
[declarationSUBTYPEpublique …; ]
[declarationRECORDpublique …; ]
[declarationTABLEpublique …; ]
[declarationEXCEPTIONpublique …; ]
[declarationCURSORpublique …; ]
[declarationVariablePublique …; ]
[declarationFonctionPublique …; ]
[declarationProcedurePublique …; ]
END [nomPaquetage];
Spécification : exemple
CREATE PACKAGE gestionMES AS
…
FUNCTION nbFilms(idMES Film.MES%TYPE)
RETURN INTEGER;
PROCEDURE filmParMES();
…
END gestionMES;
Section d implémentation
• Syntaxe :
CREATE [OR REPLACE] PACKAGE BODY nomPaquetage {IS | AS}
[declarationTypePrive …; ]
[declarationObjetPrive …; ]
[definitionFonctionPrivee …; ]
[definitionProcedurePrivee …; ]
[instructionsFonctionPublique …; ]
[instructionsProcedurePublique …; ]
END [nomPaquetage];
/* Fonction publique : Affiche pour chaque metteur en scène provenant un curseur privé :
- son prenom et son nom
- appel une procédure d affichage de tous ses films */
PROCEDURE filmParMES() IS
leMES Artiste%ROWTYPE;
BEGIN
FOR leMES IN lesMES() LOOP
DBMS_OUTPUT.PUT_LINE(leMES.prenom|| ||leMES.nom);
lesFilms (leMES.id);
END LOOP;
END filmParMES;
END gestionMES;
Référence au paquetage
• Uniquement sur les objets et programmes publics
• Syntaxe :
nomPaquetage.nomObjet
nomPaquetage.nomSousProgramme(…)
Manipulation d un paquetage
• Re-compilation d un paquetage :
▫ CREATE OR REPLACE PACKAGE
▫ Modification d’une sections
Ø re-compilation automatique de l’autre section
▫ Erreurs de compilation avec SQL*Plus :
SHOW ERRORS
• Suppression d un paquetage :
DROP BODY nomPaquetage;
DROP nomPaquetage;
Exceptions
• Conditions d erreur lors de l exécution
• EXCEPTION
▫ Clause de récupération d’erreur
▫ Evite l’arrêt systèmatique du programme
• Possibilité de définir des erreurs
• Affichage de l erreur
DBMS_OUTPUT.PUT_LINE(SQLERRM || : || SQLCODE);
Mécanismes de déclenchement
1. Déclenchement automatique
• Erreurs prédéfinies Oracle
• VALUE_ERROR, ZERO_DIVIDE, TOO_MANY_ROWS, etc.
2. Déclenchement programmé
• Dans DECLARE :
nomException EXCEPTION;
• Dans BEGIN :
RAISE nomException;
• Dans EXCEPTION :
WHEN nomException THEN
Transactions
• Objectif :
▫ Cohérence d’une suite de maj sur des données
État cohérent 1
de la base
Rollback
Instruction 1
Instruction 2
… Perturbation
Instruction n
Commit
État cohérent 2
de la base
Transactions : contrôle
• Début
▫ 1° SQL après le BEGIN
▫ 1° SQL après une transaction
• Fin
▫ Avec succès : COMMIT [WORK];
▫ Échec : ROLLBACK [WORK];
▫ Fin implicite
Avec succès : fin normale d’une session
Échec : fin anormale d’une session
Transactions/Exceptions : exemple
CREATE PROCEDURE ajoutFilm () IS
nvFilm Film%ROWTYPE;
nbFilm INTEGER;
mesErreur EXCEPTION;
filmErreur EXCEPTION;
BEGIN
SELECT MAX(id)+1 INTO film.id FROM Film;
nvFilm.titre := DBMS_OUTPUT.GET_LINE( Titre= ,1);
nvFilm.MES := trouver_idMES();
PL/SQL et MySQL
• Quelques différences :
▫ Déclaration d’une variable : DECLARE var <type>;
▫ Affectation de variable : SET variable = <expr>;
▫ Curseurs :
DECLARE cur CURSOR FOR <SQL>;
FETCH cur INTO a, b, c; (plusieurs variables)
▫ Pas de boucles FOR
▫ Afficher des données : SELECT
SELECT concat(‘texte : ’, var, ‘. Texte’) ;
▫ Exceptions
Déclarer un “maître” (Handler) pour l’erreur
Valable pour la procédure à partir de la déclaration
Différents types d’actions
Mysql et Erreurs
DECLARE <type d’action> HANDLER
FOR <condition d’erreur> [, <condition>] ...
<statement>
• Type d’action :
▫ CONTINUE / EXIT / UNDO
• Condition d’erreur :
▫ Erreur MySQL : SQLSTATE [VALUE] <sqlstate value>
http://dev.mysql.com/doc/refman/5.0/fr/error-handling.html
Ex : 23000 : valeur unique, 42000 : incorrect/inconnu/interdit
▫ SQLWARNING / NOT FOUND / SQLEXCEPTION