• Aucun résultat trouvé

Introduction au PL/SQL Oracle. Alexandre Meslé

N/A
N/A
Protected

Academic year: 2022

Partager "Introduction au PL/SQL Oracle. Alexandre Meslé"

Copied!
79
0
0

Texte intégral

(1)

Introduction au PL/SQL Oracle

Alexandre Mesl´ e

17 octobre 2011

(2)

Table des mati` eres

1 Notes de cours 3

1.1 Introduction au PL/SQL . . . . 3

1.1.1 PL/SQL . . . . 3

1.1.2 Blocs . . . . 3

1.1.3 Affichage . . . . 3

1.1.4 Variables . . . . 3

1.1.5 Traitements conditionnels . . . . 4

1.1.6 Traitements r´ ep´ etitifs . . . . 4

1.2 Tableaux et structures . . . . 5

1.2.1 Tableaux . . . . 5

1.2.2 Structures . . . . 6

1.3 Utilisation du PL/SQL . . . . 8

1.3.1 Affectation . . . . 8

1.3.2 Tables et structures . . . . 8

1.3.3 Transactions . . . . 9

1.4 Exceptions . . . . 10

1.4.1 Rattraper une exception . . . . 10

1.4.2 Exceptions pr´ ed´ efinies . . . . 11

1.4.3 Codes d’erreur . . . . 11

1.4.4 D´ eclarer et lancer ses propres exceptions . . . . 11

1.5 Sous-programmes . . . . 13

1.5.1 Proc´ edures . . . . 13

1.5.2 Fonctions . . . . 13

1.6 Curseurs . . . . 15

1.6.1 Introduction . . . . 15

1.6.2 Les curseurs . . . . 15

1.7 Curseurs parametr´ es . . . . 17

1.7.1 Introduction . . . . 17

1.7.2 D´ efinition . . . . 17

1.7.3 D´ eclaration . . . . 17

1.7.4 Ouverture . . . . 17

1.7.5 Lecture d’une ligne, fermeture . . . . 17

1.7.6 Boucle pour . . . . 18

1.7.7 Exemple r´ ecapitulatif . . . . 18

1.8 Triggers . . . . 19

1.8.1 Principe . . . . 19

1.8.2 Classification . . . . 19

1.8.3 Cr´ eation . . . . 19

1.8.4 Acc` es aux lignes en cours de modification . . . . 20

1.8.5 Contourner le probl` eme des tables en mutation . . . . 22

1.9 Packages . . . . 25

1.9.1 Principe . . . . 25

1.9.2 Sp´ ecification . . . . 25

1.9.3 Corps . . . . 25

(3)

2 Exercices 27

2.1 Introduction au PL/SQL . . . . 27

2.2 Tableaux et Structures . . . . 28

2.3 Utilisation PL/SQL . . . . 30

2.4 Exceptions . . . . 31

2.5 Sous-programmes . . . . 32

2.6 Curseurs . . . . 33

2.7 Curseurs parametr´ es . . . . 34

2.8 Triggers . . . . 35

2.9 Packages . . . . 36

2.10 R´ evisions . . . . 37

3 Corrig´ es 38 3.1 Introduction au PL/SQL . . . . 38

3.2 Tableaux et Structures . . . . 39

3.3 Application du PL/SQL et Exceptions . . . . 42

3.4 Sous-programmes . . . . 46

3.5 Curseurs . . . . 49

3.6 Curseurs param´ etr´ es . . . . 52

3.7 Triggers . . . . 53

3.8 Packages . . . . 62

3.9 R´ evisions . . . . 63

A Scripts de cr´ eation de bases 67 A.1 Livraisons Sans contraintes . . . . 67

A.2 Modules et prerequis . . . . 68

A.3 G´ eom´ etrie . . . . 69

A.4 Livraisons . . . . 70

A.5 Arbre g´ en´ ealogique . . . . 71

A.6 Comptes bancaires . . . . 72

A.7 Comptes bancaires avec exceptions . . . . 74

A.8 Secr´ etariat p´ edagogique . . . . 76

A.9 Mariages . . . . 78

(4)

Chapitre 1

Notes de cours

1.1 Introduction au PL/SQL

1.1.1 PL/SQL

Le PL de PL/SQL signifie Procedural Language. Il s’agit d’une extension proc´ edurale du SQL permettant d’effectuer des traitements complexes sur une base de donn´ ees. Les possibilit´ es offertes sont les mˆ emes qu’avec des langages imp´ eratifs (instructions en s´ equence) classiques.

Ecrivez-le dans un ´ editeur dont vous copierez le contenu dans SQL+. Un script ´ ecrit en PL/SQL se termine obliga- toirement par un /, sinon SQL+ ne l’interpr` ete pas. S’il contient des erreurs de compilation, il est possible d’afficher les messages d’erreur avec la commande SQL+ : SHOW ERRORS.

1.1.2 Blocs

Tout code ´ ecrit dans un langage proc´ edural est form´ e de blocs. Chaque bloc comprend une section de d´ eclaration de variables, et un ensemble d’instructions dans lequel les variables d´ eclar´ ees sont visibles.

La syntaxe est DECLARE

/∗ d e c l a r a t i o n de v a r i a b l e s ∗/

BEGIN

/∗ i n s t r u c t i o n s a e x e c u t e r ∗/

END;

1.1.3 Affichage

Pour afficher le contenu d’une variable, les proc´ edures DBMS OUTPUT.PUT() et DBMS OUTPUT.PUT LINE() prennent en argument une valeur ` a afficher ou une variable dont la valeur est ` a afficher. Par d´ efaut, les fonctions d’affichage sont desactiv´ ees. Il convient, ` a moins que vous ne vouliez rien voir s’afficher, de les activer avec la commande SQL+

SET SERVEROUTPUT ON.

1.1.4 Variables

Une variable se d´ eclare de la sorte : nom type [ : = initialisation ] ;

L’initisation est optionnelle. Nous utiliserons les mˆ emes types primitifs que dans les tables. Par exemple : SET SERVEROUTPUT ON

DECLARE

c varchar2 ( 1 5 ) := ’ H e l l o World ! ’ ; BEGIN

DBMS_OUTPUT . PUT_LINE ( c ) ; END;

/

Les affectations se font avec la syntaxe variable := valeur ;

(5)

1.1.5 Traitements conditionnels

Le IF et le CASE fonctionnent de la mˆ eme fa¸ con que dans les autres langages imp´ eratifs : IF /∗ c o n d i t i o n 1 ∗ / THEN

/∗ i n s t r u c t i o n s 1 ∗/

ELSE

/∗ i n s t r u c t i o n s 2 ∗/

END IF ; voire

IF /∗ c o n d i t i o n 1 ∗ / THEN /∗ i n s t r u c t i o n s 1 ∗/

ELSIF /∗ c o n d i t i o n 2 ∗/

/∗ i n s t r u c t i o n s 2 ∗/

ELSE

/∗ i n s t r u c t i o n s 3 ∗/

END IF ;

Les conditions sont les mˆ emes qu’en SQL. Le switch du langage C s’impl´ emente en PL/SQL de la fa¸ con suivante : CASE /∗ v a r i a b l e ∗ /

WHEN /∗ v a l e u r 1 ∗ / THEN /∗ i n s t r u c t i o n s 1 ∗/

WHEN /∗ v a l e u r 2 ∗ / THEN /∗ i n s t r u c t i o n s 2 ∗/

. . .

WHEN /∗ v a l e u r n ∗ / THEN /∗ i n s t r u c t i o n s n ∗/

ELSE

/∗ i n s t r u c t i o n s p a r d ´ e f a u t ∗/

END CASE;

1.1.6 Traitements r´ ep´ etitifs

LOOP ... END LOOP ; permet d’impl´ ementer les boucles LOOP

/∗ i n s t r u c t i o n s ∗/

END LOOP ;

L’instruction EXIT WHEN permet de quitter une boucle.

LOOP

/∗ i n s t r u c t i o n s ∗/

EXIT WHEN /∗ c o n d i t i o n ∗/ ; END LOOP ;

La boucle FOR existe aussi en PL/SQL :

FOR /∗ v a r i a b l e ∗ / IN /∗ i n f ∗/ . . /∗ sup ∗ / LOOP /∗ i n s t r u c t i o n s ∗/

END LOOP ;

Ainsi que la boucle WHILE : WHILE /∗ c o n d i t i o n ∗/ LOOP

/∗ i n s t r u c t i o n s ∗/

END LOOP ;

Est-il possible, en bidouillant, d’impl´ ementer une boucle DO ... WHILE ?

(6)

1.2 Tableaux et structures

1.2.1 Tableaux

Cr´ eation d’un type tableau

Les types tableau doivent ˆ etre d´ efinis explicitement par une d´ eclaration de la forme TYPE /∗ t y p e ∗ / IS VARRAY ( /∗ t a i l l e ∗ / ) OF /∗ t y p e E l e m e n t s ∗/ ;

– type est le nom du type tableau cr´ ee par cette instruction

– taille est le nombre maximal d’´ el´ ements qu’il est possible de placer dans le tableau.

– typeElements est le type des ´ el´ ements qui vont ˆ etre stock´ es dans le tableau, il peut s’agir de n’importe quel type.

Par exemple, cr´ eons un type tableau de nombres indic´ e de 1 ` a 10, que nous appelerons numberTab TYPE numberTab IS VARRAY ( 1 0 ) OF NUMBER;

D´ eclaration d’un tableau

Dor´ enavant, le type d’un tableau peut ˆ etre utilis´ e au mˆ eme titre que NUMBER ou VARCHAR2. Par exemple, d´ eclarons un tableau appel´ e t de type numberTab,

DECLARE

TYPE numberTab IS VARRAY ( 1 0 ) OF NUMBER;

t numberTab ; BEGIN

/∗ i n s t r u c t i o n s ∗/

END;

/

Allocation d’un tableau

La cr´ eation d’un type tableau met ` a disposition un constructeur du mˆ eme nom que le type cr´ e´ e. Cette fonction r´ eserve de l’espace m´ emoire pour ce tableau et retourne l’adresse m´ emoire de la zone r´ eserv´ ee, il s’agit d’une sorte de malloc. Si, par exemple, un type tableau numtab a ´ et´ e cr´ ee, la fonction numtab() retourne une tableau vide.

DECLARE

TYPE numberTab IS VARRAY ( 1 0 ) OF NUMBER;

t numberTab ; BEGIN

t := numberTab ( ) ;

/∗ u t i l i s a t i o n du t a b l e a u ∗/

END;

/

Une fois cette allocation faite, il devient presque possible d’utiliser le tableau...

Dimensionnement d’un tableau

Le tableau retourn´ e par le constructeur est vide. Il convient ensuite de r´ eserver de l’espace pour stocker les ´ el´ ements qu’il va contenir. On utilise pour cela la m´ ethode EXTEND(). EXTEND s’invoque en utilisant la notation point´ ee. Par exemple,

DECLARE

TYPE numberTab IS VARRAY ( 1 0 ) OF NUMBER;

t numberTab ; BEGIN

t := numberTab ( ) ; t . EXTEND ( 4 ) ;

/∗ u t i l i s a t i o n du t a b l e a u ∗/

END;

/

(7)

Dans cet exemple, t.EXTEND(4) ; permet par la suite d’utiliser les ´ el´ ements du tableau t(1), t(2), t(3) et t(4).

Il n’est pas possible ”d’´ etendre” un tableau ` a une taille sup´ erieure ` a celle sp´ ecifi´ ee lors de la cr´ eation du type tableau associ´ e.

Utilisation d’un tableau

On acc` ede, en lecture et en ´ ecriture, au i-` eme ´ el´ ement d’une variable tabulaire nomm´ e T avec l’instruction T(i).

Les ´ el´ ements sont indic´ es ` a partir de 1.

Effectuons, par exemple, une permutation circulaire vers la droite des ´ el´ ements du tableau t.

DECLARE

TYPE numberTab IS VARRAY ( 1 0 ) OF NUMBER;

t numberTab ; i number ; k number ; BEGIN

t := numberTab ( ) ; t . EXTEND ( 1 0 ) ;

FOR i IN 1 . . 1 0 LOOP t ( i ) := i ; END LOOP ;

k := t ( 1 0 ) ;

FOR i in REVERSE 2 . . 1 0 LOOP t ( i ) := t (i − 1 ) ; END LOOP ;

t ( 1 ) := k ;

FOR i IN 1 . . 1 0 LOOP

DBMS_OUTPUT . PUT_LINE ( t ( i ) ) ; END LOOP ;

END;

/

1.2.2 Structures

Un structure est un type regroupant plusieurs types. Une variable de type structur´ e contient plusieurs variables, ces variables s’appellent aussi des champs.

Cr´ eation d’un type structur´ e

On d´ efinit un type structur´ e de la sorte :

TYPE /∗ nomType ∗ / IS RECORD

(

/∗ l i s t e d e s champs ∗/

) ;

nomType est le nom du type structur´ e construit avec la syntaxe pr´ ec´ edente. La liste suit la mˆ eme syntaxe que la liste des colonnes d’une table dans un CREATE TABLE. Par exemple, construisons le type point (dans IR

2

),

TYPE point IS RECORD (

abscisse NUMBER , ordonnee NUMBER ) ;

Notez bien que les types servant ` a d´ efinir un type structur´ e peuvent ˆ etre quelconques : variables scalaires, tableaux, structures, etc.

D´ eclaration d’une variable de type structur´ e

point est maintenant un type, il devient donc possible de cr´ eer des variables de type point, la r` egle est toujours la

mˆ eme pour d´ eclarer des variables en PL/SQL, par exemple

(8)

p point ;

permet de d´ eclarer une variable p de type point.

Utilisation d’une variable de type structur´ e

Pour acc´ eder ` a un champ d’une variable de type structur´ e, en lecture ou en ´ ecriture, on utilise la notation point´ ee : v.c est le champ appel´ e c de la variable structur´ e appel´ ee v. Par exemple,

DECLARE

TYPE point IS RECORD (

abscisse NUMBER , ordonnee NUMBER ) ;

p point ; BEGIN

p . abscisse := 1 ; p . ordonnee := 3 ;

DBMS_OUTPUT . PUT_LINE ( ’ p . a b s c i s s e = ’ | | p . abscisse | |

’ and p . o rd o n n e e = ’ | | p . ordonnee ) ; END;

/

Le script ci-dessous cr´ ee le type point, puis cr´ ee une variable t de type point, et enfin affecte aux champs abscisse

et ordonnee du point p les valeurs 1 et 3.

(9)

1.3 Utilisation du PL/SQL

Ce cours est une introduction aux interactions possibles entre la base de donn´ ees et les scripts PL/SQL.

1.3.1 Affectation

On place dans une variable le r´ esultat d’une requˆ ete en utilisant le mot-cl´ e INTO. Les instructions SELECT champ_1 , . . . , champ_n INTO v_1 , . . . , v_n

FROM . . .

affecte aux variables v 1, ..., v n les valeurs retourn´ ees par la requˆ ete. Par exemple DECLARE

num NUMBER;

nom VARCHAR2( 3 0 ) := ’ Poup´ ee Batman ’ ; BEGIN

SELECT numprod INTO num FROM PRODUIT

WHERE nomprod = nom ;

DBMS_OUTPUT . PUT_LINE ( ’L ’ ’ a r t i c l e ’ | | nom | | ’ a pour num´ ero ’ | | num ) ; END;

/

Prˆ etez attention au fait que la requˆ ete doit retourner une et une une seule ligne, sinon, une erreur se produit ` a l’ex´ ecution.

1.3.2 Tables et structures

Si vous ne tenez pas ` a vous prendre la tˆ ete pour choisir le type de chaque variable, demandez-vous ce que vous allez mettre dedans ! Si vous tenez ` a y mettre une valeur qui se trouve dans une colonne d’une table, il est possible de vous r´ ef´ erer directement au type de cette colonne avec le type nomTable.nomColonne%type. Par exemple,

DECLARE

num PRODUIT . numprod%type ;

nom PRODUIT . nomprod%type := ’ Poup´ ee Batman ’ ; BEGIN

SELECT numprod INTO num FROM PRODUIT

WHERE nomprod = nom ;

DBMS_OUTPUT . PUT_LINE ( ’L ’ ’ a r t i c l e ’ | | nom | | ’ a pour num´ ero ’ | | num ) ; END;

/

Pour aller plus loin, il est mˆ eme possible de d´ eclarer une structure pour repr´ esenter une ligne d’une table, le type porte alors le nom suivant : nomTable%rowtype.

DECLARE

nom PRODUIT . nomprod%type := ’ Poup´ ee Batman ’ ; ligne PRODUIT%rowtype ;

BEGIN

SELECT ∗ INTO ligne FROM PRODUIT

WHERE nomprod = nom ;

DBMS_OUTPUT . PUT_LINE ( ’L ’ ’ a r t i c l e ’ | |

ligne . nomprod | | ’ a pour num´ ero ’ | | ligne . numprod ) ; END;

/

(10)

1.3.3 Transactions

Un des m´ ecanismes les plus puissants des SGBD r´ ecents r´ eside dans le syst` eme des transactions. Une transaction est un ensemble d’op´ erations “atomiques”, c’est-` a-dire indivisible. Nous consid´ ererons qu’un ensemble d’op´ erations est indivisible si une ex´ ecution partielle de ces instructions poserait des probl` emes d’int´ egrit´ e dans la base de donn´ ees.

Par exemple, dans le cas d’une base de donn´ ees de gestion de comptes en banque, un virement d’un compte ` a un autre se fait en deux temps : cr´ editer un compte d’une somme s, et d´ ebiter un autre de la mˆ eme somme s. Si une erreur survient pendant la deuxi` eme op´ eration, et que la transaction est interrompue, le virement est incomplet et le patron va vous assassiner.

Il convient donc de disposer d’un m´ ecanisme permettant de se prot´ eger de ce genre de d´ esagr´ ement. Plutˆ ot que se casser la tˆ ete ` a tester les erreurs ` a chaque ´ etape et ` a balancer des instructions permettant de “revenir en arri` ere”, nous allons utiliser les instructions COMMIT et ROLLBACK.

Voici le squelette d’un exemple : /∗ i n s t r u c t i o n s ∗ /

IF /∗ e r r e u r ∗ / THEN ROLLBACK;

ELSE

COMMIT;

END;

Le ROLLBACK annule toutes les modifications faites depuis le d´ ebut de la transaction (donc depuis le pr´ ec´ edent COMMIT), COMMIT les enregistre d´ efinitivement dans la base de donn´ ees.

La variable d’environnement AUTOCOMMIT, qui peut ˆ etre positionn´ ee ` a ON ou ` a OFF permet d’activer la gestion des

transactions. Si elle est positionn´ ee ` a ON, chaque instruction a des r´ epercussions imm´ ediates dans la base, sinon, les

modifications ne sont effectives qu’une fois qu’un COMMIT a ´ et´ e ex´ ecut´ e.

(11)

1.4 Exceptions

Le m´ ecanisme des exceptions est impl´ ement´ e dans la plupart des langages r´ ecent, notament orient´ es objet. Cette fa¸con de programmer a quelques avantages imm´ ediats :

– obliger les programmeurs ` a traiter les erreurs : combien de fois votre prof de C a hurl´ e en vous suppliant de v´ erifier les valeurs retourn´ ees par un malloc, ou un fopen ? La plupart des compilateurs des langages ` a exceptions (notamment java) ne compilent que si pour chaque erreur potentielle, vous avez pr´ epar´ e un bloc de code (´ eventuellement vide...) pour la traiter. Le but est de vous assurer que vous n’avez pas oubli´ e d’erreur.

– Rattraper les erreurs en cours d’ex´ ecution : Si vous programmez un syst` eme de s´ ecurit´ e de centrale nucl´ eaire ou un pilote automatique pour l’aviation civile, une erreur de m´ emoire qui vous afficherait l’´ ecran bleu de windows, ou le message “Envoyer le rapport d’erreur ?”, ou plus simplement le fameux “Segmentation fault” produirait un effet des plus mauvais. Certaines erreurs d’´ execution sont rattrapables, autrement dit, il est possible de r´ esoudre le probl` eme sans interrompre le programme.

– Ecrire le traitement des erreurs ` a part : Pour des raisons fiabilit´ e, de lisibilit´ e, il a ´ et´ e consid´ er´ e que m´ elanger le code “normal” et le traitement des erreurs ´ etait un style de programmation perfectible... Dans les langages ` a exception, les erreurs sont trait´ ees ` a part.

1.4.1 Rattraper une exception

Je vous ai menti dans le premier cours, un bloc en PL/SQL a la forme suivante : DECLARE

/∗ d e c l a r a t i o n s ∗/

BEGIN

/∗ i n s t r u c t i o n s ∗/

EXCEPTION

/∗ t r a i t e m e n t d e s e r r e u r s ∗/

END;

Une exception est une “erreur type”, elle porte un nom, au mˆ eme titre qu’une variable a une identificateur, par exemple GLUBARF. Lorsque dans les instructions, l’erreur GLUBARF se produit, le code du BEGIN s’interrompt et le code de la section EXCEPTION est lanc´ e. On dit aussi que quand une exception est lev´ ee (raised) (on dit aussi jet´ ee (thrown)), on la rattrape (catch) dans le bloc EXCEPTION. La section EXCEPTION a la forme suivante :

EXCEPTION

WHEN E1 THEN

/∗ t r a i t e m e n t ∗/

WHEN E2 THEN

/∗ t r a i t e m e n t ∗/

WHEN E3 THEN

/∗ t r a i t e m e n t ∗/

WHEN OTHERS THEN

/∗ t r a i t e m e n t ∗/

END;

On ´ enum` ere les erreurs les plus pertinentes en utilisant leur nom et en consacrant ` a chacune d’elle un traitement particulier pour rattraper (ou propager) l’erreur. Quand un bloc est trait´ e, les WHEN suivants ne sont pas ´ evalu´ es.

OTHERS est l’exception par d´ efaut, OTHERS est toujours v´ erifi´ e, sauf si un cas pr´ ec´ edent a ´ et´ e v´ erifi´ e. Dans l’exemple suivant :

DECLARE

/∗ d e c l a r a t i o n s ∗/

BEGIN

/∗ i n s t r u c t i o n s ∗/

COMMIT;

EXCEPTION

WHEN GLUBARF THEN ROLLBACK;

DBMS_OUTPUT . PUT_LINE ( ’GLUBARF e x c e p t i o n r a i s e d ! ’ ) ; WHEN OTHERS THEN

DBMS_OUTPUT . PUT_LINE ( ’SQLCODE = ’ | | SQLCODE ) ;

DBMS_OUTPUT . PUT_LINE ( ’SQLERRM = ’ | | SQLERRM ) ;

(12)

END;

Les deux variables globales SQLCODE et SQLERRM contiennent respectivement le code d’erreur Oracle et un message d’erreur correspondant ` a la derni` ere exception lev´ ee. Chaque exception a donc, en plus d’un nom, un code et un message.

1.4.2 Exceptions pr´ ed´ efinies

Bon nombre d’exceptions sont pr´ ed´ efinies par Oracle, par exemple

– NO DATA FOUND est lev´ ee quand la requˆ ete d’une instruction de la forme SELECT ... INTO ... ne retourne aucune ligne

– TOO MANY ROWS est lev´ ee quand la requˆ ete d’une instruction de la forme SELECT ... INTO ... retourne plusieurs lignes

– DUP VAL ON INDEX est lev´ ee si une insertion (ou une modification) est refus´ ee ` a cause d’une contrainte d’unicit´ e.

On peut enrichir notre exemple de la sorte : DECLARE

num NUMBER;

nom VARCHAR2( 3 0 ) := ’ Poup´ ee Batman ’ ; BEGIN

SELECT numprod INTO num FROM PRODUIT

WHERE nomprod = nom ;

DBMS_OUTPUT . PUT_LINE ( ’L ’ ’ a r t i c l e ’ | | nom | | ’ a pour num´ ero ’ | | num ) ; EXCEPTION

WHEN NO_DATA_FOUND THEN

DBMS_OUTPUT . PUT_LINE ( ’ Aucun a r t i c l e ne p o r t e l e nom ’

| | nom ) ;

WHEN TOO_MANY_ROWS THEN

DBMS_OUTPUT . PUT_LINE ( ’ P l u s i e u r s a r t i c l e s p o r t e n t l e nom ’

| | nom ) ; WHEN OTHERS THEN

DBMS_OUTPUT . PUT_LINE ( ’ I l y a un g r o s p r o b l` e m e . . . ’ ) ; END;

/

SELECT numprod INTO num... l` eve une exception si la requˆ ete renvoie un nombre de lignes diff´ erent de 1.

1.4.3 Codes d’erreur

Je vous encore menti, certaines exceptions n’ont pas de nom. Elle ont seulement un code d’erreur, il est conseill´ e de se reporter ` a la documentation pour les obtenir. On les traite de la fa¸ con suivante

EXCEPTION

WHEN OTHERS THEN

IF SQLCODE = CODE1 THEN /∗ t r a i t e m e n t ∗ / ELSIF SQLCODE = CODE2 THEN

/∗ t r a i t e m e n t ∗ / ELSE

DBMS_OUTPUT . PUT_LINE ( ’ J ’ ’ v o i s p a s c ’ ’ que ca p e u t e t r e . . . ’ ) ;

END;

C’est souvent le cas lors de violation de contraintes.

1.4.4 D´ eclarer et lancer ses propres exceptions

Exception est un type, on d´ eclare donc les exceptions dans une section DECLARE. Une exception se lance avec

l’instruction RAISE. Par exemple,

(13)

DECLARE

GLUBARF EXCEPTION;

BEGIN

RAISE GLUBARF ; EXCEPTION

WHEN GLUBARF THEN

DBMS_OUTPUT . PUT_LINE ( ’ g l u b a r f r a i s e d . ’ ) ; END;

/

(14)

1.5 Sous-programmes

1.5.1 Proc´ edures

Syntaxe

On d´ efinit une proc´ edure de la sorte

CREATE OR REPLACE PROCEDURE /∗ nom ∗/ ( /∗ p a r a m e t r e s ∗/ ) IS /∗ d e c l a r a t i o n d e s v a r i a b l e s l o c a l e s ∗ /

BEGIN

/∗ i n s t r u c t i o n s ∗/

END;

les param` etres sont une simple liste de couples nom type. Par exemple, la procedure suivante affiche un compte ` a rebours.

CREATE OR REPLACE PROCEDURE compteARebours ( n NUMBER ) IS BEGIN

IF n > = 0 THEN

DBMS_OUTPUT . PUT_LINE ( n ) ; compteARebours ( n − 1 ) ; END IF ;

END;

Invocation

En PL/SQL, une proc´ edure s’invoque tout simplement avec son nom. Mais sous SQL+, on doit utiliser le mot-cl´ e CALL. Par exemple, on invoque le compte ` a rebours sous SQL+ avec la commande CALL compteARebours(20).

Passage de param` etres

Oracle permet le passage de param` etres par r´ ef´ erence. Il existe trois types de passage de param` etres : – IN : passage par valeur

– OUT : aucune valeur pass´ ee, sert de valeur de retour – IN OUT : passage de param` etre par r´ ef´ erence

Par d´ efaut, le passage de param` etre se fait de type IN.

CREATE OR REPLACE PROCEDURE incr ( val IN OUT NUMBER ) IS BEGIN

val := val + 1 ; END;

1.5.2 Fonctions

Syntaxe

On cr´ ee une nouvelle fonction de la fa¸ con suivante :

CREATE OR REPLACE FUNCTION /∗ nom ∗/ ( /∗ p a r a m e t r e s ∗/ ) RETURN /∗ t y p e

∗/ IS

/∗ d e c l a r a t i o n d e s v a r i a b l e s l o c a l e s ∗ / BEGIN

/∗ i n s t r u c t i o n s ∗/

END;

L’instruction RETURN sert ` a retourner une valeur. Par exemple,

CREATE OR REPLACE FUNCTION module ( a NUMBER , b NUMBER ) RETURN NUMBER IS BEGIN

IF a < b THEN

RETURN a ;

ELSE

(15)

RETURN module ( a − b , b ) ; END IF ;

END;

Invocation

Tout comme les proc´ edures, l’invocation des fonctions ne pose aucun probl` eme en PL/SQL, par contre, sous SQL+, c’est quelque peu particulier. On passe par une pseudo-table nomm´ ee DUAL de la fa¸ con suivante :

SELECT module ( 2 1 , 1 2 ) FROM DUAL ;

Passage de param` etres

Les param` etres sont toujours pass´ es avec le type IN.

(16)

1.6 Curseurs

1.6.1 Introduction

Les instructions de type SELECT ... INTO ... manquent de souplesse, elles ne fontionnent que sur des requˆ etes retourant une et une seule valeur. Ne serait-il pas int´ eressant de pouvoir placer dans des variables le r´ esultat d’une requˆ ete retournant plusieurs lignes ? A m´ editer...

1.6.2 Les curseurs

Un curseur est un objet contenant le r´ esultat d’une requˆ ete (0, 1 ou plusieurs lignes).

d´ eclaration

Un curseur se d´ eclare dans une section DECLARE : CURSOR /∗ nomcurseur ∗/ IS /∗ r e q u ˆ e t e ∗ / ;

Par exemple, si on tient ` a r´ ecup´ erer tous les employ´ es de la table EMP, on d´ eclare le curseur suivant.

CURSOR emp_cur IS

SELECT ∗ FROM EMP ;

Ouverture

Lors de l’ouverture d’un curseur, la requˆ ete du curseur est ´ evalu´ ee, et le curseur contient toutes les donn´ ees retourn´ ees par la requˆ ete. On ouvre un curseur dans une section BEGIN :

OPEN /∗ nomcurseur ∗/ ;

Par exemmple, DECLARE

CURSOR emp_cur IS

SELECT ∗ FROM EMP ; BEGIN

OPEN emp_cur ;

/∗ U t i l i s a t i o n du c u r s e u r ∗/

END;

Lecture d’une ligne

Une fois ouvert, le curseur contient toutes les lignes du r´ esultat de la requˆ ete On les r´ ecup` ere une par une en utilisant le mot-cl´ e FETCH :

FETCH /∗ n o m c u r s e u r ∗/ INTO /∗ l i s t e v a r i a b l e s ∗/ ;

La liste de variables peut ˆ etre remplac´ ee par une structure de type nom curseur%ROWTYPE. Si la lecture de la ligne

´ echoue, parce qu’il n’y a plus de ligne ` a lire, l’attribut %NOTFOUND prend la valeur vrai.

DECLARE

CURSOR emp_cur IS

SELECT ∗ FROM EMP ; ligne emp_cur%rowtype BEGIN

OPEN emp_cur ; LOOP

FETCH emp_cur INTO ligne ; EXIT WHEN emp_cur%NOTFOUND ;

DBMS_OUTPUT . PUT_LINE ( ligne . ename ) ; END LOOP ;

/∗ . . . ∗ /

END;

(17)

Fermeture

Apr` es utilisation, il convient de fermer le curseur.

CLOSE /∗ nomcurseur ∗/ ; Compl´ etons notre exemple, DECLARE

CURSOR emp_cur IS

SELECT ∗ FROM EMP ; ligne emp_cur%rowtype ; BEGIN

OPEN emp_cur ; LOOP

FETCH emp_cur INTO ligne ; EXIT WHEN emp_cur%NOTFOUND ;

DBMS_OUTPUT . PUT_LINE ( ligne . ename ) ; END LOOP ;

CLOSE emp_cur ; END;

/

Le programme ci-dessus peut aussi s’´ ecrire DECLARE

CURSOR emp_cur IS

SELECT ∗ FROM EMP ; ligne emp_cur%rowtype ; BEGIN

OPEN emp_cur ;

FETCH emp_cur INTO ligne ; WHILE emp_cur%FOUND LOOP

DBMS_OUTPUT . PUT_LINE ( ligne . ename ) ; FETCH emp_cur INTO ligne ;

END LOOP ; CLOSE emp_cur ; END;

Boucle FOR

Il existe une boucle FOR se chargeant de l’ouverture, de la lecture des lignes du curseur et de sa fermeture, FOR ligne IN emp_cur LOOP

/∗ T r a i t e m e n t ∗/

END LOOP ; Par exemple, DECLARE

CURSOR emp_cur IS

SELECT ∗ FROM EMP ; ligne emp_cur%rowtype ; BEGIN

FOR ligne IN emp_cur LOOP

DBMS_OUTPUT . PUT_LINE ( ligne . ename ) ; END LOOP ;

END;

/

(18)

1.7 Curseurs parametr´ es

1.7.1 Introduction

A votre avis, le code suivant est-il valide ? DECLARE

NUMBER n := 1 4 ; BEGIN

DECLARE

CURSOR C IS SELECT ∗ FROM PERSONNE

WHERE numpers > = n ; ROW C%rowType ;

BEGIN

FOR ROW IN C LOOP

DBMS_OUTPUT . PUT_LINE ( ROW . numpers ) ; END LOOP ;

END;

END;

/

R´ eponse : non. La requˆ ete d’un curseur ne peut pas contenir de variables dont les valeurs ne sont pas fix´ ees.

Pourquoi ? Parce que les valeurs des ces sont susceptibles de changer entre la d´ eclaration du curseur et son ouverture.

Le rem` ede est un curseur param´ etr´ e.

1.7.2 D´ efinition

Un curseur param´ etr´ e est un curseur dont la requˆ ete contient des variables dont les valeurs ne seront fix´ ees qu’` a l’ouverture.

1.7.3 D´ eclaration

On pr´ ecise la liste des noms et des type des param` etres entre parenth` eses apr` es le nom du curseur : CURSOR /∗ nom ∗ / ( /∗ l i s t e d e s p a r a m` e t r e s ∗ / ) IS

/∗ r e q u ˆ e t e ∗/

Par exemple, cr´ eeons une requˆ ete qui, pour une personne donn´ ee, nous donne la liste des noms et pr´ enoms de ses enfants :

CURSOR enfants ( numparent NUMBER ) IS SELECT ∗

FROM PERSONNE

WHERE pere = numparent OR mere = numparent ;

1.7.4 Ouverture

On ouvre un curseur param´ etr´ e en passant en param` etre les valeurs des variables : OPEN /∗ nom ∗ / ( /∗ l i s t e d e s p a r a m` e t r e s ∗ / )

Par exemple,

OPEN enfants ( 1 ) ;

1.7.5 Lecture d’une ligne, fermeture

la lecture d’une ligne suit les mˆ emes r` egles qu’avec un curseur non param´ etr´ e.

(19)

1.7.6 Boucle pour

La boucle pour se charge de l’ouverture, il convient donc de placer les param` etre dans l’entˆ ete de la boucle, FOR /∗ v a r i a b l e ∗ / IN /∗ nom ∗/ ( /∗ l i s t e p a r a m` e t r e s ∗/ ) LOOP

/∗ i n s t r u c t i o n s ∗/

END LOOP ; Par exemple,

FOR e IN enfants ( 1 ) LOOP

DBMS_OUTPUT . PUT_LINE ( e . nompers | | ’ ’ | | e . prenompers ) ; END LOOP ;

1.7.7 Exemple r´ ecapitulatif

DECLARE

CURSOR parent IS SELECT ∗

FROM PERSONNE ; p parent%rowtype ;

CURSOR enfants ( numparent NUMBER ) IS SELECT ∗

FROM PERSONNE

WHERE pere = numparent OR mere = numparent ; e enfants%rowtype ;

BEGIN

FOR p IN parent LOOP

DBMS_OUTPUT . PUT_LINE ( ’ Les e n f a n t s de ’ | | p . prenom | |

’ ’ | | p . nom | | ’ s o n t : ’ ) ; FOR e IN enfants ( p . numpers ) LOOP

DBMS_OUTPUT . PUT_LINE ( ’ ∗ ’ | | e . prenom

| | ’ ’ | | e . nom ) ; END LOOP ;

END LOOP ; END;

/

(20)

1.8 Triggers

1.8.1 Principe

Un trigger est une proc´ edure stock´ ee qui se lance automatiquement lorsqu’un ´ ev´ enement se produit. Par ´ ev´ enement, on entend dans ce cours toute modification des donn´ ees se trouvant dans les tables. On s’en sert pour contrˆ oler ou appliquer des contraintes qu’il est impossible de formuler de fa¸ con d´ eclarative.

1.8.2 Classification

Type d’´ ev´ enement

Lors de la cr´ eation d’un trigger, il convient de pr´ eciser quel est le type d’´ ev´ enement qui le d´ eclenche. Nous r´ ealiserons dans ce cours des triggers pour les ´ ev´ enements suivants :

– INSERT – DELETE – UPDATE

Moment de l’´ execution

On pr´ ecise aussi si le trigger doit ˆ etre ´ execut´ e avant (BEFORE) ou apr` es (AFTER) l’´ ev´ enement.

Ev´ enements non atomiques

Lors que l’on fait un DELETE ..., il y a une seule instruction, mais plusieurs lignes sont affect´ ees. Le trigger doit-il ˆ etre ex´ ecut´ e pour chaque ligne affect´ ee (FOR EACH ROW), ou seulement une fois pour toute l’instruction (STATEMENT) ?

– un FOR EACH ROW TRIGGER est ex´ ecut´ e ` a chaque fois qu’une ligne est affect´ ee.

– un STATEMENT TRIGGER est ´ execut´ ee ` a chaque fois qu’une instruction est lanc´ ee.

1.8.3 Cr´ eation

Syntaxe

On d´ eclare un trigger avec l’instruction suivante : CREATE OR REPLACE TRIGGER nomtrigger

[ BEFORE | AFTER ] [INSERT | DELETE | UPDATE] ON nomtable [ FOR EACH ROW | ]

DECLARE

/∗ d e c l a r a t i o n s ∗/

BEGIN

/∗ i n s t r u c t i o n s ∗/

END;

Par exemple,

SQL> CREATE OR REPLACE TRIGGER pasDeDeleteDansClient 2 BEFORE DELETE ON CLIENT

3 BEGIN

4 RAISE_APPLICATION_ERROR ( −20555 , ’Va t e f a i r e . . . ’ ) ; 5 END;

6 /

D´ eclencheur cr´ e´ e . SQL> SELECT COUNT ( ∗ )

2 FROM CLIENT ; COUNT ( ∗ )

−−−−−−−−−−

21

SQL> DELETE FROM CLIENT ;

(21)

DELETE FROM CLIENT

ERREUR ` a la ligne 1 : ORA −20555: Va te faire . . .

ORA −06512: ` a ”SCOTT.PASDEDELETEDANSCLIENT” , ligne 2

ORA −04088: erreur lors d ex´ ecution du d´ eclencheur ’SCOTT.PASDEDELETEDANSCLIENT ’

SQL> SELECT COUNT ( ∗ ) 2 FROM CLIENT ; COUNT ( ∗ )

−−−−−−−−−−

21

L’instruction RAISE APPLICATION ERROR(code, message) l` eve une exception sans nom portant un code code et un message d’erreur message. Vous remarquez que comme l’erreur a ´ et´ e lev´ ee avant la suppression, les donn´ ees sont toujours pr´ esentes dans la table CLIENT. Le trigger a contrˆ ol´ e une r` egle, et comme elle n’´ etait pas respect´ ee, il a lanc´ e une erreur.

Combinaisons d’´ ev´ enements

Il est possible, en s´ eparant les types d’´ ev´ enement par le mot-cl´ e OR, de d´ efinir un trigger d´ eclench´ e par plusieurs

´ ev´ enements. Les variables bool´ eennes INSERTING, UPDATING et DELETING permettent d’identifier l’´ ev´ enement qui a d´ eclench´ e le trigger.

CREATE OR REPLACE TRIGGER afficheEvenement BEFORE INSERT OR UPDATE OR DELETE ON CLIENT FOR EACH ROW

BEGIN

IF INSERTING THEN

DBMS_OUTPUT . PUT_LINE ( ’ I n s e r t i o n dans CLIENT ’ ) ; ELSIF UPDATING THEN

DBMS_OUTPUT . PUT_LINE ( ’ Mise a j o u r dans CLIENT ’ ) ; ELSE

DBMS_OUTPUT . PUT_LINE ( ’ S u p p r e s s i o n dans CLIENT ’ ) ; END IF ;

END;

1.8.4 Acc` es aux lignes en cours de modification

Dans les FOR EACH ROW triggers, il est possible avant la modification de chaque ligne, de lire l’ancienne ligne et la nouvelle ligne par l’interm´ ediaire des deux variables structur´ ees :old et :new. Par exemple le trigger suivant empˆ eche de diminuer un salaire :

CREATE OR REPLACE TRIGGER pasDeBaisseDeSalaire BEFORE UPDATE ON EMP

FOR EACH ROW BEGIN

IF ( : old . sal > : new . sal ) THEN

RAISE_APPLICATION_ERROR ( −20567 ,

’ Pas de b a i s s e de s a l a i r e ! ’ ) ; END IF ;

END;

Tables en mutation

Il est impossible, dans un trigger de type FOR EACH ROW de faire un SELECT sur la table en cours de modification.

(22)

SQL> CREATE OR REPLACE TRIGGER beforeStatement 2 BEFORE UPDATE ON CLIENT

3 DECLARE 4 NB NUMBER;

5 BEGIN

6 SELECT COUNT ( ∗ ) INTO NB 7 FROM CLIENT ;

8 END;

9 /

D´ eclencheur cr´ e´ e . SQL>

SQL> CREATE OR REPLACE TRIGGER afterStatement 2 AFTER UPDATE ON CLIENT

3 DECLARE 4 NB NUMBER;

5 BEGIN

6 SELECT COUNT ( ∗ ) INTO NB 7 FROM CLIENT ;

8 END;

9 /

D´ eclencheur cr´ e´ e . SQL>

SQL> UPDATE CLIENT SET nomcli = nomcli ; 21 ligne ( s ) mise ( s ) ` a jour .

SQL>

SQL> CREATE OR REPLACE TRIGGER beforeForEachRow 2 BEFORE UPDATE ON CLIENT

3 FOR EACH ROW 4 DECLARE 5 NB NUMBER;

6 BEGIN

7 SELECT COUNT ( ∗ ) INTO NB 8 FROM CLIENT ;

9 END;

10 /

D´ eclencheur cr´ e´ e . SQL>

SQL> UPDATE CLIENT SET nomcli = nomcli ; UPDATE CLIENT SET nomcli = nomcli

ERREUR ` a la ligne 1 :

ORA −04091: la table SCOTT . CLIENT est en mutation ; le d´ eclencheur ou la fonction ne peut la voir

ORA −06512: ` a ”SCOTT.BEFOREFOREACHROW” , ligne 4

ORA −04088: erreur lors d ex´ ecution du d´ eclencheur ’SCOTT.BEFOREFOREACHROW’

SQL> DROP TRIGGER beforeForEachRow ;

D´ eclencheur supprim´ e .

(23)

SQL>

SQL>

SQL> CREATE OR REPLACE TRIGGER afterForEachRow 2 AFTER UPDATE ON CLIENT

3 FOR EACH ROW 4 DECLARE 5 NB NUMBER;

6 BEGIN

7 SELECT COUNT ( ∗ ) INTO NB 8 FROM CLIENT ;

9 END;

10 /

D´ eclencheur cr´ e´ e . SQL>

SQL> UPDATE CLIENT SET nomcli = nomcli ; UPDATE CLIENT SET nomcli = nomcli

ERREUR ` a la ligne 1 :

ORA −04091: la table SCOTT . CLIENT est en mutation ; le d´ eclencheur ou la fonction ne peut la voir

ORA −06512: ` a ”SCOTT.AFTERFOREACHROW” , ligne 4

ORA −04088: erreur lors d ex´ ecution du d´ eclencheur ’SCOTT.AFTERFOREACHROW’

1.8.5 Contourner le probl` eme des tables en mutation

Il existe plusieurs fa¸ cons de contourner ce probl` eme :

– Utiliser un STATEMENT trigger. Comme on ne sait pas quelles lignes ont ´ et´ e modifi´ ees, on est oblig´ e de toutes les traiter. Cette approche pr´ esente donc un inconv´ enient majeur : elle nous am` ene ` a effectuer de nombreux traitements inutiles.

– En ayant des donn´ ees redondantes. Il suffit que les donn´ ees servant ` a la v´ erification se trouvent dans une autre table que celle en mutation. Cette m´ ethode a pour inconv´ enient la m´ emoire occup´ ee et la quantit´ e de code ` a ´ ecrire pour maintenir la coh´ erence des donn´ ees. Dans la plupart des cas, cette solution est malgr´ e tout la meilleure.

Colonnes suppl´ ementaires

Par exemple, si l’on souhaite empˆ echer un client d’avoir plus de 10 comptes en banque, une solution est de placer dans la table client une colonne contenant le nombre de comptes.

ALTER TABLE CLIENT ADD nbComptes number ; UPDATE CLIENT SET nbComptes = 0 ;

Une fois cette table cr´ ee, il convient de s’assurer que les donn´ ees de la colonne nbComptes contient toujours les bonnes valeurs. On le fait avec plusieurs sous-programmes :

CREATE OR REPLACE TRIGGER metAJourNbComptes AFTER INSERT OR UPDATE OR DELETE ON COMPTECLIENT BEGIN

UPDATE CLIENT SET nbComptes = (

SELECT COUNT( ∗ ) FROM COMPTECLIENT CC WHERE CC . numCli = numCli

) ; END;

/

CREATE OR REPLACE TRIGGER verifieNbComptes

(24)

BEFORE INSERT ON COMPTECLIENT FOR EACH ROW

DECLARE

nbComptes NUMBER ; BEGIN

SELECT nbComptes INTO nbComptes FROM CLIENT

WHERE numCli = : new . numcli ; IF ( nbComptes >= 1 0 ) THEN

RAISE_APPLICATION_ERROR ( −20556 ,

’ Ce c l i e n t a d e j a t r o p de comptes ’ ) ; END IF ;

END;

/

On peut affiner en rempla¸ cant metAJourNbComptes par plusieurs sous-programmes : CREATE OR REPLACE TRIGGER initialiseNbComptes

BEFORE INSERT ON CLIENT FOR EACH ROW

BEGIN

: new . nbComptes := 0 ; END;

/

CREATE OR REPLACE TRIGGER metAJourNbComptes AFTER INSERT OR UPDATE OR DELETE ON COMPTECLIENT FOR EACH ROW

BEGIN

IF DELETING OR UPDATING THEN

UPDATE CLIENT SET nbComptes = nbComptes − 1 WHERE numcli = : old . numcli ;

END IF ;

IF INSERTING OR UPDATING THEN

UPDATE CLIENT SET nbComptes = nbComptes + 1 WHERE numcli = : new . numcli ;

END IF ; END;

/

Tables suppl´ ementaires

Si l’on souhaite par exemple empˆ echer les circuits dans la table PERSONNE, il est n´ ecessaire de faire un parcours de graphe. Ce qui n´ ecessite des SELECT dans la table en cours de mutation. La seule solution est dans ce cas d’avoir une table miroir qui contient les colonnes cl´ es primaire et ´ etrang` eres de cette table, et de s’en servir pour d´ etecter les circuits.

CREATE TABLE MIRRORPERSONNE (

numpers NUMBER PRIMARY KEY , pere NUMBER ,

mere NUMBER ) ;

Nous allons ensuite proc´ eder de mˆ eme, en r´ epercutant chaque op´ eration de PERSONNE sur MIRRORPERSONNE.

CREATE OR REPLACE TRIGGER miseAJourMirrorPersonne BEFORE UPDATE OR INSERT OR DELETE ON PERSONNE FOR EACH ROW

BEGIN

IF DELETING OR UPDATING THEN

(25)

DELETE FROM MIRRORPERSONNE WHERE numpers = : old . numpers ; END IF ;

IF INSERTING OR UPDATING THEN

INSERT INTO MIRRORPERSONNE VALUES ( : new . numpers , : new . pere , : new . mere ) ; END IF ;

END;

/

Une fois cela fait, il suffit de rechercher si une personne ins´ er´ ee est une descendante d’elle mˆ eme dans MIRRORPERSONNE.

CREATE OR REPLACE FUNCTION trouveCircuit ( current NUMBER , toFind NUMBER ) RETURN BOOLEAN IS

numPere NUMBER ; numMere NUMBER ; BEGIN

IF ( current IS NULL) THEN RETURN FALSE;

END IF ;

SELECT pere , mere INTO numPere , numMere FROM MIRRORPERSONNE

WHERE numPers = current ;

RETURN ( numPere = toFind OR numMere = toFind OR trouveCircuit ( numPere , toFind ) OR

trouveCircuit ( numMere , toFind ) ) ; END;

/

CREATE OR REPLACE TRIGGER verifieCircuit AFTER UPDATE OR INSERT ON PERSONNE

FOR EACH ROW BEGIN

IF ( trouveCircuit ( : new . numPers , : new . numPers ) ) THEN RAISE_APPLICATION_ERROR ( −20557 ,

’ C i r c u i t dans l ’ ’ a r b r e g ´ e n ´ e a l o g i q u e . ’ ) ; END IF ;

END;

/

(26)

1.9 Packages

1.9.1 Principe

Un package est un ensemble de sous-programmes et de variables form´ e par – Une sp´ ecification : d´ eclaration de variables et de sous-programmes – Un corps : impl´ ementation des sous-programmes

Tout ce qui se trouve dans la sp´ ecification doit se trouver dans le corps, mais la r´ eciproque est fausse. Un package satisfait les points suivants :

– encapsulation : certains traitements sont masqu´ es, seule la sp´ ecification du package est visible. Cela a pour avantage de simplifier la tˆ ache de celui qui va utiliser le package.

– modularit´ e : il est possible de d´ evelopper s´ epar´ ement les diverses parties de l’application. le d´ eveloppement devient ainsi un assemblage de package.

Ces deux aspects fournissent une souplesse certaine au niveau du d´ eveloppement : il est possible de modifier le corps d’un package sans changer sa sp´ ecification, donc sans modifier le fonctionnement de l’application.

1.9.2 Sp´ ecification

La syntaxe permettant de cr´ eer l’entˆ ete est la suivante : CREATE OR REPLACE PACKAGE nompackage IS

/∗

d e c l a r a t i o n s

∗/

END nomPackage ; /

Par exemple,

CREATE OR REPLACE PACKAGE compteur IS procedure reset ;

function nextValue return number ; END compteur ;

/

1.9.3 Corps

La syntaxe permettant de cr´ eer le corps est la suivante : CREATE OR REPLACE PACKAGE BODY nompackage IS

/∗

i m p l e m e n t a t i o n

∗/

END nomPackage ; /

Par exemple,

CREATE OR REPLACE PACKAGE BODY compteur IS cpt NUMBER := 0 ;

PROCEDURE reset IS BEGIN

cpt := 0 ; END;

FUNCTION nextValue RETURN NUMBER IS BEGIN

cpt := cpt + 1 ; RETURN cpt − 1 ; END;

END compteur ;

(27)

/

On peut utiliser un package depuis n’importe quel script PL/SQL : DECLARE

nb NUMBER;

BEGIN

FOR nb IN 4 . . 2 0 LOOP

DBMS_OUTPUT . PUT_LINE ( COMPTEUR . nextValue ( ) ) ; END LOOP ;

COMPTEUR . RESET ( ) ;

FOR nb IN REVERSE 0 . . 1 0 LOOP

DBMS_OUTPUT . PUT_LINE ( COMPTEUR . nextValue ( ) ) ; END LOOP ;

END;

/

(28)

Chapitre 2

Exercices

2.1 Introduction au PL/SQL

Exercice 1

Ecrivez un programme affectant les valeurs 1 et 2 ` a deux variables a et b, puis permutant les valeurs de ces deux variables.

Exercice 2

Ecrivez un programme pla¸ cant la valeur 10 dans une variable a, puis affichant la factorielle de a.

Exercice 3

Ecrivez un programme pla¸ cant les valeurs 48 et 84 dans deux variables a et b puis affichant le pgcd de a et b.

(29)

2.2 Tableaux et Structures

Exercice 1

1. Cr´ eez un type tableau pouvant contenir jusqu’` a 50 entiers.

2. Cr´ eez une variable de ce type , faites une allocation dynamique et dimensionnez ce tableau ` a 20 emplacements.

3. Placez dans ce tableau la liste des 20 premiers carr´ es parfaits : 1, 4, 9, 16, 25, . . . 4. Inversez l’ordre des ´ el´ ements du tableau

5. Affichez le tableau.

Exercice 2

Triez le tableau pr´ ec´ edent avec la m´ ethode du tri ` a bulle.

Exercice 3

Recherchez, par dichotomie, si l’´ el´ ement 225 se trouve dans le tableau.

Exercice 4

On impl´ emente des listes chaˆın´ ees avec des tableaux de la sorte, SET SERVEROUTPUT ON

DECLARE

-- Maillon d’une liste cha^ ın´ ee TYPE CELL IS RECORD

(

-- Donn´ ee de chaque maillon data INTEGER,

-- Indice du maillon pr´ ec´ edent de la liste, -- -1 s’il n’y en a pas previous INTEGER,

-- Indice du maillon suivant de la liste, -- -1 s’il n’y en a pas next INTEGER

);

-- Type tableau contenant les maillons de la liste TYPE TREE IS VARRAY (19) OF CELL;

-- Tableau contenant les maillons de la liste t TREE;

-- indice du premier ´ el´ ement de la liste first integer;

-- indice du dernier ´ el´ ement de la liste last integer;

BEGIN

t := TREE();

t.extend(19);

-- Initialisation FOR i IN 1..19 LOOP

t(i).data := power(i, 5) mod 19 ; t(i).previous := i-1;

t(i).next := i+1;

END LOOP;

first := 1;

last := 19;

t(first).previous := -1;

t(last).next := -1;

(30)

-- Affichage DECLARE

p integer := first;

BEGIN

WHILE p <> -1 LOOP

DBMS_OUTPUT.PUT_LINE(’(’ || p || ’, ’ ||

t(p).data || ’, ’ ||

t(p).previous || ’, ’ || t(p).next || ’)’);

p := t(p).next;

END LOOP;

END;

/* Ecrivez la suite vous-m^ eme... */

END;

/

Inversez l’ordre des ´ el´ ements de la liste, sans changer les indices des maillons (seulement en modifiant le chaˆınage).

Exercice 5

Utilisez le tri ` a bulle pour remettre les ´ el´ ements dans l’ordre. Les indications sont les mˆ emes : ne d´ eplacez pas les

maillons, vous n’avez le droit de toucher qu’au chaˆınage. Bon courage, l’aspirine n’est pas fournie.

(31)

2.3 Utilisation PL/SQL

Nous travaillerons sur les donn´ ees A.6 et A.5.

Vous n’oublierez pas de placer des commit en des lieux bien choisis.

Exercice 1

Vous remarquerez que les valeurs des numpers de la table PERSONNE forment une s´ equence de nombres de 1 ` a 21.

Utilisez une boucle dans laquelle vous placerez une requˆ ete pour recopier les couples nom/pr´ enom de la table personne dans la table CLIENT.

Exercice 2

Ecrivez un script r´ ecup´ erant le client de cl´ e primaire la plus ´ elev´ ee, et injectant ce client dans la table PERSONNEL.

Exercice 3

Ouvrez un compte courant pour chaque personne, effectuez un d´ epˆ ot en esp` ece ´ egal ` a numpers ∗ 100 euros.

Exercice 4

Ouvrez un livret pour chaque personne ayant un numpers pair, faites un virement de leur compte courant vers ce

livret de sorte qu’il ne reste plus que 500 sur leur compte.

(32)

2.4 Exceptions

Nous utiliserons les donn´ ees de A.7 et A.5

Vous ˆ etes invit´ es ` a modifier le code de la s´ eance pr´ ec´ edente. Chaque fois qu’un SELECT ... INTO ... sera effectu´ e, vous rattraperez les exceptions NO DATA FOUND et TOO MANY ROWS. A chaque insertion, vous ratrapperez l’exception DUP VAL ON INDEX.

Exercice 1

Faites de sorte que les scripts important les donn´ ees des tables CLIENT ne puissent ˆ etre ex´ ecut´ es qu’une seule fois.

Exercice 2

Les scripts remplissant la table Operation ne fonctionneront pas aujourd’hui... Mˆ eme s’il fonctionnaient la derni` ere

fois. Trouvez les codes d’erreurs des exceptions lev´ ees par ces scripts, rattrapez-les de la fa¸ con la plus appropri´ ee qui

soit.

(33)

2.5 Sous-programmes

Exercice 1

Ecrire une fonction r´ ecursive retournant b

n

, avec n entier positif ou nul.

Exercice 2

Am´ eliorer la fonction pr´ ec´ edente en utilisant le fait que b

n

= (b

2

)

n2

si n est pair.

Pour les questions suivantes, utilisez les donn´ ees de A.5.

Exercice 3

Ecrire une fonction demi-freres prenant deux num´ eros de personnes en param` etre et retournant vrai si et seulement si ces deux personnes ont un parent en commun.

Exercice 4

Ecrire une fonction cousins germains prenant deux num´ eros de personnes en param` etre et retournant vrai si et seulement si ces deux deux individus sont cousins germains.

Exercice 5

Ecrire une proc´ edure r´ ecursive affichant le nom de la personne dont le num´ ero est pass´ e en param` etre et se rappellant r´ ecursivement sur le p` ere de cette personne. Faites de sorte ` a ne pas utiliser d’exceptions.

Exercice 6

Ecrire une proc´ edure r´ ecursive affichant les noms des ascendants de sexe masculin de la personne dont le num´ ero est pass´ e en param` etre.

Exercice 7

Ecrire une fonction r´ ecursive prenant deux num´ eros de personne A et B et retournant vrai si A est un ascendant de B.

Exercice 8

Ecrire une fonction prenant en param` etre deux num´ eros de personne A et B et retournant, si l’un est un ascendant de l’autre, le nombre de g´ en´ erations les s´ eparant, −1 si l’un n’est pas un ascendant de l’autre.

Exercice 9

Pr´ eparez un verre d’aspirine et ´ ecrivez une requˆ ete retournant le(s) couples(s) personnes s´ epar´ ees par le plus de g´ en´ erations.

Exercice 10

Reprendre le code du tp pr´ ec´ edent, le d´ ecouper en sous-programmes de la fa¸ con la moins inintelligente possible.

Bon courage.

(34)

2.6 Curseurs

Exercice 1

Refaites les exercices de 2.3 en utilisant les curseurs.

Exercice 2

En utlisant les donnees A.5, ecrivez une fonction affichant toute la descendance d’une personne.

(35)

2.7 Curseurs parametr´ es

L’int´ erˆ et de ces exercices ´ etant de vous familiariser avec les curseurs param´ etr´ es, vous ferez en sorte de ne pas contourner leur usage. Nous utiliserons les donn´ ees de A.6

Exercice 1

Ecrire une proc´ edure qui affiche tous les clients, et pour chaque client, la liste des comptes.

Exercice 2

Ecrire une proc´ edure qui affiche tous les clients, et pour chaque client, la liste des comptes, et pour chacun de ces

comptes, l’historique des op´ erations.

(36)

2.8 Triggers

Impl´ ementez les contraintes suivantes dans les donn´ ees de les donn´ ees de A.8. Vous ferez des sous-programmes tenant sur une page, et ne contenant pas plus de trois niveaux d’imbrication. Vous r´ epertorierez les num´ eros d’erreurs que vous affecterez ` a chaque lev´ ee d’exception.

1. Il ne doit pas ˆ etre possible de modifier la note min dans la table prerequis.

2. Dans un module, il ne doit pas y avoir plus de effecMax ´ el` eves inscrits.

3. On ne peut cr´ eer un examen pour un module que s’il y a des ´ el` eves inscrits dans ce module.

4. Un ´ el` eve ne peut passer un examen que si sa date d’inscription est ant´ erieure ` a la date de l’examen.

5. Il ne doit pas y avoir de circuit dans la table prerequis (il existe une fa¸ con de la v´ erifier en PL/SQL, mais comme vous ne la connaissez pas, faites un parcours en profondeur du graphe des pr´ e-requis)

6. Un ´ el` eve s’inscrivant ` a un module doit avoir eu au moins la note min ` a tous les modules pr´ e-requis.

7. Ajouter dans ´ etudiant un champ moyenne, celui-ci contiendra la moyenne de chaque ´ etudiant s’il a pass´ e les examens de tous les modules dans lesquels il est inscrit.

8. Revenez sur la premi` ere contrainte : il ne doit ˆ etre possible de modifier une note min dans la table prerequis que s’il n’existe pas d’´ el` eve dont une inscription serait invalid´ ee.

9. Il ne doit ˆ etre possible de modifier effecMax que si des ´ etudiants ne se retrouvent pas avec une inscription invalid´ ee.

Libre ` a vous par la suite de trouver d’autres contraintes et de les impl´ ementer.

(37)

2.9 Packages

Exercice 1

Lancez deux sessions simultan´ ement sur le mˆ eme serveur et invoquez les sous-programmes du package compteur depuis chacune des sessions. Que remarquez-vous ?

Exercice 2

Impl´ ementer le corps du package suivant (utilisez les donn´ ees de A.5).

CREATE OR R E P L A C E P A C K A G E g e s t i o n _ a r b r e I S c i r c u i t exception;

c u r s o r f e u i l l e s r e t u r n p e r s o n n e%r o w t y p e; p r o c e d u r e a j o u t e P e r s o n n e(n o m p e r s o n n e.n o m%t y p e,

p r e n o m p e r s o n n e.p r e n o m%t y p e, p e r e p e r s o n n e.p e r e%t y p e, m e r e p e r s o n n e.m e r e%t y p e) ;

p r o c e d u r e m o d i f i e P a r e n t s(p e r s p e r s o n n e.n u m p e r s%t y p e,

n u m P e r e p e r s o n n e.p e r e%t y p e, n u m M e r e p e r s o n n e.m e r e%t y p e) ;

END g e s t i o n _ a r b r e; /

(38)

2.10 R´ evisions

Impl´ ementez les contraintes suivantes dans les donn´ ees de A.9.

1. Les parents d’une mˆ eme personne sont des personnes diff´ erentes.

2. L’arbre g´ en´ ealogique ne contient pas de circuit.

3. Les dates de divorce sont ult´ erieures aux dates de mariage.

4. Une mˆ eme personne ne peut pas ˆ etre mari´ ee ` a plusieurs personnes simultan´ ement.

5. Personne ne peut ˆ etre p` ere d’une personne et m` ere d’une autre.

6. Un mari ne peut pas ˆ etre m` ere et une femme ne peut pas ˆ etre p` ere.

7. Deux personnes ayant du sang en commun ne peuvent se marier.

(39)

Chapitre 3

Corrig´ es

3.1 Introduction au PL/SQL

−− E x e r c i c e 1 D E C L A R E

aNUMBER;

bNUMBER;

tNUMBER;

B E G I N

a := 1 ; b := 2 ;

D B M S _ O U T P U T.P U T _ L I N E(’ a = ’| |a) ; D B M S _ O U T P U T.P U T _ L I N E(’ b = ’| |b) ;

D B M S _ O U T P U T.P U T _ L I N E(’ L e t ’ ’ s swap a and b . . . The r e s u l t i s : ’) ; t := a;

a := b; b := t;

D B M S _ O U T P U T.P U T _ L I N E(’ a = ’| |a) ; D B M S _ O U T P U T.P U T _ L I N E(’ b = ’| |b) ; END;

/

−− E x e r c i c e 2 D E C L A R E

aNUMBER;

r e s NUMBER;

c o u n t e r NUMBER;

B E G I N

a := 1 0 ; r e s := 1 ; c o u n t e r := a;

W H I L E c o u n t e r > 0 L O O P r e s := r e s ∗ c o u n t e r; c o u n t e r := c o u n t e r − 1 ; END L O O P;

D B M S _ O U T P U T.P U T _ L I N E(a | | ’ != ’| |r e s) ; END;

/

−− E x e r c i c e 3 D E C L A R E

aNUMBER:= 4 8 ; bNUMBER:= 8 4 ; a m o d b NUMBER;

B E G I N

D B M S _ O U T P U T.P U T(’PGCD( ’| |a| |’ , ’| |b| |’ ) = ’) ; W H I L E b > 0 L O O P

a m o d b := a;

W H I L E a m o d b >= b L O O P a m o d b := a m o d b − b; END L O O P;

a := b; b := a m o d b; END L O O P;

D B M S _ O U T P U T.P U T _ L I N E(a) ; END;

/

(40)

3.2 Tableaux et Structures

SET S E R V E R O U T P U T ON

−− T a b l e a u x D E C L A R E

T Y P E m o n t a b I S V A R R A Y ( 5 0 ) O F INTEGER ; t m o n t a b;

B E G I N

t := m o n t a b( ) ; t.e x t e n d( 2 0 ) ;

−− I n i t i a l i s a t i o n F O R i IN 1 . . 2 0 L O O P

t(i) := i∗i; END L O O P;

−− I n v e r s i o n de l ’ o r d r e d e s ´e l´e m e n t s D E C L A R E

t e m p i n t e g e r ; B E G I N

F O R i IN 1 . . 1 0 L O O P t e m p := t(i) ; t(i) := t(20−i+ 1 ) ; t(20−i+1) := t e m p; END L O O P;

END;

−− A f f i c h a g e F O R i IN 1 . . 2 0 L O O P

D B M S _ O U T P U T.P U T _ L I N E(’ t ( ’ | | i | | ’ ) = ’ | | t(i) ) ; END L O O P;

−− Tri `a b u l l e D E C L A R E

t e m p i n t e g e r ; B E G I N

F O R i IN R E V E R S E 2 . . 2 0 L O O P F O R j IN 2 . .i L O O P

I F t(j − 1 ) > t(j) THEN t e m p := t(j) ; t(j) := t(j−1 ) ; t(j−1) := t e m p; END I F;

END L O O P; END L O O P;

END;

−− A f f i c h a g e F O R i IN 1 . . 2 0 L O O P

D B M S _ O U T P U T.P U T _ L I N E(’ t ( ’ | | i | | ’ ) = ’ | | t(i) ) ; END L O O P;

−− Recherche par d i c h o t o m i e de l ’ ´e l´e m e n t 225 D E C L A R E

i n f INTEGER := 1 ;

s u p INTEGER := 2 0 ;

m INTEGER ; X INTEGER := 4 0 0 ; B E G I N

L O O P

D B M S _ O U T P U T.P U T _ L I N E(’ i n f = ’ | | i n f | |

’ ; sup = ’ | | s u p) ; m := (i n f + s u p) / 2 ;

E X I TWHEN

t(m) = X OR i n f = s u p; I F t(m) > XTHEN

s u p := m−1;

ELSE

i n f := m+1;

END I F; END L O O P;

I F t(m) = X THEN

D B M S _ O U T P U T.P U T _ L I N E(X | |

’ e s t dans l e t a b l e a u ’) ; ELSE

D B M S _ O U T P U T.P U T _ L I N E(X | |

’ n” e s t p a s dans l e t a b l e a u ’) ; END I F;

END;

END;

/

(41)

−− S t r u c t u r e s D E C L A R E

−− M a i l l o n d ’ une l i s t e c h aˆı n´e e T Y P E C E L L I S R E C O R D

(

−− Donn´ee de c h a q u e m a i l l o n d a t a INTEGER,

−− I n d i c e du m a i l l o n p r ´e c ´e d e n t de l a l i s t e ,

−− −1 s ’ i l n ’ y en a p a s p r e v i o u s INTEGER,

−− I n d i c e du m a i l l o n s u i v a n t de l a l i s t e ,

−− −1 s ’ i l n ’ y en a p a s

next INTEGER

) ;

−− Type t a b l e a u c o n t e n a n t l e s m a i l l o n s de l a l i s t e T Y P E T R E E I S V A R R A Y ( 1 9 ) O F C E L L;

−− Ta bl ea u c o n t e n a n t l e s m a i l l o n s de l a l i s t e t T R E E;

−− i n d i c e du p r e m i e r ´e l´e m e n t de l a l i s t e f i r s t i n t e g e r ;

−− i n d i c e du d e r n i e r ´e l´e m e n t de l a l i s t e l a s t i n t e g e r ;

B E G I N

t := T R E E( ) ; t.e x t e n d( 1 9 ) ;

−− I n i t i a l i s a t i o n F O R i IN 1 . . 1 9 L O O P

t(i) .d a t a := p o w e r(i, 5 ) m o d 19 ; t(i) .p r e v i o u s := i−1;

t(i) .next := i+1;

END L O O P; f i r s t := 1 ; l a s t := 1 9 ;

t(f i r s t) .p r e v i o u s := −1;

t(l a s t) .next := −1;

−− A f f i c h a g e D E C L A R E

p i n t e g e r := f i r s t; B E G I N

W H I L E p <>−1 L O O P

D B M S _ O U T P U T.P U T _ L I N E(’ ( ’ | | p | | ’ , ’ | | t(p) .d a t a | | ’ , ’ | |

t(p) .p r e v i o u s | | ’ , ’ | | t(p) .next | | ’ ) ’) ; p := t(p) .next;

END L O O P; END;

−− I n v e r s i o n de l ’ o r d r e d e s ´e l´e m e n t s D E C L A R E

t e m p INTEGER ; B E G I N

F O R i IN 1 . . 1 9 L O O P

t e m p := t(i) .p r e v i o u s; t(i) .p r e v i o u s := t(i) .next; t(i) .next := t e m p;

END L O O P; f i r s t := 1 9 ; l a s t := 1 ; END;

−− A f f i c h a g e D E C L A R E

p i n t e g e r := f i r s t; B E G I N

W H I L E p <>−1 L O O P

D B M S _ O U T P U T.P U T _ L I N E(’ ( ’ | | p | | ’ , ’ | |

t(p) .d a t a | | ’ , ’ | | t(p) .p r e v i o u s | | ’ , ’ | | t(p) .next | | ’ ) ’) ; p := t(p) .next;

END L O O P; END;

−− Tri `a b u l l e D E C L A R E

i i n t e g e r := l a s t; j i n t e g e r ; B E G I N

W H I L E t(t(i) .p r e v i o u s) .p r e v i o u s <> −1 L O O P j := f i r s t;

W H I L E i<>j L O O P

I F(t(j) .d a t a > t(t(j) .next) .d a t a)THEN

(42)

−− Echange de j e t t ( j ) . n e x t

−− par m o d i f i c a t i o n du c h aˆı n a g e D E C L A R E

a f t e r J INTEGER := t(j) .next; b e f o r e J INTEGER := t(j) .p r e v i o u s; B E G I N

t(j) .next := t(a f t e r J) .next; t(a f t e r J) .next := j;

t(a f t e r J) .p r e v i o u s := b e f o r e J; t(j) .p r e v i o u s := a f t e r J;

I F t(j) .next<> −1THEN

t(t(j) .next) .p r e v i o u s := j; ELSE

l a s t := j; END I F;

I F t(a f t e r J) .p r e v i o u s <> −1THEN

t(t(a f t e r J) .p r e v i o u s) .next := a f t e r J; ELSE

f i r s t := a f t e r J; END I F;

I F a f t e r J = i THEN i := j; END I F;

END;

ELSE

j := t(j) .next; END I F;

END L O O P;

i := t(i) .p r e v i o u s; END L O O P;

END;

−− A f f i c h a g e D E C L A R E

p i n t e g e r := f i r s t; B E G I N

W H I L E p <>−1 L O O P

D B M S _ O U T P U T.P U T _ L I N E(’ ( ’ | | p | | ’ , ’ | | t(p) .d a t a | | ’ , ’ | |

t(p) .p r e v i o u s | | ’ , ’ | | t(p) .next | | ’ ) ’) ; p := t(p) .next;

END L O O P; END;

END;

/

(43)

3.3 Application du PL/SQL et Exceptions

SET S E R V E R O U T P U T ON SET A U T O C O M M I T O F F

−− E x e r c i c e 1 D E C L A R E

u n C l i e n t P E R S O N N E%R O W T Y P E; n u m C l i e n t P E R S O N N E.n u m p e r s%t y p e; Y _ A _ E U _ U N E _ M E R D E EXCEPTION;

B E G I N

F O R n u m C l i e n t IN 1 . . 2 1 L O O P B E G I N

SELECT ∗ INTO u n C l i e n t FROM P E R S O N N E

WHERE n u m p e r s = n u m C l i e n t;

INSERT INTO C L I E N T (n u m c l i, n o m c l i, p r e n o m c l i) VALUES

(u n C l i e n t.n u m p e r s, u n C l i e n t.n o m, u n C l i e n t.p r e n o m) ; EXCEPTION

WHEN N O _ D A T A _ F O U N D THEN D B M S _ O U T P U T.P U T _ L I N E(

’ Personne n”a l ” i d e n t i f i a n t ’ | | n u m C l i e n t) ;

WHEN T O O _ M A N Y _ R O W S THEN D B M S _ O U T P U T.P U T _ L I N E(

’ C e t t e message ne d e v r a i t j a m a i s a p p a r aˆı t r e ! ’) ; WHEN D U P _ V A L _ O N _ I N D E X THEN

D B M S _ O U T P U T.P U T _ L I N E(

’ C o n t r a i n t e de c l ´e v i o l ´e e ! Message SQL : ’ | | S Q L E R R M) ;

WHENO T H E R S THEN

R A I S E Y _ A _ E U _ U N E _ M E R D E; END;

END L O O P; COMMIT;

EXCEPTION

WHENY _ A _ E U _ U N E _ M E R D E THEN

D B M S _ O U T P U T.P U T _ L I N E(’SQLCODE = ’ | | S Q L C O D E) ; D B M S _ O U T P U T.P U T _ L I N E(’ I l y a eu une Merde ! ’) ; ROLLBACK;

END;

/

−− E x e r c i c e 2 D E C L A R E

u n C l i e n t C L I E N T%r o w t y p e; B E G I N

SELECT ∗ INTO u n C l i e n t FROM C L I E N T WHERE n u m C l i =

(

SELECT MAX(n u m c l i) FROMC L I E N T

) ;

INSERT INTO P E R S O N N E L VALUES (

1 ,

u n C l i e n t.n o m c l i, u n C l i e n t.p r e n o m c l i, NULL,

1 2 5 4 . 2 8 ) ; COMMIT;

EXCEPTION

WHENN O _ D A T A _ F O U N D THEN

D B M S _ O U T P U T.P U T _ L I N E(’ Aucun c l i e n t ’) ; WHEND U P _ V A L _ O N _ I N D E X THEN

D B M S _ O U T P U T.P U T _ L I N E(

’ I l y a un g r o s p r o b l`e m e . . . J” comprends p a s c ” q u i s ” p a s s e ’) ; END;

/

−− E x e r c i c e 3

D E C L A R E

n u m C l i e n t C L I E N T.n u m c l i%T Y P E; t C C L T Y P E C C L.n u m t y p e c c l%T Y P E; n t o T Y P E O P E R A T I O N.n u m t y p e o p e r%T Y P E; Y _ A _ U N _ G R O _ B L E M E EXCEPTION;

B E G I N

SELECT n u m t y p e o p e r INTO n t o

Références

Documents relatifs

◮ Retrouver les d ´epartements qui sont impliqu ´es dans le d ´eveloppement du jeu en r ´eseau peut se faire dans une sous-requ ˆete, dont le r ´esultat peut ˆetre utilis ´e dans

◮ On peut enchaˆıner une s ´election avec une insertion, pour remplir une table avec les r ´esultats d’une requ ˆete SELECT :.. INSERT INTO R(a1, a2...)

Almost every best practice offered in this book includes a code example, both in the text and in downloadable form from the Oracle PL/SQL Best Practices site, available through

3- Ne cessant d’améliorer notre commande, nous avons constaté qu’un phénomène d’oscillation de l’eau autour d’un niveau provoque de nombreux démarrage et arrêt

Bref, ce document refléterait bien la « réalité » sociale de l’époque et, même si, le professeur prend soin de dire que « c’est une caricature », il n’est pas sûr que

Ce scénario décrit les processus qui surviennent lors des interventions de maintenance précédant généralement un avis de panne pour un objet technique (vous avez également

On décompose le volume du liquide en rotation en couronnes cylindriques de rayon r, d’épaisseur dr et de hauteur z(r). Exprimer le volume dV d’une telle couronne. En supposant que

Elle est d’autant plus importante que la masse de la charge est grande et s’oppose à la mise en mouvement. Elle est caractérisée par le moment d’inertie J, qui s’exprime en