Sunteți pe pagina 1din 134

Cours Oracle

Alexandre Meslé

4 octobre 2008
Table des matières

1 Notes de cours 4
1.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.1.1 Qu’est-ce qu’un SGBD ? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.1.2 Organisation relationnelle des données . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.1.3 Survol de SQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.1.4 SQL+ et iSQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.2 Contraintes déclaratives . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
1.2.1 Valeurs par défaut . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
1.2.2 Champs non renseignés . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
1.2.3 Clé primaire . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
1.2.4 Clé étrangère . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
1.2.5 Syntaxe alternative . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
1.3 Requêtes mono-tabulaires . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
1.3.1 Compléments sur SELECT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
1.3.2 Instruction WHERE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
1.3.3 Conditions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
1.3.4 Suppression . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
1.3.5 Mise à jour . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
1.4 Requêtes multi-tabulaires . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
1.4.1 Principe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
1.4.2 Produit cartésien . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
1.4.3 Jointure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
1.4.4 Jointures refléxives . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
1.5 Agrégation de données . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
1.5.1 Fonctions d’agrégation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
1.5.2 Groupage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
1.6 Vues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
1.6.1 Définition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
1.6.2 Syntaxe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
1.6.3 Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
1.6.4 Suppression . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
1.7 Requêtes imbriquées . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
1.7.1 Sous requêtes renvoyant une valeur scalaire . . . . . . . . . . . . . . . . . . . . . . 23
1.7.2 Sous requêtes renvoyant une colonne . . . . . . . . . . . . . . . . . . . . . . . . . . 25
1.7.3 Sous requêtes non correlées renvoyant une table . . . . . . . . . . . . . . . . . . . . 25
1.7.4 Sous requêtes correlées . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
1.8 Compléments sur les types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
1.8.1 Types numériques . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
1.8.2 Types chaine de caractères . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
1.8.3 Types date . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
1.8.4 La fonction inclassable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
1.8.5 Contraintes CHECK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
1.9 Noyau impératif du PL/SQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33

1
1.9.1 PL/SQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
1.9.2 Blocs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
1.9.3 Affichage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
1.9.4 Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
1.9.5 Traitements conditionnels . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
1.9.6 Traitements répétitifs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
1.10 Tableaux et structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
1.10.1 Tableaux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
1.10.2 Structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
1.11 Applications du PL/SQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
1.11.1 Affectation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
1.11.2 Tables et structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
1.11.3 Transactions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
1.12 Exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
1.12.1 Rattraper une exception . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
1.12.2 Exceptions prédéfinies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
1.12.3 Codes d’erreur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
1.12.4 Déclarer et lancer ses propres exceptions . . . . . . . . . . . . . . . . . . . . . . . . 42
1.13 Sous-programmes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
1.13.1 Procédures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
1.13.2 Fonctions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
1.14 Curseurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
1.14.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
1.14.2 Les curseurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
1.15 Curseurs parametrés . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
1.15.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
1.15.2 Définition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
1.15.3 Déclaration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
1.15.4 Ouverture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
1.15.5 Lecture d’une ligne, fermeture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
1.15.6 Boucle pour . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
1.15.7 Exemple récapitulatif . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
1.16 Triggers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
1.16.1 Principe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
1.16.2 Classification . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
1.16.3 Création . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50

2 Exercices 54
2.1 Contraintes déclaratives . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
2.2 Requêtes monotabulaires . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
2.3 Requêtes multitabulaires . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
2.4 Agrégation de données . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
2.5 Vues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
2.6 Requêtes imbriquées . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
2.7 Compléments sur les types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
2.8 Révisions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
2.9 Examen Type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
2.10 Introduction au PL/SQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
2.11 Tableaux et Structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
2.12 Applications du PL/SQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
2.13 Exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
2.14 Sous-programmes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
2.15 Curseurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
2.16 Curseurs parametrés . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
2.17 Triggers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87

2
3 Corrigés 90
3.1 Contraintes déclaratives . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
3.2 Requêtes monotabulaires . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
3.3 Requêtes multitabulaires . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
3.4 Agrégation de données . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
3.5 Vues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
3.6 Requêtes imbriquées . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
3.7 Compléments sur les types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
3.8 Révisions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
3.9 Examen Type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
3.10 Introduction au PL/SQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
3.11 Tableaux et Structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
3.12 Application du PL/SQL et Exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
3.13 Sous-programmes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
3.14 Curseurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120
3.15 Curseurs paramétrés . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123
3.16 Triggers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124

3
Chapitre 1

Notes de cours

1.1 Introduction
1.1.1 Qu’est-ce qu’un SGBD ?
– Définition : logiciel qui stocke des données de façon organisée et cohérente.
– Access : version édulcorée. Mais mono-utilisateur, et faible capacité.
– Les données sont stockées dans des fichiers gérés par le serveur de base de données. Cette opération
est opaque. On transmet depuis un client des instructions à la base par l’intermédiaire du langage
SQL.
Avantages :
– permet de maintenir de façon fiable l’intégrité des données
– opérations de bas niveau opaques
– rapide
– multi-utilisateurs
– moins de trafic sur le réseau
– sécurité
Inconvénient :
– Un peu plus long que bien programmé en C, et encore...
Plusieurs façons d’organiser les données :
– hiérarchique
– relationnel
– déductif
– objet
– etc.
Les gros SGBD-R :
– DB2 (IBM)
– Oracle
– Microsoft SQL Server
– mySQL

SQL
Structured Query Language. SQL est le langage standard de la base de données. D’un SGBD à l’autre,
le SQL change très peu. Ce cours est surtout un cours de SQL.

1.1.2 Organisation relationnelle des données


– Les donnés sont stockées dans des tables.

4
– Table : tableau à deux entrées.
Le MPD nous donne, pour chaque table, les colonnes (i.e. champs) que doit comporter la table.
nomtable ( c o l o n n e 1 , c o l o n n e 2 , . . . , c o l o n n e n )

Par exemple :
CLIENT( numero , prenom , nom , e m a i l )

nous donnera la table

numéro nom prénom email


20505372 Alexandre Meslé alexandre.mesle@gmail.com
... ... ... ...
Supposons que l’on veuille gérer des commandes émises par des clients. Nous souhaitons stocker les
données suivantes :
– nom, prénom et adresse complète des clients
– produits proposés et coûts unitaires
– pour chaque commande, le détail et le montant.
Après maintes péripéties, nous en arrivons au MPD suivant :
CLIENT( n u m e r o c l i e n t , prenom , nom , a d r e s s e 1 , a d r e s s e 2 , #CP)
CODE POSTAL(CP, v i l l e )
PRODUIT( numero produit , d e s c r i p t i o n , prix unitaire )
COMMANDE(# n u m e r o c l i e n t , numero commande )
LIGNECOMMANDE(# n u m e r o c l i e n t , #numero commande , #numero produit , q u a n t i t e )

Nous pouvons représenter la base, avec quelques données insérées, par des tableaux

numero client prenom nom adresse1 adresse2 #CP


1 Alexandre Meslé Cité les framboises 28, rue du chemin vert 75013
2 Amédée Morflegroin 29, rue de Choisy 95200
3 Médor dans sa niche 75013
4 Louis-Hubert Martin 112, rue de la Pompe 75016
CP ville
75013 Paris
75016 Paris
95200 Sarcelles
numero produit decription prix unitaire
1 Boite de cornichons 2.5
2 Goupillon 6.5
3 Cotons-tige 1.2
4 Ajax WC 1.2
5 Place concert des Stones 145
6 Roue de secours 75
7 Compas 4
8 Armoire Glüdehnblourf 146
9 Paté diététique 12
10 Croquettes laxatives 8
#numero client numero commande
1 1
1 2
2 1
3 1

5
#numero client #numero commande #numero produit quantite
1 1 5 2
1 2 4 29
1 2 7 1
2 1 1 4
3 1 9 238

1.1.3 Survol de SQL


Le SQL de base se décline en quatre parties :
– DDL : Data definition language
– DML : Data manipulation language
– DQL : Data query language
– DCL : Data control language
A cela s’ajoute le PL/SQL. Celui-ci permet de gérer presque toutes les contraintes et de maintenir la
cohérence de la base de données. Mais c’est beaucoup plus compliqué...

Créer des tables


Les types pour commencer
– numériques : number
– chaı̂nes de caractères : varchar2(taille)
syntaxe :
CREATE TABLE <nomdelatable >
(< d e s c r i p t i o n c o l o n n e 1 >, . . . , <d e s c r i p t i o n c o l o n n e n >)
Pour chaque colonne :
<nomcolonne> <type> [< o p t i o n s e v e n t u e l l e s >]
exemple :
create table c l i e n t
(
numcli number,
nom varchar2 ( 2 5 6 ) ,
prenom varchar2 ( 2 5 6 )
)

Afficher le contenu d’une table


syntaxe :
SELECT ∗ FROM <nomdelatable >
exemple :
s e l e c t ∗ from c l i e n t

Ajouter une ligne dans une table


syntaxe :
INSERT INTO <nomdelatable > (<nomcolonne 1 >, . . . , <nomcolonne n >)
VALUES (< v a l e u r c o l o n n e 1 >, . . . , <v a l e u r c o l o n n e n >)
exemple :
INSERT INTO CLIENT ( numcli , nom , prenom ) VALUES ( 1 , ’ Mesle ’ , ’ Alexandre ’ )

6
1.1.4 SQL+ et iSQL
Connection
login : scott
password : tiger

Liste des tables

SELECT t a b l e n a m e FROM u s e r t a b l e s ;
Description des tables
Syntaxe :
DESC <nomtable >;
Exemple :
DESC c l i e n t ;

Attention
Les commandes de SQL+ se terminent par un point-virgule !

7
1.2 Contraintes déclaratives
1.2.1 Valeurs par défaut

create table c l i e n t
(
numcli number,
nom varchar2 ( 2 5 6 ) default ’ Moi ’ ,
prenom varchar2 ( 2 5 6 )
)
fait de ’Moi’ le nom par défaut.
1.2.2 Champs non renseignés

create table c l i e n t
(
numcli number,
nom varchar2 ( 2 5 6 ) NOT NULL,
prenom varchar2 ( 2 5 6 ) NOT NULL
)
force la saisie des champs nom et prénom.
1.2.3 Clé primaire
Une clé primaire est :
– toujours renseignée
– unique
On peut préciser PRIMARY KEY dans la création de table
create table c l i e n t
(
numcli number PRIMARY KEY,
nom varchar2 ( 2 5 6 ) ,
prenom varchar2 ( 2 5 6 )
)
La colonne numcli est clé primaire, toute insertion ne respectant pas la contraine de clé primaire sera
refusée par Oracle.

1.2.4 Clé étrangère


Une clé étrangère référence une ligne d’une table quelconque :
Syntaxe :
REFERENCES <nomtable> (<nomcolonne >)

create table c l i e n t
(
numcli number PRIMARY KEY,
nom varchar2 ( 2 5 6 ) ,
prenom varchar2 ( 2 5 6 ) ,
numdept number REFERENCES DEPT ( nd )
)
Une ligne ne pourra être insérée dans la table client que s’il existe dans la table DEPT une ligne dont la
valeur nd est la même que la valeur numdept en cours d’insertion.
On remarque qu’il devient impossible d’écraser la table DEPT si elle est référencée par une clé étrangère.

8
1.2.5 Syntaxe alternative

ALTER TABLE <nomtable>


ADD [CONSTRAINT <nomcontrainte >] <d e s c r i p t i o n c o n t r a i n t e >
descriptioncontrainte d’une clé primaire :
PRIMARY KEY(< c o l o n n e 1 >, . . . , <c o l o n n e n >)
descriptioncontrainte d’une clé étrangère :
FOREIGN KEY(< c o l o n n e 1 >, . . . , <c o l o n n e n >)
REFERENCES <t a b l e r e f e r e n c e e > (< c o l o n n e 1 >, . . . , <c o l o n n e n >)
Il est aussi possible de placer une descriptioncontrainte dans le CREATE TABLE. Par exemple,
create table c l i e n t
(
numcli number,
nom varchar2 ( 2 5 6 ) ,
prenom varchar2 ( 2 5 6 ) ,
numdept number,
PRIMARY KEY (number) ,
FOREIGN KEY ( numdept ) REFERENCES DEPT ( nd )
)
On remarque qu’il est possible de nommer une contrainte. C’est utile si on souhaite la supprimer :
ALTER TABLE <nomtable> DROP CONSTRAINT <nomcontrainte >
Pour lister les contraintes :
SELECT ∗ FROM USER CONSTRAINTS

9
1.3 Requêtes mono-tabulaires
1.3.1 Compléments sur SELECT
Il est possible d’utiliser SELECT pour n’afficher que certaines colonnes d’une table. Syntaxe :
SELECT <c o l o n n e 1 >, <c o l o n n e 2 >, . . . , <c o l o n n e n >
FROM <table>
Cette instruction s’appelle une requête, elle affichera pour chaque ligne de la table les valeurs des colonnes
colonne1 à colonnen . Il est possible de supprimer les lignes en double à l’aide du mot-clé DISTINCT. Par
exemple :
SELECT DISTINCT <c o l o n n e 1 >, <c o l o n n e 2 >, . . . , <c o l o n n e n >
FROM <table>
Pour trier les données, on utilise ORDER BY. Exemple :
SELECT <c o l o n n e 1 >, <c o l o n n e 2 >, . . . , <c o l o n n e n >
FROM <table>
ORDER BY <c o l o n n e 1 b i s >, <c o l o n n e 2 b i s >, . . . , <c o l o n n e n b i s >
Cette instruction trie les données par colonne1bis croissants. En cas d’égalité, le tri est fait par colonne2bis
croissants, etc. Pour trier par ordre décroissant, on ajoute DESC après le nom de la colonne choisie comme
critère décroissant. Par exemple :
SELECT <c o l o n n e 1 >, <c o l o n n e 2 >, . . . , <c o l o n n e n >
FROM <table>
ORDER BY <c o l o n n e 1 b i s > DESC, <c o l o n n e 2 b i s >, . . . , <c o l o n n e n b i s >

1.3.2 Instruction WHERE


Cette instruction permet de ne sélectionner que certaines lignes de la table. Par exemple la requête
SELECT n o m c l i e n t , p r e n o m c l i e n t
FROM c l i e n t
WHERE n u m e r o c l i e n t = 1
va afficher les nom et prénom du client dont le numéro est 1. La syntaxe générale est
SELECT <c o l o n n e 1 >, <c o l o n n e 2 >, . . . , <c o l o n n e n >
FROM <table>
WHERE <c o n d i t i o n >
condition sera évaluée pour chaque ligne de la table, et seules celles qui véfieront cette condition feront
partie du résultat de la requête.

1.3.3 Conditions
Comparaison
Les conditions peuvent être des relations d’égalité (=), de différence (<>), d’inégalité (<, >, >= ou <=)
sur des colonnes :
numero client = 2
nom client = ’ Chirac ’
p r e n o m c l i e n t <> ’ Hubert ’
s a l a r y < 230
t a x e s >= 23000

10
Négation
La négation d’une condition s’obtient à l’aide de NOT. Par exemple, il est possible de ré-ecrire les conditions
ci-avant :
NOT ( n u m e r o c l i e n t <> 2 )
NOT ( n o m c l i e n t <> ’ C h i r a c ’ )
NOT ( p r e n o m c l i e n t = ’ Hubert ’ )
NOT ( s a l a r y >= 2 3 0 )
NOT ( taxes < 23000)

Connecteurs logiques
De même, vous avez à votre disposition tous les connecteurs logiques binaires : AND, OR. Ainsi, les deux
conditions suivantes sont les mêmes :
NOT( ( nom = ’ Bush ’ ) AND ( prenom <> ’ Medor ’ ) )
(nom <> ’ Bush ’ ) OR ( prenom = ’ Medor ’ )

NULLité
Un champ non renseigné a la valeur NULL, dans une comparaison, NULL n’est jamais égal à quelque valeur
qu’il soit ! La condition suivante est toujours fausse :
NULL = NULL;
La requête suivante ne renvoie aucune ligne :
SELECT ∗ FROM EMP WHERE COMM=NULL;
Pour tester la nullité d’un champ, on utilise IS NULL, par exemple :
SELECT ∗ FROM EMP WHERE COMM IS NULL;
La non-nullité se teste de deux façons :
WHERE NOT (COMM IS NULL) ;
WHERE COMM IS NOT NULL

Encadrement
Une valeur numérique peut être encadrée à l’aide de l’opérateur BETWEEN, par exemple les deux conditions
suivantes sont équivalentes :
SALAIRE BETWEEN 1000 AND 5000
(SALAIRE >= 1 0 0 0 ) AND (SALAIRE <= 5 0 0 0 )

Inclusion
L’opérateur IN permet de tester l’appartenance à une liste de valeurs. Les deux propositions suivantes
sont équivalentes
NAME IN ( ’ Mesle ’ , ’ Bush ’ , ’ Medor ’ )
(NAME = ’ Mesle ’ ) OR (NAME = ’ Bush ’ ) OR (NAME = ’ Medor ’ )

11
LIKE
LIKE sert à comparer le contenu d’une variable à un littéral générique. Par exemple, la condition
NAME LIKE ’M%’
sera vérifiée si NAME commence par un ’M’. Ca fonctionne aussi sur les valeurs de type numérique, la
condition
SALARY LIKE ’ %000000000 ’
sera vérifiée si SALARY se termine par 000000000. Le caractère % peut remplacer dans le littéral n’importe
que suite, vide ou non, de caractères ; il a le même rôle que * en DOS et en SHELL. Le caractère
remplace un et un seul caractère dans le littéral. Par exemple, la condition
NAME LIKE ’ B s%’
ne sera vérifiée que si NAME commence par un ’B’ et contient un ’s’ en troisième position.

1.3.4 Suppression
L’expression
DELETE FROM <NOMTABLE> WHERE <CONDITION>
efface de la table NOMTABLE toutes les lignes vérifiant condition. Attention ! La commande
DELETE FROM <NOMTABLE>
efface toutes les lignes de la table NOMTABLE !

1.3.5 Mise à jour


L’expression
UPDATE <NOMTABLE> SET
<c o l o n n e 1 > = <v a l e u r 1 >,
<c o l o n n e 2 > = <v a l e u r 2 >,
... ,
<c o l o n n e n > = <v a l e u r n >
WHERE <CONDITION>
modifie les lignes de la table NOMTABLE vérifiant condition. Elle affecte au champ colonnei la valeur
valeuri . Par exemple,
UPDATE CLIENT SET NAME = ’ Medor ’ WHERE LUNCH = ’ Bones ’
affecte la valeur ’Médor’ aux champs noms de toutes les lignes dont la valeur LUNCH est égale à ’Bones’.
Il est possible, dans une modification, d’utiliser les valeurs des autres champs de la ligne, voire même
l’ancienne valeur de ce champ. Par exemple,
UPDATE CLIENT SET SALARY = SALARY + 5000
augmente tous les salaires de 5000 (choisissez l’unité !).

12
1.4 Requêtes multi-tabulaires
1.4.1 Principe
Etant donné le code ci-dessous,
CREATE TABLE MODULE
(numMod number primary key ,
nomMod varchar2 ( 3 0 )
);

CREATE TABLE PREREQUIS


(
numMod number r e f e r e n c e s MODULE(numMod) ,
numModPrereq number r e f e r e n c e s MODULE(numMod) ,
noteMin number( 2 ) DEFAULT 10 NOT NULL ,
PRIMARY KEY(numMod, numModPrereq )
);

INSERT INTO MODULE VALUES (1 , ’ ORacle ’ ) ;


INSERT INTO MODULE VALUES (2 , ’C++’ ) ;
INSERT INTO MODULE VALUES (3 , ’C ’ ) ;
INSERT INTO MODULE VALUES (4 , ’ Algo ’ ) ;
INSERT INTO MODULE VALUES (5 , ’ Merise ’ ) ;
INSERT INTO MODULE VALUES (6 , ’PL/SQL O r a c l e ’ ) ;
INSERT INTO MODULE VALUES (7 , ’mySQL ’ ) ;
INSERT INTO MODULE VALUES (8 , ’ Algo avancee ’ ) ;

INSERT INTO PREREQUIS (numMod, numModPrereq ) VALUES ( 1 , 5 ) ;


INSERT INTO PREREQUIS (numMod, numModPrereq ) VALUES ( 2 , 3 ) ;
INSERT INTO PREREQUIS VALUES ( 6 , 1 , 1 2 ) ;
INSERT INTO PREREQUIS (numMod, numModPrereq ) VALUES ( 6 , 5 ) ;
INSERT INTO PREREQUIS (numMod, numModPrereq ) VALUES ( 8 , 5 ) ;
INSERT INTO PREREQUIS (numMod, numModPrereq ) VALUES ( 7 , 5 ) ;
Si on souhaite connaı̂tre les numéros des modules prerequis pour s’inscrire dans le module ’PL/SQL
Oracle’, il nous faut tout d’abord le numéro de ce module :
SQL> SELECT numMod FROM module WHERE nomMod = ’PL/SQL O r a c l e ’ ;

NUMMOD
−−−−−−−−−−
6
Ensuite, cherchons les numéros des modules prérequis pour s’inscrire dans le module numéro 6,
SQL> SELECT numModPrereq FROM p r e r e q u i s WHERE numMod = 6 ;

NUMMODPREREQ
−−−−−−−−−−−−
1
5
Et pour finir, allons récupérer les noms de ces modules,
SQL> SELECT nomMod FROM module WHERE numMod IN ( 1 , 5 ) ;

NOMMOD
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

13
Oracle
Merise
Vous êtes probablement tous en train de vous demander s’il n’existe pas une méthode plus simple et plus
rapide, et surtout une façon d’automatiser ce que nous venons de faire. Il existe un moyen de sélectionner
des données dans plusieurs tables simultanément. Pour traiter la question ci-dessus il suffisait de saisir :
SQL> SELECT m2 . nomMod
2 FROM module m1, module m2, p r e r e q u i s p
3 WHERE m1 . numMod = p . numMod AND m2 . numMod = p . numModprereq
4 AND m1 . nomMod = ’PL/SQL O r a c l e ’ ;

NOMMOD
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Oracle
Merise
Le but de ce chapitre est d’expliciter ce type de commande.

1.4.2 Produit cartésien


L’instruction SELECT ... FROM ... peut s’étendre de la façon suivante :
SELECT <l i s t e c o l o n n e s >
FROM < l i s t e t a b l e s >
L’exemple ci-dessous vous montre le résultat d’une telle commande.
SQL> SELECT ∗ FROM p r o p o s e r , p r o d u i t ;

NUMFOU NUMPROD PRIX NUMPROD NOMPROD


−−−−−−−−−− −−−−−−−−−− −−−−−−−−−− −−−−−−−−−− −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
1 1 200 1 Roue de s e c o u r s
1 1 200 2 Poupee Batman
1 1 200 3 Cotons t i g e s
1 1 200 4 Cornichons
1 2 15 1 Roue de s e c o u r s
1 2 15 2 Poupee Batman
1 2 15 3 Cotons t i g e s
1 2 15 4 Cornichons
2 2 1 1 Roue de s e c o u r s
2 2 1 2 Poupee Batman
2 2 1 3 Cotons t i g e s

NUMFOU NUMPROD PRIX NUMPROD NOMPROD


−−−−−−−−−− −−−−−−−−−− −−−−−−−−−− −−−−−−−−−− −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
2 2 1 4 Cornichons
3 3 2 1 Roue de s e c o u r s
3 3 2 2 Poupee Batman
3 3 2 3 Cotons t i g e s
3 3 2 4 Cornichons

16 l i g n e ( s ) s e l e c t i o n n e e ( s ) .
Placer une liste de tables dans le FROM revient à former toutes les combinaisons de lignes possibles.
Cependant, cela a relativement peu de sens.

14
1.4.3 Jointure
Il serait plus intéressant, dans le cas présent, de ne voir s’afficher que des lignes dont les numéros de
produits concordent. Pour ce faire, il suffit d’utiliser WHERE. Par exemple,
SQL> SELECT ∗ FROM p r o p o s e r , p r o d u i t
2 WHERE p r o p o s e r . numprod = p r o d u i t . numprod ;

NUMFOU NUMPROD PRIX NUMPROD NOMPROD


−−−−−−−−−− −−−−−−−−−− −−−−−−−−−− −−−−−−−−−− −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
1 1 200 1 Roue de s e c o u r s
2 2 1 2 Poupee Batman
1 2 15 2 Poupee Batman
3 3 2 3 Cotons t i g e s
Nous avons mis en correspondance des lignes de la table proposer avec des lignes de la table produit en
utilisant le fait que numprod est une clé étrangère dans proposer. Comme la colonne numprod apparait
deux fois dans la requête, il est nécessaire de la préfixer par le nom de la table de sorte que chaque colonne
puisse être désignée de façon non ambiguë. Si on veut mettre face à face les noms des produits et les noms
des fournisseurs, il suffit de saisir la requête
SQL> SELECT nomfou , nomprod
2 FROM p r o d u i t , f o u r n i s s e u r , p r o p o s e r
3 WHERE p r o d u i t . numProd = p r o p o s e r . numProd
4 AND f o u r n i s s e u r . numFou = p r o p o s e r . numFou ;

NOMFOU NOMPROD
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
f1 Roue de s e c o u r s
f2 Poupee Batman
f1 Poupee Batman
f3 Cotons t i g e s

1.4.4 Jointures refléxives


En utilisant la syntaxe suivante, il est possible de rennomer les tables,
FROM <t a b l e 1 > <table 1 renommee >, . . . , <t a b l e n > <table n renommee >
Reformulons la requête ci-dessus,
SQL> SELECT nomfou , nomprod
2 FROM p r o d u i t p , f o u r n i s s e u r f , p r o p o s e r pr
3 WHERE p . numProd = pr . numProd
4 AND f . numFou = pr . numFou ;

NOMFOU NOMPROD
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
f1 Roue de s e c o u r s
f2 Poupee Batman
f1 Poupee Batman
f3 Cotons t i g e s
Le renommage permet entre autres de faire des jointures réflexives, c’est à dire entre une table et elle
même. Par exemple, en reprenant la table intervalle,
SQL> SELECT ∗ FROM i n t e r v a l l e ;

BORNEINF BORNESUP

15
−−−−−−−−−− −−−−−−−−−−
0 30
2 3
2 56
5 10
7 32
8 27
12 3
12 30
21 8
34 26

10 l i g n e ( s ) s e l e c t i o n n e e ( s ) .
La commande ci-dessous affiche tous les couples d’intervalles ayant une borne en commun,
SQL> SELECT ∗ FROM i n t e r v a l l e i , i n t e r v a l l e j
2 WHERE ( i . b o r n e I n f = j . b o r n e I n f OR i . borneSup = j . borneSup )
3 AND i . rowid <> j . rowid ;

BORNEINF BORNESUP BORNEINF BORNESUP


−−−−−−−−−− −−−−−−−−−− −−−−−−−−−− −−−−−−−−−−
0 30 12 30
2 3 2 56
2 3 12 3
2 56 2 3
12 3 2 3
12 3 12 30
12 30 0 30
12 30 12 3

8 ligne ( s ) selectionnee ( s ).
Que ceux qui ont du courage reformulent la requête sans utiliser le rowid !

16
1.5 Agrégation de données
1.5.1 Fonctions d’agrégation
Exemple introductif
Nous voulons connaı̂tre le nombre de lignes de table produit. Deux façons de procéder :
1. Solution pour les boeufs
SQL> SELECT ∗ FROM PRODUIT;

NUMPROD NOMPROD
−−−−−−−−−− −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
1 Roue de s e c o u r s
2 Poupee Batman
3 Cotons t i g e s
4 Cornichons

4 ligne ( s ) selectionnee ( s ).
On a la réponse avec le nombre de lignes sélectionnées.
2. Solution pour les boss
SQL> SELECT count ( ∗ ) FROM PRODUIT;

COUNT( ∗ )
−−−−−−−−−−
4

1 ligne selectionnee .
La réponse est le résultat de la requête.
Que s’est-il passé ? Qu’est-ce donc que cette requête ésotérique ? Réponse : Le cours d’aujourd’hui.

Définition
Une fonction d’agrégation retourne une valeur calculée sur toutes les lignes de la requête (nombre,
moyenne...). Nous allons utiliser les suivantes :
– COUNT(col) : retourne le nombre de lignes dont le champ col est non NULL.
– AVG(col) : retourne la moyenne des valeurs col sur toutes les lignes dont le champ col est non
NULL.
– MAX(col) : retourne la plus grande des valeurs col sur toutes les lignes dont le champ col est non
NULL.
– MIN(col) : retourne la plus petite des valeurs col sur toutes les lignes dont le champ col est non
NULL.
– SUM(col) : retourne la somme des valeurs col sur toutes les lignes dont le champ col est non NULL.

Exemples d’utilisation
L’exemple suivant retourne le prix du produit proposé au prix maximal.
SQL> SELECT MAX( p r i x )
2 FROM PROPOSER;

MAX(PRIX)
−−−−−−−−−−
200

17
1 ligne selectionnee .
Il est possible de renommer la colonne MAX(prix), en utilisant le mot clé AS :
SQL> SELECT MAX( p r i x ) AS PRIX MAXIMAL
2 FROM PROPOSER;

PRIX MAXIMAL
−−−−−−−−−−−−
200

1 ligne selectionnee .
Les requêtes suivantes récupèrent le nom du fournisseur proposant l’article ’Poupée Batman’ au prix le
moins élevé :
SQL> SELECT MIN( p r i x ) AS PRIX MINIMUM
2 FROM PROPOSER PR, PRODUIT P
3 WHERE PR. numprod = P . numprod
4 AND nomprod = ’ Poupee Batman ’ ;

PRIX MINIMUM
−−−−−−−−−−−−
1

1 ligne selectionnee .

SQL> SELECT nomfou


2 FROM FOURNISSEUR F , PROPOSER PR, PRODUIT P
3 WHERE F . numfou = PR. numfou
4 AND PR. numprod = P . numprod
5 AND nomprod = ’ Poupee Batman ’
6 AND p r i x = 1 ;

NOMFOU
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
f2

1 ligne selectionnee .
Il est possible de faire cela avec une seule requête en récupérant le prix minimum dans une requête
imbriquée. Mais cela sera pour un cours ultérieur.

Compléments sur COUNT


On récupère le nombre de ligne retournées par une requête en utilisant COUNT(*). Par exemple, si on
souhaite connaı̂tre le nombre de produits proposés par le fournisseur ’f1’ :
SQL> SELECT COUNT( ∗ ) AS NB PROD
2 FROM FOURNISSEUR F , PROPOSER P
3 WHERE F . numfou = P . numfou
4 AND nomfou = ’ f 1 ’ ;

NB PROD
−−−−−−−−−−
2

1 ligne selectionnee .

18
On aurait aussi pu saisir :
SQL> SELECT COUNT( numprod ) AS NB PROD
2 FROM FOURNISSEUR F , PROPOSER P
3 WHERE F . numfou = P . numfou
4 AND nomfou = ’ f 1 ’ ;

NB PROD
−−−−−−−−−−
2

1 ligne selectionnee .
Pour connaı̂tre le nombre de produits proposés, c’est à dire dont le numprod a une occurence dans la table
PROPOSER, on procède de la façon suivante :
SQL> SELECT COUNT(DISTINCT numprod ) AS NB PRODUITS PROPOSES
2 FROM PROPOSER;

NB PRODUITS PROPOSES
−−−−−−−−−−−−−−−−−−−−
3

1 ligne selectionnee .
Le DISTINCT nous sert à éviter qu’un même produit proposé par des fournisseurs différents soit compta-
bilisé plusieurs fois.

1.5.2 Groupage
L’instruction GROUP BY
Les opération d’agrégation considérées jusqu’à maintenant portent sur la totalité des lignes retournées
par les requêtes, l’instruction GROUP BY permet de former des paquets à l’intérieur desquels les données
seront agrégées. Cette instruction s’utilise de la manière suivante
SELECT . . .
FROM . . .
WHERE. . .
GROUP BY < l i s t e c o l o n n e s >
ORDER BY . . .
La liste des colonnes sert de critère pour répartir les lignes dans des paquets de lignes. Si par exemple
nous souhaitons afficher la liste des nombres de produits proposés par chaque fournisseur :
SQL> SELECT nomfou , COUNT(DISTINCT numprod ) AS NB PRODUITS PROPOSES
2 FROM FOURNISSEUR F , PROPOSER P
3 WHERE F . numfou = P . numfou
4 GROUP BY nomfou ;

NOMFOU NB PRODUITS PROPOSES


−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− −−−−−−−−−−−−−−−−−−−−
f1 2
f2 1
f3 1

3 ligne ( s ) selectionnee ( s ).

19
L’instruction HAVING
Supposons que de la requête précédente, nous ne souhaitions garder que les lignes pour lesquelles la
valeur NB PRODUITS PROPOSES est égale à 1. Ajouter une condition dans WHERE serait inutile, le filtrage
occasionné par WHERE est effectué avant l’agrégation. Il nous faudrait une instruction pour n’inclure que
des groupes de données répondant certains critères. L’instruction utilisée pour ce faire est HAVING. Son
utilisation est la suivante :
SELECT . . .
FROM . . .
WHERE . . .
GROUP BY. . .
HAVING <c o n d i t i o n >
ORDER BY . . .
Par exemple,
SQL> SELECT nomfou , COUNT(DISTINCT numprod ) AS NB PRODUITS PROPOSES
2 FROM FOURNISSEUR F , PROPOSER P
3 WHERE F . numfou = P . numfou
4 GROUP BY nomfou
5 HAVING COUNT(DISTINCT numprod ) = 1
6 ORDER BY nomfou DESC;

NOMFOU NB PRODUITS PROPOSES


−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− −−−−−−−−−−−−−−−−−−−−
f3 1
f2 1

2 ligne ( s ) selectionnee ( s ).
Affichons les noms des fournisseurs qui ont livré strictement plus d’un produit différent (toutes livraisons
confondues),
SQL> SELECT nomfou
2 FROM FOURNISSEUR F , DETAILLIVRAISON D
3 WHERE F . numfou = D. numfou
4 GROUP BY nomfou
5 HAVING count (DISTINCT D. numprod ) > 1 ;

NOMFOU
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
f1

1 ligne selectionnee .

20
1.6 Vues
1.6.1 Définition
Une vue est une table contenant des données calculées sur celle d’une autre table. Les données d’une vue
sont tout le temps à jour. Si vous modifiez les données d’une des tables sur lesquelles est calculée la vue,
alors les modifications sont automatiquement répercutées sur la vue.

1.6.2 Syntaxe
Appréciez la simplicité de la syntaxe :
CREATE VIEW <nom vue> AS <r e q u e t e >

1.6.3 Application
Par exemple, la requête suivante met en correpondance les noms des produits avec le nombre de fournis-
seurs qui le proposent :
SQL> SELECT nomprod , COUNT( numfou ) AS NB FOURNISSEURS
2 FROM PRODUIT P
3 LEFT OUTER JOIN PROPOSER PR
4 ON P . numprod = PR. numprod
5 GROUP BY nomprod
6 ORDER BY COUNT( numfou ) ;

NOMPROD NB FOURNISSEURS
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− −−−−−−−−−−−−−−−
Cornichons 0
Cotons t i g e s 1
Roue de s e c o u r s 1
Poupee Batman 2

4 ligne ( s ) selectionnee ( s ).
Ce type de requête sera explité dans un cours ultérieur. Pour le moment, notez juste que les outils dont
vous disposez pour le moment ne vous permettront pas de formuler une requête affichant les noms des
produits n’ayant aucun fournisseur. Créons une vue pour ne pas avoir à se farcir la requête chaque fois
que nous aurons besoin de ces informations :
SQL> CREATE VIEW NB FOURNISSEURS PAR PRODUIT AS
2 SELECT nomprod , COUNT( numfou ) AS NB FOURNISSEURS
3 FROM PRODUIT P
4 LEFT OUTER JOIN PROPOSER PR
5 ON P . numprod = PR. numprod
6 GROUP BY nomprod
7 ORDER BY COUNT( numfou ) ;

Vue c r e e e .
Une fois créée, on peut interroger une vue de la même façon qu’on interroge une table :
SQL> SELECT ∗
2 FROM NB FOURNISSEURS PAR PRODUIT ;

NOMPROD NB FOURNISSEURS
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− −−−−−−−−−−−−−−−
Cornichons 0

21
Cotons t i g e s 1
Roue de s e c o u r s 1
Poupee Batman 2

4 ligne ( s ) selectionnee ( s ).
Notez que toute modification dans la table PROPOSER ou PRODUIT sera immédiatement répercutée sur la
vue.
SQL> INSERT INTO PROPOSER VALUES ( 3 , 4 , 9 ) ;

1 ligne creee .

SQL> SELECT ∗
2 FROM NB FOURNISSEURS PAR PRODUIT ;

NOMPROD NB FOURNISSEURS
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− −−−−−−−−−−−−−−−
Cornichons 1
Cotons t i g e s 1
Roue de s e c o u r s 1
Poupee Batman 2

4 ligne ( s ) selectionnee ( s ).
Maintenant, nous souhaitons voir s’afficher, pour tout i, le nombre de produits proposés par exactement
i fournisseurs.
SQL> SET head o f f
SQL> SELECT ’ I l y a ’ | | COUNT(NOMPROD) | | ’ p r o d u i t ( s ) q u i e s t / s o n t ’ | |
2 ’ p r o p o s e ( s ) par ’ | | NB FOURNISSEURS | | ’ f o u r n i s s e u r ( s ) . ’
3 FROM NB FOURNISSEURS PAR PRODUIT
4 GROUP BY NB FOURNISSEURS
5 ORDER BY NB FOURNISSEURS ;

I l y a 3 p r o d u i t ( s ) q u i e s t / s o n t p r o p o s e ( s ) par 1 f o u r n i s s e u r ( s ) .
I l y a 1 p r o d u i t ( s ) q u i e s t / s o n t p r o p o s e ( s ) par 2 f o u r n i s s e u r ( s ) .

2 ligne ( s ) selectionnee ( s ).

SQL> SET head on

1.6.4 Suppression
On supprime une vue avec l’instruction suivante :
DROP VIEW <nom vue >;

22
1.7 Requêtes imbriquées
Oracle permet d’imbriquer les requêtes, c’est-à-dire de placer des requêtes dans les requêtes. Une requête
imbriquée peut renvoyer trois types de résultats :
– une valeur scalaire
– une colonne
– une table

1.7.1 Sous requêtes renvoyant une valeur scalaire


Le résultat d’une requête est dit scalaire s’il comporte une seule ligne et une seule colonne. Par exemple :
SQL> SELECT COUNT( ∗ ) FROM PERSONNE;

COUNT( ∗ )
−−−−−−−−−−
21
On peut placer dans une requête une sous-requête calculant un résultat scalaire. Un tel type de sous-
requête se place soit comme une colonne supplémentaire, soit comme une valeur servant à évaluer des
conditions (WHERE ou HAVING).

Colonne fictive
On peut ajouter une colonne dans une requête, et choisir comme valeurs pour cette colonne le résultat
d’une requête. Ce type de requête est souvent une alternative à GROUP BY. Par exemple, la requête suivante
nous renvoie, pour tout produit, le nombre de fournisseurs proposant ce produit :
SQL> SELECT nomprod , (SELECT COUNT( ∗ )
2 FROM PROPOSER PR
3 WHERE PR. numprod = P . numprod )
4 AS NB FOURNISSEURS
5 FROM PRODUIT P ;

NOMPROD NB FOURNISSEURS
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− −−−−−−−−−−−−−−−
Roue de s e c o u r s 1
Poupee Batman 2
Cotons t i g e s 1
Cornichons 0

Conditions complexes
On peut construire une condition en utilisant le résultat d’une requête. Pour notre exemple, déclarons
d’abord une vue contenant le nombe d’articles proposés par chaque fournisseur,
SQL> CREATE VIEW NB PROD PAR FOU AS
2 SELECT numfou , (SELECT COUNT( ∗ )
3 FROM PROPOSER P
4 WHERE P . numfou = F . numfou )
5 AS NB PROD
6 FROM FOURNISSEUR F ;

Vue c r e e e .
Ensuite, recherchons les noms des fournisseurs proposant le plus de produits :

23
SQL> SELECT nomfou
2 FROM FOURNISSEUR F , NB PROD PAR FOU N
3 WHERE F . numfou = N. numfou
4 AND NB PROD = (SELECT MAX(NB PROD)
5 FROM NB PROD PAR FOU ) ;

NOMFOU
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
f1
La requête SELECT MAX(NB PROD) FROM NB PROD PAR FOU est évaluée avant, et son résultat lui est sub-
stitué dans l’expression de la requête. Comme on a
SQL> SELECT MAX(NB PROD) FROM NB PROD PAR FOU ;

MAX(NB PROD)
−−−−−−−−−−−−
2
Alors la requête précédente, dans ce contexte, est équivalente à
SQL> SELECT nomfou
2 FROM FOURNISSEUR F , NB PROD PAR FOU N
3 WHERE F . numfou = N. numfou
4 AND NB PROD = 2 ;

NOMFOU
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
f1

INSERT et UPDATE
On peut placer dans des instructions de mises à jour ou d’insertions des requêtes imbriquées. Par exemple,
SQL> INSERT INTO PERSONNE ( numpers , nom , prenom )
2 VALUES ( (SELECT MAX( numpers ) + 1 FROM PERSONNE) ,
3 ’ Darth ’ , ’ Vador ’ ) ;

1 ligne creee .
SQL> UPDATE PERSONNE SET
2 p e r e = (SELECT numpers
3 FROM PERSONNE
4 WHERE nom = ’ S o c r a t e ’
5 AND prenom IS NULL) ,
6 mere = (SELECT numpers
7 FROM PERSONNE
8 WHERE nom = ’ Fabian ’
9 AND prenom = ’ Lara ’ )
10 WHERE numpers = (SELECT numpers
11 FROM PERSONNE
12 WHERE nom = ’ Darth ’
13 AND prenom = ’ Vador ’ ) ;

1 l i g n e mise a j o u r .

24
1.7.2 Sous requêtes renvoyant une colonne
On considère une colonne comme une liste de valeurs, on peut tester l’appartance d’un élément à cette
liste à l’aide de l’opérateur IN. On peut s’en servir comme une alternative aux jointures, par exemple,
réécrivons la requête de la section précédente. La requête suivante nous renvoie le nombre de produits
proposés par les fournisseurs proposant le plus de produits :
SQL> SELECT MAX(NB PROD) FROM NB PROD PAR FOU ;

MAX(NB PROD)
−−−−−−−−−−−−
2
Maintenant, recherchons les numéros des fournisseurs proposant un tel nombre de produits :
SQL> SELECT N. numfou
2 FROM NB PROD PAR FOU N
3 WHERE NB PROD = (SELECT MAX(NB PROD)
4 FROM NB PROD PAR FOU ) ;

NUMFOU
−−−−−−−−−−
1
Notons que s’il existe plusieurs fournisseurs proposant 2 produits, cette requête renverra plusieurs lignes.
C’est donc par hasard qu’elle ne retourne qu’une ligne. Le numéro du fournisseur proposant le plus de
produits est donc le 1. Cherchons ce fournisseur :
SQL> SELECT nomfou
2 FROM FOURNISSEUR F
3 WHERE F . numfou IN ( 1 ) ;

NOMFOU
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
f1
Il suffit donc dans la requête ci-dessous de remplacer le 1 par la requête qui a retourné 1. On a finalement :
SQL> SELECT nomfou
2 FROM FOURNISSEUR F
3 WHERE F . numfou IN (SELECT N. numfou
4 FROM NB PROD PAR FOU N
5 WHERE NB PROD = (SELECT MAX(NB PROD)
6 FROM NB PROD PAR FOU ) ) ;

NOMFOU
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
f1

1.7.3 Sous requêtes non correlées renvoyant une table


On peut remplacer le nom d’une table dans la clause FROM par une sous-requête. Par exemple, la requête
suivante renvoie une table.
SQL> SELECT
2 (SELECT COUNT( ∗ )
3 FROM PROPOSER PR
4 WHERE PR. numfou = F . numfou
5 ) AS NB PROD

25
6 FROM FOURNISSEUR F ;

NB PROD
−−−−−−−−−−
2
1
1
0
Cette table contient, pour chaque fournisseur, le nombre de produits proposés. Si l’on souhaite connaı̂tre
le plus grand nombre de produits proposés, on se sert du résultat de la requête ci-dessus comme d’une
table :
SQL> SELECT MAX(NB PROD) AS MAX NB PROD
2 FROM
3 (SELECT
4 (SELECT COUNT( ∗ )
5 FROM PROPOSER PR
6 WHERE PR. numfou = F . numfou
7 ) AS NB PROD
8 FROM FOURNISSEUR F
9 );

MAX NB PROD
−−−−−−−−−−−
2
Ce type de requête est une alternative aux vues. Récupérons maintenant les noms des fournisseurs pro-
posant le plus de produits (sans jointure et sans vue !) :
SQL> SELECT nomfou
2 FROM FOURNISSEUR
3 WHERE numfou IN
4 (SELECT numfou
5 FROM
6 (SELECT numfou ,
7 (SELECT COUNT( ∗ )
8 FROM PROPOSER PR
9 WHERE PR. numfou = F . numfou
10 ) AS NB PROD
11 FROM FOURNISSEUR F
12 ) N
13 WHERE NB PROD =
14 (SELECT MAX(NB PROD)
15 FROM
16 (SELECT numfou ,
17 (SELECT COUNT( ∗ )
18 FROM PROPOSER PR
19 WHERE PR. numfou = F . numfou
20 ) AS NB PROD
21 FROM FOURNISSEUR F
22 ) N
23 )
24 );

NOMFOU
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

26
f1
Vous constatez que la solution utilisant les vues est nettement plus simple.

1.7.4 Sous requêtes correlées


Une sous-requête peut être de deux types :
– simple : Elle évaluée avant la requête principale
– correlée : Elle est évaluée pour chaque ligne de la requête principale
Par exemple, la requête suivante renvoie le nombre de produits livrés pour chaque fournisseur. Elle contient
une sous-requête correlée.
SQL> SELECT numfou ,
2 (SELECT SUM( q t e )
3 FROM DETAILLIVRAISON D
4 WHERE D. numfou = F . numfou
5 ) NB PROD L
6 FROM FOURNISSEUR F ;

NUMFOU NB PROD L
−−−−−−−−−− −−−−−−−−−−
1 45
2
3 10
4
Cette même requête, une fois évaluée, peut server de requête non correlée si on souhaite connaı̂tre les
noms de ces fournisseurs :
SQL> SELECT nomfou , NB PROD L
2 FROM FOURNISSEUR F ,
3 (SELECT numfou ,
4 (SELECT SUM( q t e )
5 FROM DETAILLIVRAISON D
6 WHERE D. numfou = F . numfou
7 ) NB PROD L
8 FROM FOURNISSEUR F
9 ) L
10 WHERE F . numfou = L . numfou ;

NOMFOU NB PROD L
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− −−−−−−−−−−
f1 45
f2
f3 10
f4
Amusons-nous : quel sont, pour chaque fournisseur, les produits qui ont été les plus livrés ?
SQL> SELECT nomfou , nomprod
2 FROM FOURNISSEUR F , PRODUIT P ,
3 (SELECT FF . numfou , PP . numprod
4 FROM FOURNISSEUR FF , PRODUIT PP
5 WHERE
6 (SELECT SUM( q t e )
7 FROM DETAILLIVRAISON L
8 WHERE L . numfou = FF . numfou
9 AND L . numprod = PP . numprod

27
10 )
11 =
12 (SELECT MAX(NB PROD L)
13 FROM
14 (SELECT numfou , SUM( q t e ) AS NB PROD L
15 FROM DETAILLIVRAISON L
16 GROUP BY numprod , numfou
17 ) Q
18 WHERE Q. numfou = FF . numfou
19 )
20 GROUP BY numfou , numprod
21 ) M
22 WHERE M. numprod = P . numprod
23 AND M. numfou = F . numfou ;

NOMFOU NOMPROD
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
f1 Roue de s e c o u r s
f3 Cotons t i g e s
Dans la requête précédente, quelles sous-requêtes sont correlées et lesquelles ne le sont pas ?

28
1.8 Compléments sur les types
1.8.1 Types numériques
NUMBER(p, s) définit un type numérique de au plus (p − s) chiffres avant la virgule et au plus s chiffres
après la virgule.
SQL> CREATE TABLE TOTO
2 ( t u t u number( 4 , 2 )
3 );

Table c r e e e .

SQL> INSERT INTO TOTO VALUES( 1 0 . 2 ) ;

1 ligne creee .

SQL> INSERT INTO TOTO VALUES( 1 0 ) ;

1 ligne creee .

SQL> INSERT INTO TOTO VALUES( . 0 1 ) ;

1 ligne creee .

SQL> INSERT INTO TOTO VALUES( 2 1 . 0 1 ) ;

1 ligne creee .

SQL> INSERT INTO TOTO VALUES( 2 1 . 0 ) ;

1 ligne creee .

SQL> INSERT INTO TOTO VALUES( 2 1 . 0 1 2 ) ;

1 ligne creee .

SQL> INSERT INTO TOTO VALUES( 3 2 1 . 0 ) ;


INSERT INTO TOTO VALUES( 3 2 1 . 0 )

ERREUR a l a l i g n e 1 :
ORA−01438: v a l e u r i n c o h e r e n t e avec l a p r e c i s i o n i n d i q u e e pour c e t t e c o l o n n e

SQL> INSERT INTO TOTO VALUES( 3 2 1 ) ;


INSERT INTO TOTO VALUES( 3 2 1 )

ERREUR a l a l i g n e 1 :
ORA−01438: v a l e u r i n c o h e r e n t e avec l a p r e c i s i o n i n d i q u e e pour c e t t e c o l o n n e

SQL> SELECT ∗
2 FROM TOTO;

TUTU
−−−−−−−−−−

29
10 ,2
10
,01
21 ,01
21
21 ,01

6 ligne ( s ) selectionnee ( s ).

1.8.2 Types chaine de caractères


Une petite liste de propriétés et de fonctions qui peuvent servir :
– Pour concaténer deux chaı̂nes de caractères, on utilise l’opérateur ||
– Il est aussi possible de comparer deux chaines de caractères avec >, l’ordre considéré est l’ordre
”dictionnaire” (ou lexicographique).
– La longueur s’obtient avec la fonction LENGTH.
– On extrait une sous-chaine de caractères de longueur l à partir de l’indice i (les indices commencent
à 1) de la chaı̂ne s avec la fonction SUBSTR(S, i, l). Par exemple, SUBSTR(’oracle’, 3, 2) =
’ac’
– UPPER convertit en majuscules, LOWER convertit en minuscules.

1.8.3 Types date


Une date en SQL est considéré comme un point dans le temps. On le convertit en chaine de caratères avec
la fonction to char(date, format), où format est une chaı̂ne de caractères optionnelle. Par exemple,
SQL> SELECT t o c h a r ( d a t e l i ) AS DT
2 FROM LIVRAISON ;

DT
−−−−−−−−
30/10/06
30/10/06
SQL> SELECT t o c h a r ( d a t e l i , ’ yyyy ’ ) AS ANNEE
2 FROM LIVRAISON ;

ANNE
−−−−
2006
2006
SQL> SELECT t o c h a r ( d a t e l i , ’ yyyy /mm/dd ’ ) AS DT
2 FROM LIVRAISON ;

DT
−−−−−−−−−−
2006/10/30
2006/10/30
SQL> SELECT t o c h a r ( d a t e l i , ’yyyymmdd ’ ) AS DT
2 FROM LIVRAISON ;

DT
−−−−−−−−
20061030
20061030
On convertit une chaine de caractères en date avec la fonction to date(date, format). Par exemple :

30
SQL> UPDATE LIVRAISON
2 SET d a t e l i = t o d a t e ( ’ 1934 ’ | | t o c h a r ( d a t e l i , ’mmdd ’ ) , ’yyyymmdd ’ ) ;

2 l i g n e ( s ) mise ( s ) a j o u r .

SQL> SELECT ∗
2 FROM LIVRAISON ;

NUMFOU NUMLI DATELI


−−−−−−−−−− −−−−−−−−−− −−−−−−−−
1 1 30/10/34
3 1 30/10/34

SQL> UPDATE LIVRAISON


2 SET d a t e l i = t o d a t e ( ’ 2006 ’ | | t o c h a r ( d a t e l i , ’mmdd ’ ) , ’yyyymmdd ’ ) ;

2 l i g n e ( s ) mise ( s ) a j o u r .

SQL> SELECT ∗ FROM LIVRAISON ;

NUMFOU NUMLI DATELI


−−−−−−−−−− −−−−−−−−−− −−−−−−−−
1 1 30/10/06
3 1 30/10/06

1.8.4 La fonction inclassable


nvl(valeur1, valeur2) renvoie valeur1 si valeur1 est non NULL, valeur2 sinon. Par exemple,
SQL> DELETE FROM TOTO;

6 l i g n e ( s ) supprimee ( s ) .

SQL> SELECT SUM( t u t u )


2 FROM TOTO;

SUM(TUTU)
−−−−−−−−−−

SQL> SELECT n v l (SUM( t u t u ) , 0 )


2 FROM TOTO;

NVL(SUM(TUTU) , 0 )
−−−−−−−−−−−−−−−−
0

1.8.5 Contraintes CHECK


La contrainte déclarative de type permet de tester une condition portant les les lignes de la table prises
une par une. La syntaxe est :
ALTER TABLE nomtable ADD CONSTRAINT n o m c o n t r a i n t e CHECK( c o n d i t i o n ) ;
Par exemple,

31
SQL> ALTER TABLE EMP ADD CONSTRAINT c k s a l a r y CHECK(SAL > 0 ) ;

Table m o d i f i e e .

SQL> INSERT INTO EMP (EMPNO, SAL) VALUES ( 1 5 , −1);


INSERT INTO EMP (EMPNO, SAL) VALUES ( 1 5 , −1)

ERREUR a l a l i g n e 1 :
ORA−02290: v i o l a t i o n de c o n t r a i n t e s (SCOTT.CK SALARY) de v e r i f i c a t i o n
Une contrainte de type CHECK ne peut pas contenir de requêtes ni de valeurs non constantes (sysdate par
exemple).

32
1.9 Noyau impératif du PL/SQL
1.9.1 PL/SQL
Le PL de PL/SQL signifie Procedural Language. Il s’agit d’une extension procédurale du SQL permettant
d’effectuer des traitements complexes sur une base de données. Les possibilités offertes sont les mêmes
qu’avec des langages impératifs (instructions en séquence) classiques.
Ecrivez-le dans un éditeur dont vous copierez le contenu dans SQL+. Un script écrit en PL/SQL se termine
obligatoirement par un /, sinon SQL+ ne l’interprète pas. S’il contient des erreurs de compilation, il est
possible d’afficher les messages d’erreur avec la commande SQL+ : SHOW ERRORS.

1.9.2 Blocs
Tout code écrit dans un langage procédural est formé de blocs. Chaque bloc comprend une section de
déclaration de variables, et un ensemble d’instructions dans lequel les variables déclarées 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.9.3 Affichage
Pour afficher le contenu d’une variable, les procédures DBMS OUPUT.PUT() et DBMS OUPUT.PUT LINE()
prennent en argument une valeur à afficher ou une variable dont la valeur est à afficher. Par défaut, les
fonctions d’affichage sont desactivées. Il convient, à moins que vous ne vouliez rien voir s’afficher, de les
activer avec la commande SQL+ SET SERVEROUTPUT ON.

1.9.4 Variables
Une variable se déclare de la sorte :
nom type [ : = i n i t i a l i s a t i o n ] ;
L’initisation est optionnelle. Nous utiliserons les mêmes 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 ;

1.9.5 Traitements conditionnels


Le IF et le CASE fonctionnent de la même façon que dans les autres langages impératifs :
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
voire

33
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êmes qu’en SQL. Le switch du langage C s’implémente en PL/SQL de la façon
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 par d é f a u t ∗/
END CASE

1.9.6 Traitements répétitifs


LOOP ... END LOOP ; permet d’implémenter les boucles
LOOP
/∗ i n s t r u c t i o n s ∗/
END
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
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;
Il est possible, en bidouillant d’implémenter la boucle DO ... WHILE...

34
1.10 Tableaux et structures
1.10.1 Tableaux
Création d’un type tableau
Les types tableau doivent être définis explicitement par une déclaration 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ée par cette instruction
– taille est le nombre maximal d’éléments qu’il est possible de placer dans le tableau.
– typeElements est le type des éléments qui vont être stockés dans le tableau, il peut s’agir de
n’importe quel type.
Par exemple, créons un type tableau de nombres indicé de 1 à 10, que nous appelerons numberTab
TYPE numberTab IS VARRAY ( 1 0 ) OF NUMBER;

Déclaration d’un tableau


Dorénavant, le type d’un tableau peut être utilisé au même titre que NUMBER ou VARCHAR2. Par exemple,
déclarons un tableau appelé 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éation d’un type tableau met à disposition un constructeur du même nom que le type créé. Cette
fonction réserve de l’espace mémoire pour ce tableau et retourne l’adresse mémoire de la zone réservée,
il s’agit d’une sorte de malloc. Si, par exemple, un type tableau numtab a été crée, 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é par le constructeur est vide. Il convient ensuite de réserver de l’espace pour stocker
les éléments qu’il va contenir. On utilise pour cela la méthode EXTEND(). EXTEND s’invoque en utilisant
la notation pointée. Par exemple,
DECLARE
TYPE numberTab IS VARRAY ( 1 0 ) OF NUMBER;
t numberTab ;
BEGIN

35
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;
/
Dans cet exemple, t.EXTEND(4) ; permet par la suite d’utiliser les éléments du tableau t(1), t(2), t(3)
et t(4). Il n’est pas possible ”d’étendre” un tableau à une taille supérieure à celle spécifiée lors de la
création du type tableau associé.

Utilisation d’un tableau


On accède, en lecture et en écriture, au i-ème élément d’une variable tabulaire nommé T avec l’instruction
T(i). Les éléments sont indicés à partir de 1.
Effectuons, par exemple, une permutation circulaire vers la droite des éléments du tableau t.
SET SERVEROUTPUT ON
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.10.2 Structures
Un structure est un type regroupant plusieurs types. Une variable de type structuré contient plusieurs
variables, ces variables s’appellent aussi des champs.

Création d’un type structuré


On définit un type structuré de la sorte :
TYPE /∗ nomType ∗/ IS RECORD
(
/∗ l i s t e d e s champs ∗/
);
nomType est le nom du type structuré construit avec la syntaxe précédente. La liste suit la même syntaxe
que la liste des colonnes d’une table dans un CREATE TABLE. Par exemple, construisons le type point
(dans IR2 ),

36
TYPE p o i n t IS RECORD
(
a b s c i s s e NUMBER,
ordonnee NUMBER
);
Notez bien que les types servant à définir un type structuré peuvent être quelconques : variables scalaires,
tableaux, structures, etc.

Déclaration d’une variable de type structuré


point est maintenant un type, il devient donc possible de créer des variables de type point, la règle est
toujours la même pour déclarer des variables en PL/SQL, par exemple
p point ;
permet de déclarer une variable p de type point.

Utilisation d’une variable de type structuré


Pour accéder à un champ d’une variable de type structuré, en lecture ou en écriture, on utilise la notation
pointée : v.c est le champ appelé c de la variable structuré appelée v. Par exemple,
SET SERVEROUTPUT ON
DECLARE
TYPE p o i n t IS RECORD
(
a b s c i s s e NUMBER,
ordonnee NUMBER
);
p point ;
BEGIN
p . a b s c i s s e := 1 ;
p . ordonnee := 3 ;
DBMS OUTPUT. PUT LINE( ’ p . a b s c i s s e = ’ | | p . a b s c i s s e | |
’ and p . ordonnee = ’ | | p . ordonnee ) ;
END;
/
Le script ci-dessous crée le type point, puis crée une variable t de type point, et enfin affecte aux champs
abscisse et ordonnee du point p les valeurs 1 et 3.

37
1.11 Applications du PL/SQL
Ce cours est une introduction aux interactions possibles entre la base de données et les scripts PL/SQL.

1.11.1 Affectation
On place dans une variable le résultat d’une requête en utilisant le mot-clé INTO. Les instructions
SELECT champ 1 INTO v 1 , . . . , champ n INTO v n
FROM . . .
affecte aux variables v 1, ..., v n les valeurs retournées par la requête. Par exemple
SET SERVEROUTPUT ON
DECLARE
num NUMBER;
nom VARCHAR2( 3 0 ) := ’ Poupée 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éro ’ | | num ) ;
END;
/
Prêtez attention au fait que la requête doit retourner une et une une seule ligne, sinon, une erreur se
produit à l’exécution.

1.11.2 Tables et structures


Si vous ne tenez pas à vous prendre la tête pour choisir le type de chaque variable, demandez-vous ce que
vous allez mettre dedans ! Si vous tenez à y mettre une valeur qui se trouve dans une colonne d’une table, il
est possible de vous référer directement au type de cette colonne avec le type nomTable.nomColonne%type.
Par exemple,
SET SERVEROUTPUT ON
DECLARE
num PRODUIT. numprod%type ;
nom PRODUIT. nomprod%type := ’ Poupée 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éro ’ | | num ) ;
END;
/
Pour aller plus loin, il est même possible de déclarer une structure pour représenter une ligne d’une table,
le type porte alors le nom suivant : nomTable%rowtype.
SET SERVEROUTPUT ON
DECLARE
nom PRODUIT. nomprod%type := ’ Poupée Batman ’ ;
l i g n e PRODUIT%rowtype ;
BEGIN
SELECT ∗ INTO l i g n e
FROM PRODUIT

38
WHERE nomprod = nom ;
DBMS OUTPUT. PUT LINE( ’L ’ ’ a r t i c l e ’ | |
l i g n e . nomprod | | ’ a pour numéro ’ | | l i g n e . numprod ) ;
END;
/

1.11.3 Transactions
Un des mécanismes les plus puissants des SGBD récent réside dans le système des transactions. Un
transaction est un ensemble d’opérations “atomiques”, c’est-à-dire indivisible. Nous considérerons qu’un
ensemble d’opérations est indivisible si une exécution partielle de ces instructions poserait des problèmes
d’intégrité dans la base de données. Par exemple, dans le cas d’une base de données de gestion de comptes
en banque, un virement d’un compte à un autre se fait en deux temps : créditer un compte d’une somme
s, et débiter un autre de la même somme s. Si une erreur survient pendant la deuxième opération, et que
la transaction est interrompue, le virement est incomplet et le patron va vous assasiner.

Il convient donc de disposer d’un mécanisme permettant de se protéger de ce genre de désagrément.


Plutôt que se casser la tête à tester les erreurs à chaque étape et à balancer des instructions permettant
de “revenir en arrière”, 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ébut de la transaction (donc depuis le
précédent COMMIT), COMMIT les enregistre définitivement dans la base de données.

La variable d’environnement AUTOCOMMIT, qui peut être positionnée à ON ou à OFF permet d’activer
la gestion des transactions. Si elle est positionnée à ON, chaque instruction a des répercussions immédiates
dans la base, sinon, les modifications ne sont effectives qu’une fois qu’un COMMIT a été exécuté.

39
1.12 Exceptions
Le mécanisme des exceptions est implémenté dans la plupart des langages récent, notament orientés
objet. Cette façon de programmer a quelques avantages immédiats :
– obliger les programmeurs à traiter les erreurs : combien de fois votre prof de C a hurlé
en vous suppliant de vérifier les valeurs retournées par un malloc, ou un fopen ? La plupart des
compilateurs des langages à exceptions (notamment java) ne compilent que si pour chaque erreur
potentielle, vous avez préparé un bloc de code (éventuellement vide...) pour la traiter. Le but est
de vous assurer que vous n’avez pas oublié d’erreur.
– Rattraper les erreurs en cours d’exécution : Si vous programmez un système de sécurité
de centrale nucléaire ou un pilote automatique pour l’aviation civile, une erreur de mémoire qui
vous afficherait l’écran 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’éxecution sont rattrapables, autrement dit, il est possible de résoudre le problème sans interrompre
le programme.
– Ecrire le traitement des erreurs à part : Pour des raisons fiabilité, de lisibilité, il a été
considéré que mélanger le code “normal” et le traitement des erreurs était un style de programmation
perfectible... Dans les langages à exception, les erreurs sont traitées à part.

1.12.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ême titre qu’une variable a une identifica-
teur, 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é. On dit aussi que quand une exception est
levée (raised) (on dit aussi jetée (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 énumère les erreurs les plus pertinentes en utilisant leur nom et en consacrant à chacune d’elle un
traitement particulier pour rattraper (ou propager) l’erreur. Quand un bloc est traité, les WHEN suivants
ne sont pas évalués. OTHERS est l’exception par défaut, OTHERS est toujours vérifié, sauf si un cas précédent
a été vérifié. 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;

40
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) ;
END;
Les deux variables globales SQLCODE et SQLERRM contiennent respectivement le code d’erreur Oracle et
un message d’erreur correspondant à la dernière exception levée. Chaque exception a donc, en plus d’un
nom, un code et un message.

1.12.2 Exceptions prédéfinies


Bon nombre d’exceptions sont prédéfinies par Oracle, par exemple
– NO DATA FOUND est levée quand la requête d’une instruction de la forme SELECT ... INTO ... ne
retourne aucune ligne
– TOO MANY ROWS est levée quand la requête d’une instruction de la forme SELECT ... INTO ...
retourne plusieurs lignes
– DUP VAL ON INDEX est levée si une insertion (ou une modification) est refusée à cause d’une contrainte
d’unicité.
On peut enrichir notre exemple de la sorte :
SET SERVEROUTPUT ON
DECLARE
num NUMBER;
nom VARCHAR2( 3 0 ) := ’ Poupée 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éro ’ | | 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 problème . . . ’ ) ;
END;
/
SELECT numprod INTO num... lève une exception si la requête renvoie un nombre de lignes différent de
1.

1.12.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é de se reporter à la documentation pour les obtenir. On les traite de la façon suivante
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE = CODE1 THEN

41
/∗ 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 pas c ’ ’ que ca
peut e t r e . . . ’ ) ;
END;
C’est souvent le cas lors de violation de contraintes.

1.12.4 Déclarer et lancer ses propres exceptions


Exception est un type, on déclare donc les exceptions dans une section DECLARE. Une exception se
lance avec l’instruction RAISE. Par exemple,
SET SERVEROUTPUT ON
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;
/

42
1.13 Sous-programmes
1.13.1 Procédures
Syntaxe
On définit une procédure 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ètres sont une simple liste de couples nom type. Par exemple, la procedure suivante affiche un
compte à rebours.
CREATE OR REPLACE PROCEDURE compteARebours ( c p t NUMBER) IS
BEGIN
IF n >= 0 THEN
DBMS OUTPUT. PUT LINE( c p t ) ;
compteARebours ( c p t − 1 ) ;
END IF ;
END;

Invocation
En PL/SQL, une procédure s’invoque tout simplement avec son nom. Mais sous SQL+, on doit utili-
ser le mot-clé CALL. Par exemple, on invoque le compte à rebours sous SQL+ avec la commande CALL
compteARebours(20).

Passage de paramètres
Oracle permet le passage de paramètres par référence. Il existe trois types de passage de paramètres :
– IN : passage par valeur
– OUT : aucune valeur passée, sert de valeur de retour
– IN OUT : passage de paramètre par référence
Par défaut, le passage de paramètre se fait de type IN.
CREATE OR REPLACE PROCEDURE i n c r ( v a l IN OUT NUMBER) IS
BEGIN
v a l := v a l + 1 ;
END;

1.13.2 Fonctions
Syntaxe
On crée une nouvelle fonction de la façon 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 à retourner une valeur. Par exemple,

43
CREATE OR REPLACE module ( a NUMBER, b NUMBER) RETURN NUMBER IS
BEGIN
IF a < b THEN
RETURN a ;
ELSE
RETURN module ( a − b , b ) ;
END IF ;
END;

Invocation
Tout comme les procédures, l’invocation des fonctions ne pose aucun problème en PL/SQL, par contre, sous
SQL+, c’est quelque peu particulier. On passe par une pseudo-table nommée DUAL de la façon suivante :
SELECT module ( 2 1 , 1 2 ) FROM DUAL;

Passage de paramètres
Les paramètres sont toujours passés avec le type IN.

44
1.14 Curseurs
1.14.1 Introduction
Les instructions de type SELECT ... INTO ... manquent de souplesse, elles ne fontionnent que sur des
requêtes retourant une et une seule valeur. Ne serait-il pas intéressant de pouvoir placer dans des variables
le résultat d’une requête retournant plusieurs lignes ? A méditer...

1.14.2 Les curseurs


Un curseur est un objet contenant le résultat d’une requête (0, 1 ou plusieurs lignes).

déclaration
Un curseur se déclare dans une section DECLARE :
CURSOR /∗ nomcurseur ∗/ IS /∗ r e q u ê t e ∗/ ;
Par exemple, si on tient à récupérer tous les employés de la table EMP, on déclare le curseur suivant.
CURSOR emp cur IS
SELECT ∗ FROM EMP;

Ouverture
Lors de l’ouverture d’un curseur, la requête du curseur est évaluée, et le curseur contient toutes les données
retournées par la requête. 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ésultat de la requête On les récupère une par une
e utilisant le mot-clé FETCH :
FETCH /∗ nom curseur ∗/ INTO /∗ l i s t e v a r i a b l e s ∗/ ;
La liste de variables peut être remplacée par une structure de type nom curseur%ROWTYPE. Si la lecture
de la ligne échoue, parce qu’il n’y a plus de ligne à lire, l’attribut %NOTFOUND prend la valeur vrai.
DECLARE
CURSOR emp cur IS
SELECT ∗ FROM EMP;
l i g n e emp cur%rowtype
BEGIN
OPEN emp cur ;
LOOP
FETCH emp cur INTO l i g n e ;
EXIT WHEN emp cur%NOTFOUND;
DBMS OUTPUT. PUT LINE( l i g n e . ename ) ;

45
END LOOP;
/∗ . . . ∗/
END;

Fermeture
Après utilisation, il convient de fermer le curseur.
CLOSE /∗ nomcurseur ∗/ ;
Complétons notre exemple,
DECLARE
CURSOR emp cur IS
SELECT ∗ FROM EMP;
l i g n e emp cur%rowtype ;
BEGIN
OPEN emp cur ;
LOOP
FETCH emp cur INTO l i g n e ;
EXIT WHEN emp cur%NOTFOUND;
DBMS OUTPUT. PUT LINE( l i g n e . ename ) ;
END LOOP;
CLOSE emp cur ;
END;
/
Le programme ci-dessus peut aussi s’écrire
DECLARE
CURSOR emp cur IS
SELECT ∗ FROM EMP;
l i g n e emp cur%rowtype ;
BEGIN
OPEN emp cur ;
FETCH emp cur INTO l i g n e ;
WHILE emp cur%FOUND LOOP
DBMS OUTPUT. PUT LINE( l i g n e . ename ) ;
FETCH emp cur INTO l i g n e ;
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 l i g n e IN emp cur LOOP
/∗ Traitement ∗/
END LOOP;
Par exemple,
DECLARE
CURSOR emp cur IS
SELECT ∗ FROM EMP;
l i g n e emp cur%rowtype ;
BEGIN
FOR l i g n e IN emp cur

46
DBMS OUTPUT. PUT LINE( l i g n e . ename ) ;
END LOOP;
END;
/

47
1.15 Curseurs parametrés
1.15.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éponse : non. La requête d’un curseur ne peut pas contenir de variables dont les valeurs ne sont pas
fixées. Pourquoi ? Parce que les valeurs des ces sont susceptibles de changer entre la déclaration du curseur
et son ouverture. Le remède est un curseur paramétré.

1.15.2 Définition
Un curseur paramétré est un curseur dont la requête contient des variables dont les valeurs ne seront
fixées qu’à l’ouverture.

1.15.3 Déclaration
On précise la liste des noms et des type des paramètres entre parenthèses après le nom du curseur :
CURSOR /∗ nom ∗/ ( /∗ l i s t e d e s p a r a mè t r e s ∗/ ) IS
/∗ r e q u ê t e ∗/
Par exemple, créeons une requête qui, pour une personne donnée, nous donne la liste des noms et prénoms
de ses enfants :
CURSOR e n f a n t s ( numparent NUMBER) IS
SELECT ∗
FROM PERSONNE
WHERE p e r e = numparent
OR mere = numparent ;

1.15.4 Ouverture
On ouvre un curseur paramétré en passant en paramètre les valeurs des variables :
OPEN /∗ nom ∗/ ( /∗ l i s t e d e s p a r a mè t r e s ∗/ )
Par exemple,
OPEN e n f a n t s ( 1 ) ;

48
1.15.5 Lecture d’une ligne, fermeture
la lecture d’une ligne suit les mêmes règles qu’avec un curseur non paramétré.

1.15.6 Boucle pour


La boucle pour se charge de l’ouverture, il convient donc de placer les paramètre dans l’entête de la
boucle,
FOR /∗ v a r i a b l e ∗/ IN /∗ nom ∗/ ( /∗ l i s t e p a r a mè t r e s ∗/ ) LOOP
/∗ i n s t r u c t i o n s ∗/
END LOOP;
Par exemple,
FOR e IN e n f a n t s ( 1 ) LOOP
DBMS OUTPUT. PUT LINE( e . nompers | | ’ ’ | | e . prenompers ) ;
END LOOP;

1.15.7 Exemple récapitulatif

DECLARE
CURSOR p a r e n t IS
SELECT ∗
FROM PERSONNE;
p p a r e n t%rowtype ;
CURSOR e n f a n t s ( numparent NUMBER) IS
SELECT ∗
FROM PERSONNE
WHERE p e r e = numparent
OR mere = numparent ;
e e n f a n t%rowtype ;
BEGIN
FOR p IN p a r e n t LOOP
DBMS OUTPUT. PUT LINE( ’ Les e n f a n t s de ’ | | p . nom | |
’ ’ | | p . prenom | | ’ s o n t : ’ ) ;
FOR e IN e n f a n t s ( p . numpers ) LOOP
DBMS OUTPUT. PUT LINE( ’ ’ | | e . nompers
| | ’ ’ | | e . prenompers ) ;
END LOOP;
END LOOP;
END;

49
1.16 Triggers
1.16.1 Principe
Un trigger est une procédure stockée qui se lance automatiquement lorsqu’un événement se produit. Par
événement, on entend dans ce cours toute modification des données se trouvant dans les tables. On s’en
sert pour contrôler ou appliquer des contraintes qu’il est impossible de formuler de façon déclarative.

1.16.2 Classification
Type d’événement
Lors de la création d’un trigger, il convient de préciser quel est le type d’événement qui le déclenche.
Nous réaliserons dans ce cours des triggers pour les événements suivants :
– INSERT
– DELETE
– UPDATE

Moment de l’éxecution
On précise aussi si le trigger doit être éxecuté avant (BEFORE) ou après (AFTER) l’événement.

Evénements non atomiques


Lors que l’on fait un DELETE ..., il y a une seule instruction, mais plusieurs lignes sont affectées. Le
trigger doit-il être exécuté pour chaque ligne affectée (FOR EACH ROW), ou seulement une fois pour toute
l’instruction (STATEMENT) ?
– un FOR EACH ROW TRIGGER est exécuté à chaque fois qu’une ligne est affectée.
– un STATEMENT TRIGGER est éxecutée à chaque fois qu’une instruction est lancée.

1.16.3 Création
Syntaxe
On déclare un trigger avec l’instruction suivante :
CREATE OR REPLACE TRIGGER n o m t r i g g e r
[BEFORE | AFTER] [INSERT | DELETE | UPDATE] ON nomtable
[FOR EACH ROW | ]
/∗ 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 p a s D e D e l e t e D a n s C l i e n t
2 BEFORE DELETE ON CLIENT
3 BEGIN
4 RAISE APPLICATION ERROR( −20555 , ’Va t e f a i r e . . . ’ ) ;
5 END;
6 /

Dé c l e n c h e u r c r é é .

SQL> SELECT COUNT( ∗ )


2 FROM CLIENT ;

50
COUNT( ∗ )
−−−−−−−−−−
21

SQL> DELETE FROM CLIENT ;


DELETE FROM CLIENT

ERREUR à l a l i g n e 1 :
ORA−20555: Va t e f a i r e . . .
ORA−06512: à ”SCOTT.PASDEDELETEDANSCLIENT” , l i g n e 2
ORA−04088: e r r e u r l o r s d e xé c u t i o n du dé c l e n c h e u r ’SCOTT.PASDEDELETEDANSCLIENT ’

SQL> SELECT COUNT( ∗ )


2 FROM CLIENT ;

COUNT( ∗ )
−−−−−−−−−−
21
L’instruction RAISE APPLICATION ERROR(code, message) lève une exception sans nom portant un code
code et un message d’erreur message. Vous remarquer que comme l’erreur a été levée avant la suppression,
les données sont toujours présentes dans la table CLIENT. Le trigger a contrôlé une règle, et comme ette
n’était pas respectée, il a lancé une erreur.

Accès 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édiaire des deux variables structurées old et new.

Attention !
Il est impossible, dans un trigger de type FOR EACH ROW de faire un SELECT sur la table en cours de
modification.
SQL> CREATE OR REPLACE TRIGGER b e f o r e S t a t e m e n t
2 BEFORE UPDATE ON CLIENT
3 DECLARE
4 NB NUMBER;
5 BEGIN
6 SELECT COUNT( ∗ ) INTO NB
7 FROM CLIENT ;
8 END;
9 /

Dé c l e n c h e u r c r é é .

SQL>
SQL> CREATE OR REPLACE TRIGGER a f t e r S t a t e m e n t
2 AFTER UPDATE ON CLIENT
3 DECLARE
4 NB NUMBER;
5 BEGIN
6 SELECT COUNT( ∗ ) INTO NB
7 FROM CLIENT ;
8 END;

51
9 /

Dé c l e n c h e u r c r é é .

SQL>
SQL> UPDATE CLIENT SET n o m c l i = n o m c l i ;

21 l i g n e ( s ) mise ( s ) à j o u r .

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é c l e n c h e u r c r é é .

SQL>
SQL> UPDATE CLIENT SET n o m c l i = n o m c l i ;
UPDATE CLIENT SET n o m c l i = n o m c l i

ERREUR à l a l i g n e 1 :
ORA−04091: l a table SCOTT. CLIENT e s t en mutation ; l e dé c l e n c h e u r ou l a
f o n c t i o n ne peut l a v o i r
ORA−06512: à ”SCOTT.BEFOREFOREACHROW” , l i g n e 4
ORA−04088: e r r e u r l o r s d e xé c u t i o n du dé c l e n c h e u r ’SCOTT.BEFOREFOREACHROW’

SQL> DROP TRIGGER beforeForEachRow ;

Dé c l e n c h e u r supprimé .

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é c l e n c h e u r c r é é .

SQL>

52
SQL> UPDATE CLIENT SET n o m c l i = n o m c l i ;
UPDATE CLIENT SET n o m c l i = n o m c l i

ERREUR à l a l i g n e 1 :
ORA−04091: l a table SCOTT. CLIENT e s t en mutation ; l e dé c l e n c h e u r ou l a
f o n c t i o n ne peut l a v o i r
ORA−06512: à ”SCOTT.AFTERFOREACHROW” , l i g n e 4
ORA−04088: e r r e u r l o r s d e xé c u t i o n du dé c l e n c h e u r ’SCOTT.AFTERFOREACHROW’

53
Chapitre 2

Exercices

2.1 Contraintes déclaratives


Soit le script de création de table suivant :
CREATE TABLE PRODUIT
(numprod number,
nomprod varchar2(30));

CREATE TABLE FOURNISSEUR


(numfou number,
nomfou varchar2(30));

CREATE TABLE PROPOSER


(numfou number,
numprod number,
prix number);

CREATE TABLE LIVRAISON


(numfou number,
numli number,
dateli date default sysdate
);

CREATE TABLE DETAILLIVRAISON


(numfou number,
numli number,
numprod number,
qte number);
Le numéro de livraison est une clé secondaire, c’est-à-dire un numéro unique pour un fournisseur donné.

Exercice 1
Modifiez le script de façon à ce que les saisies des valeurs suivantes soit obligatoire :
– Le prix des articles proposés
– La quantité des produits livrés

Exercice 2
Repérez les colonnes, couples de colonnes, voire triplets de colonnes, à choisir comme clés primaires.
Modifiez le script de façon à ce que cela se fasse.

54
Exercice 3
Faites de même pour les clés étrangères, sans oublier qu’il ne peut figurer dans une livraison que des
produits proposés par le fournisseur qui effectue cette livraison.

Exercice 4
Insérez quelques lignes dans chaque table.

Exercice 5
Repérez toutes les contraintes des questions précédentes dans user constraints, supprimez-les.

Exercice 6
Redéfinissez toutes ces contraintes avec la syntaxe ALTER TABLE

55
2.2 Requêtes monotabulaires
Nous souhaitons gérer un secrétatiat pédagogique, les modules sont répertoriés dans une table, et les
modules pré-requis pour s’y inscrire (avec la note minimale) se trouvent dans la table prerequis. Une
ligne de la table PREREQUIS nous indique que pour s’inscrire dans le module numéro numMod, il faut avoir
eu au moins noteMin au module numModPrereq.

CREATE TABLE MODULE


(numMod number primary key,
nomMod varchar2(30)
);

CREATE TABLE PREREQUIS


(
numMod number references MODULE(numMod),
numModPrereq number references MODULE(numMod),
noteMin number(2) DEFAULT 10 NOT NULL ,
PRIMARY KEY(numMod, numModPrereq)
);

INSERT INTO MODULE VALUES (1, ’Oracle’);


INSERT INTO MODULE VALUES (2, ’C++’);
INSERT INTO MODULE VALUES (3, ’C’);
INSERT INTO MODULE VALUES (4, ’Algo’);
INSERT INTO MODULE VALUES (5, ’Merise’);
INSERT INTO MODULE VALUES (6, ’PL/SQL Oracle’);
INSERT INTO MODULE VALUES (7, ’mySQL’);
INSERT INTO MODULE VALUES (8, ’Algo avancée’);

INSERT INTO PREREQUIS (numMod, numModPrereq) VALUES (1, 5);


INSERT INTO PREREQUIS (numMod, numModPrereq) VALUES (2, 3);
INSERT INTO PREREQUIS VALUES (6, 1, 12);
INSERT INTO PREREQUIS (numMod, numModPrereq) VALUES (6, 5);
INSERT INTO PREREQUIS (numMod, numModPrereq) VALUES (8, 5);
INSERT INTO PREREQUIS (numMod, numModPrereq) VALUES (7, 5);

Les sorties générées par les deux premières questions sont données. Après, ça sera à vous de vérifier si les
résultats de vos requêtes est cohérent ou non.

Exercice 1
Afficher la liste des noms des modules.

Oracle
C++
C
Algo
Merise
PL/SQL Oracle
mySQL
Algo avancé

8 ligne(s) sélectionnée(s).

56
Exercice 2
Afficher la liste des numéros des modules prerequis pour d’autres modules.

1
3
5

3 ligne(s) sélectionnée(s).

Exercice 3
En utilisant le résultat de la requête précédente, et l’opérateur IN, affichez les noms de ces trois modules.

Exercice 4
Augmentez les notesMin nécessaires pour s’inscrire en ’Algo avancé’ de deux points. Celles nécessaires
pour aller en ’PL/SQL Oracle’ d’un point.

Exercice 5
Affichez, par ordre de noteMin croissantes, les numéros des modules nécessaires pour accéder au module
’PL/SQL Oracle’.

Exercice 6
Affichez les numéros des modules dans lequels je ne peux pas m’inscrire avec 10 en merise.

Exercice 7
Affichez les noms de tous les modules dont le libellé contient les mots ’Algo’ ou ’SQL’.

Exercice 8
On définit pour les questions suivantes les tables

CREATE TABLE INTERVALLE


(borneInf NUMBER,
borneSup NUMBER,
PRIMARY KEY (borneInf, borneSup));

CREATE TABLE RECTANGLE


(xHautGauche NUMBER,
yHautGauche NUMBER,
xBasDroit NUMBER,
yBasDroit NUMBER,
PRIMARY KEY (xHautGauche, yHautGauche, xBasDroit, yBasDroit));

INSERT INTO INTERVALLE VALUES (2, 56);


INSERT INTO INTERVALLE VALUES (12, 30);
INSERT INTO INTERVALLE VALUES (2, 3);
INSERT INTO INTERVALLE VALUES (12, 3);
INSERT INTO INTERVALLE VALUES (8, 27);
INSERT INTO INTERVALLE VALUES (34, 26);
INSERT INTO INTERVALLE VALUES (5, 10);
INSERT INTO INTERVALLE VALUES (7, 32);

57
INSERT INTO INTERVALLE VALUES (0, 30);
INSERT INTO INTERVALLE VALUES (21, 8);

INSERT INTO RECTANGLE VALUES (2, 12, 5, 7);


INSERT INTO RECTANGLE VALUES (2, 12, 1, 13);
INSERT INTO RECTANGLE VALUES (10, 13, 1, 11);
INSERT INTO RECTANGLE VALUES (10, 13, 10, 11);
INSERT INTO RECTANGLE VALUES (2, 7, 5, 13);
INSERT INTO RECTANGLE VALUES (21, 73, 15, 22);
INSERT INTO RECTANGLE VALUES (1, 2, 3, 4);
INSERT INTO RECTANGLE VALUES (1, 5, 3, 2);
INSERT INTO RECTANGLE VALUES (1, 6, 3, 6);
INSERT INTO RECTANGLE VALUES (4, 2, 1, 4);
INSERT INTO RECTANGLE VALUES (2, 3, 4, 0);
INSERT INTO RECTANGLE VALUES (5, 4, 2, 1);

La table INTERVALLE contient des intervalles spécifiés par leurs bornes inférieure et supérieure. Supprimer
de la table intervalle tous les intervalles qui n’en sont pas avec une seule instruction.

Exercice 9
La table RECTANGLE contient des rectangles spécifiés par les coordonnées de deux sommets diamétralement
opposés, leurs arêtes sont parallèles aux axes. Certains rectangles ont des coordonnées erronnées, c’est-à
dire que soit ils sont des segments, soit les coordonnées de certains points ne sont pas dans le bon ordre.
Supprimez, avec une seule instruction, tous les rectangles-segments.

Exercice 10
Affichez tous les intervalles contenant la valeur 10.

Exercice 11
Afficher tous les intervalles qui contiennent [5, 7]. Puis tous les intervalles contenus dans [5, 35]. Puis tous
les intervalles ayant une intersection non vide avec [15, 20].

Exercice 12
Certains des rectangles sont pathologiques, dans le sens où les valeurs des coordonnées font que l’on n’a
pas un point en haut à gauche et un en bas à droite. Afficher à ces rectangles.

Exercice 13
Certains rectangles mal définis peuvent être réparés si on permute les valeurs de xHautGauche et de
xBasDroit et/ou celles de yHautGauche et de yBasDroit. Faites-le avec deux instructions UPDATE.

Exercice 14
Soit le point de coordonnées (x, y) = (2, 2), afficher les coordonnées des rectangles qui contiennent ce
point.

Exercice 15
Afficher tous les rectangles ayant une intersection non vide avec le rectangle (4, 9, 5, 10).

58
2.3 Requêtes multitabulaires
Reprenons pour ce tp la base de donées du tp sur les contraintes :

CREATE TABLE PRODUIT


(numprod number,
nomprod varchar2(30));

CREATE TABLE FOURNISSEUR


(numfou number,
nomfou varchar2(30));

CREATE TABLE PROPOSER


(numfou number,
numprod number,
prix number NOT NULL);

CREATE TABLE LIVRAISON


(numfou number,
numli number,
dateli date default sysdate
);

CREATE TABLE DETAILLIVRAISON


(numfou number,
numli number,
numprod number,
qte number NOT NULL);

alter table produit add constraint pk_produit


PRIMARY KEY (numprod);
alter table fournisseur add constraint pk_fournisseur
PRIMARY KEY (numfou);
alter table proposer add constraint pk_proposer
PRIMARY KEY (numfou, numprod);
alter table livraison add constraint pk_livraison
PRIMARY KEY (numfou, numli);
alter table detaillivraison add constraint pk_detail_livraison
PRIMARY KEY (numfou, numli, numprod);
alter table proposer add constraint fk_proposer_fournisseur
FOREIGN KEY (numfou) REFERENCES fournisseur (numfou);
alter table proposer add constraint fk_proposer_produit
FOREIGN KEY (numprod) REFERENCES produit (numprod);
alter table livraison add constraint fk_livraison
FOREIGN KEY (numfou) REFERENCES fournisseur (numfou);
alter table detaillivraison add constraint fk_detail_livraison
FOREIGN KEY (numfou, numli) REFERENCES livraison (numfou, numli);
alter table detaillivraison add constraint fk_detail_livraison_proposer
FOREIGN KEY (numfou, numprod) REFERENCES proposer (numfou, numprod);

INSERT INTO PRODUIT values (1, ’Roue de secours’);


INSERT INTO PRODUIT values (2, ’Poupée Batman’);
INSERT INTO PRODUIT values (3, ’Cotons tiges’);
INSERT INTO PRODUIT values (4, ’Cornichons’);

59
INSERT INTO FOURNISSEUR values (1, ’f1’);
INSERT INTO FOURNISSEUR values (2, ’f2’);
INSERT INTO FOURNISSEUR values (3, ’f3’);
INSERT INTO FOURNISSEUR values (4, ’f4’);

INSERT INTO PROPOSER values (1, 1, 200);


INSERT INTO PROPOSER values (1, 2, 15);
INSERT INTO PROPOSER values (2, 2, 1);
INSERT INTO PROPOSER values (3, 3, 2);

INSERT INTO LIVRAISON (numfou, numli) values (1, 1);


INSERT INTO LIVRAISON (numfou, numli) values (1, 2);
INSERT INTO LIVRAISON (numfou, numli) values (3, 1);

INSERT INTO DETAILLIVRAISON values (3, 1, 3, 10);


INSERT INTO DETAILLIVRAISON values (1, 1, 1, 25);
INSERT INTO DETAILLIVRAISON values (1, 1, 2, 20);
INSERT INTO DETAILLIVRAISON values (1, 2, 1, 15);
INSERT INTO DETAILLIVRAISON values (1, 2, 2, 17);

Exercice 1
Afficher tous les noms des produits dont le numéro a une occurence dans la table PROPOSER.
NOMPROD
------------------------------
Cotons tiges
Poupée Batman
Roue de secours

Exercice 2
Afficher tous les noms des fournisseurs dont le numéro a une occurence dans la table PROPOSER.

NOMFOU
------------------------------
f1
f2
f3

Exercice 3
Afficher les noms des fournisseurs avec pour chaque fournisseur la liste des produits proposés.
NOMFOU NOMPROD
------------------------------ ------------------------------
f1 Roue de secours
f1 Poupée Batman
f2 Poupée Batman
f3 Cotons tiges

Exercice 4
Afficher les nom des fournisseurs proposant des ’Poupées Batman’ par ordre de prix croissant.

60
Exercice 5
Afficher les dates des livraisons effectuées par le fournisseur ’f1’ ;

Exercice 6
Afficher les noms de tous les produits déjà livrés par le fournisseur ’f3’ ;

Exercice 7
Afficher toutes les lignes de la table LIVRAISON correspondant à des livraisons dans lesquelles figure le
produit ’Poupée Batman’.

Exercice 8
Pour les exercices suivants, nous travaillerons sur les données suivantes,

CREATE TABLE PERSONNE


(numpers number PRIMARY KEY,
nom varchar2(30) NOT NULL,
prenom varchar2(30),
pere REFERENCES PERSONNE(numpers),
mere REFERENCES PERSONNE(numpers)
);

INSERT INTO PERSONNE VALUES (1, ’de Montmirail, dit le Hardi’, ’Godefroy’, NULL, NULL);
INSERT INTO PERSONNE VALUES (16, ’ET’, NULL, NULL, NULL);
INSERT INTO PERSONNE VALUES (2, ’Le Croquant’, ’Jacqou’, 1, 16);
INSERT INTO PERSONNE VALUES (3, ’La Fripouille’, ’Jacqouille’, 1, 16);
INSERT INTO PERSONNE VALUES (4, ’Bush’, ’Kate’, NULL, NULL);
INSERT INTO PERSONNE VALUES (13, ’Granger’, ’Hermione’, NULL, NULL);
INSERT INTO PERSONNE VALUES (5, ’Du Fémur’, ’Médor’, 3,4 );
INSERT INTO PERSONNE VALUES (12, ’Kobalevskaı̈a’, ’Sofia’, NULL, NULL);
INSERT INTO PERSONNE VALUES (6, ’Rieu’, ’André’, NULL, NULL);
INSERT INTO PERSONNE VALUES (7, ’Bontoutou’, ’Rex’, 6, 4);
INSERT INTO PERSONNE VALUES (8, ’Dijkstra’, ’Edvard’, 2, 13);
INSERT INTO PERSONNE VALUES (9, ’Leibniz’, ’Gottfrie1d Wilhem’, 8, 12);
INSERT INTO PERSONNE VALUES (10, ’Bach’, ’Johann Sebastien’, 5, 12);
INSERT INTO PERSONNE VALUES (17, ’Mathieu’, ’Mireille’, NULL, NULL);
INSERT INTO PERSONNE VALUES (11, ’Lemarchal’, ’Gregory’, 10, 17);
INSERT INTO PERSONNE VALUES (15, ’Socrate’, NULL, 3, 13);
INSERT INTO PERSONNE VALUES (19, ’Leroy’, ’Nolwen’, NULL, NULL);
INSERT INTO PERSONNE VALUES (20, ’Bartoli’, ’Jennifer’, 9, 19);
INSERT INTO PERSONNE VALUES (21, ’Fabian’, ’Lara’, 10, 17);
INSERT INTO PERSONNE VALUES (14, ’Stone’, ’Sharon’, 15, 20);
INSERT INTO PERSONNE VALUES (18, ’Frege’, ’Elodie’, 7, 13);

Le champ pere contient le numéro du père de la personne, le champ mere contient le numéro de la mère
de la personne. Dans les questions où il vous est demandé de formuler des requêtes retournant plusieurs
personne, il faut qu’il y ait une ligne par personne. Afficher les noms et prénoms des enfants de Sofia
Kobalevskaı̈a.
NOM PRENOM
------------------------------ ------------------------------
Leibniz Gottfried Wilhem
Bach Johann Sebastien

61
Exercice 9
Afficher les noms et prénoms des parents de Edvard Dijkstra.
NOM PRENOM
------------------------------ ------------------------------
Jacqou Le Croquant
Granger Hermione

Exercice 10
Afficher les noms et prénoms des enfants de jean-Sebastien Bach et Mireille Mathieu.

Exercice 11
Afficher les noms et prénoms du frère de Jacqouille la Fripouille.

Exercice 12
Afficher les noms et prénoms du cousin germain de Dijkstra du coté de son père.

Exercice 13
Afficher les noms et prenoms du demi-frère (du coté de sa mère) du père de Lara Fabian.

Exercice 14
Afficher les noms et prénoms des pères des enfants de Kate Bush.

Exercice 15
Afficher les noms et prénoms du neveu de Jacqou le Croquant.

Exercice 16
Afficher les noms et prénoms de la mère du fils du fils d’André Rieu.

Exercice 17
Afficher les noms et prénoms des parents et grand-parents de Sharon Stone.
NOM PRENOM
------------------------------ ------------------------------
Bartoli Jennifer
Granger Hermione
La Fripouille Jacqouille
Leibniz Gottfrie1d Wilhem
Leroy Nolwen
Socrate

6 ligne(s) sélectionnée(s).
N’oubliez pas : une ligne par personne.

62
2.4 Agrégation de données
Nous utiliserons pour ce tp les données suivantes :

CREATE TABLE PRODUIT


(numprod number,
nomprod varchar2(30));

CREATE TABLE FOURNISSEUR


(numfou number,
nomfou varchar2(30));

CREATE TABLE PROPOSER


(numfou number,
numprod number,
prix number NOT NULL);

CREATE TABLE LIVRAISON


(numfou number,
numli number,
dateli date default sysdate
);

CREATE TABLE DETAILLIVRAISON


(numfou number,
numli number,
numprod number,
qte number NOT NULL);

alter table produit add constraint pk_produit


PRIMARY KEY (numprod);
alter table fournisseur add constraint pk_fournisseur
PRIMARY KEY (numfou);
alter table proposer add constraint pk_proposer
PRIMARY KEY (numfou, numprod);
alter table livraison add constraint pk_livraison
PRIMARY KEY (numfou, numli);
alter table detaillivraison add constraint pk_detail_livraison
PRIMARY KEY (numfou, numli, numprod);
alter table proposer add constraint fk_proposer_fournisseur
FOREIGN KEY (numfou) REFERENCES fournisseur (numfou);
alter table proposer add constraint fk_proposer_produit
FOREIGN KEY (numprod) REFERENCES produit (numprod);
alter table livraison add constraint fk_livraison
FOREIGN KEY (numfou) REFERENCES fournisseur (numfou);
alter table detaillivraison add constraint fk_detail_livraison
FOREIGN KEY (numfou, numli) REFERENCES livraison (numfou, numli);
alter table detaillivraison add constraint fk_detail_livraison_proposer
FOREIGN KEY (numfou, numprod) REFERENCES proposer (numfou, numprod);

INSERT INTO PRODUIT values (1, ’Roue de secours’);


INSERT INTO PRODUIT values (2, ’Poupée Batman’);
INSERT INTO PRODUIT values (3, ’Cotons tiges’);
INSERT INTO PRODUIT values (4, ’Cornichons’);

63
INSERT INTO FOURNISSEUR values (1, ’f1’);
INSERT INTO FOURNISSEUR values (2, ’f2’);
INSERT INTO FOURNISSEUR values (3, ’f3’);
INSERT INTO FOURNISSEUR values (4, ’f4’);

INSERT INTO PROPOSER values (1, 1, 200);


INSERT INTO PROPOSER values (1, 2, 15);
INSERT INTO PROPOSER values (2, 2, 1);
INSERT INTO PROPOSER values (3, 3, 2);

INSERT INTO LIVRAISON (numfou, numli) values (1, 1);


INSERT INTO LIVRAISON (numfou, numli) values (1, 2);
INSERT INTO LIVRAISON (numfou, numli) values (3, 1);

INSERT INTO DETAILLIVRAISON values (3, 1, 3, 10);


INSERT INTO DETAILLIVRAISON values (1, 1, 1, 25);
INSERT INTO DETAILLIVRAISON values (1, 1, 2, 20);
INSERT INTO DETAILLIVRAISON values (1, 2, 1, 15);
INSERT INTO DETAILLIVRAISON values (1, 2, 2, 17);

Amusez-vous bien !

Exercice 1
Donner le nombre de fournisseurs.

Exercice 2
Donner le nombre de fournisseurs ayant déjà effectué une livraison.

Exercice 3
Quel est le prix du produit proposé au prix le plus élevé par ’f1’ ?

Exercice 4
Combien de produits sont proposés pour chaque fournisseur proposant au moins un produit ?

Exercice 5
Afficher le nombre de produits qui ne sont proposés par aucun fournisseur.

Exercice 6
Afficher, pour chaque produit (dont on affichera le nom), le nombre de fournisseurs l’ayant déjà livré.

Exercice 7
Donner pour chaque livraison le nom du fournisseur, le numero de livraison et le nombre de produits
livrés.

Exercice 8
Donner pour chaque livraison le nom du fournisseur, le numero de livraison, la date et le montant de la
facture.

64
Exercice 9
Donner les noms des produits qui ne sont proposés que par un seul fournisseur.

Exercice 10
Donner les noms des fournisseurs qui ont livré au moins une fois chaque produit qu’ils proposent.

65
2.5 Vues
Nous utiliserons pour ce tp les mêmes données que dans le tp précédent. N’hésitez pas, pour tester vos
requêtes, à insérer d’autres données dans la base.

Exercice 1
Créez une vue affichant pour chaque produit ayant déjà été livré le numéro du produit et la somme des
quantités livrées (toutes livraisons confondues).

Exercice 2
Affichez la quantité totale livrée du produit dont la quantité totale livrée est la plus élevée.

Exercice 3
Créez une vue affichant pour chaque livraison, le montant de la facture.

Exercice 4
Créez une vue affichant pour chaque fournisseur, le total des factures sur toutes les livraisons.

Exercice 5
Affichez le total des factures du fournisseurs dont le total des factures est le moins élevé.

Exercice 6
Affichez le nombre de produits distincts livrés par le fournisseur ayant livré le plus de produits distincts.
Par nombre de produits distincts, on entend sans tenir compte de la quantité.

66
2.6 Requêtes imbriquées
Nous utiliserons pour ce tp les données du tp précédant le tp précédent. Presque tous les stratagèmes sont
autorisés, vous pouvez utiliser des fonctions d’agrégation, des vues, et des requêtes imbriquées partout
sauf dans le FROM (ça sera l’objet du cours suivant). Bon courage, l’aspirine n’est pas fournie.

Exercice 1
Donner, pour chaque fournisseur (afficher son nom), le nombre de produits proposés, même si ce fournis-
seur n’en propose aucun. Il est interdit d’utiliser OUTER JOIN !

Exercice 2
Afficher les noms des fournisseurs qui proposent le produit numéro 2, il est interdit de faire des jointures !

Exercice 3
Afficher les noms des fournisseurs qui proposent des poupées Batman.

Exercice 4
Afficher les noms des fournisseurs qui ont déjà livré des poupées Batman.

Exercice 5
Quels sont les noms des fournisseurs qui ont déjà livré tous leurs produits au moins une fois ?

Exercice 6
Donner, pour chaque fournisseur (afficher son nom), le produit proposé au prix le plus élevé.

Exercice 7
Pour chaque produit p, quel sont les noms des fournisseurs qui, sur toutes ses livraisons, ont livré la plus
grande quantité cumulée de produits p.

Exercice 8
¡Afficher le nombre de produits proposés par les fournisseurs proposant le moins de produits. Norma-
lement, un 0 devrait s’afficher... Pas un 1.

Exercice 9
Afficher le(s) nom(s) du(des) fournisseur(s) proposant le moins de produits.

Exercice 10
Afficher, pour chaque produit, le(s) nom(s) du(des) fournisseur(s) qui l’a(ont) le plus livré (en quantité
cumulée).

67
2.7 Compléments sur les types
Nous utiliserons pour ce tp les mêmes données que dans le tp précédent.

Exercice 1
Rendez, à l’aide de contraintes de type CHECK les saisies des champs qte, prix et dateli oligatoires.

Exercice 2
Empêchez la saisie de prix négatifs ou nuls et de quantités négatives ou nulles.

Exercice 3
On sait que la base a été créée vers le mois d’Octobre 2006, empêchez l’ajout de livraisons antérieures à
ce mois.

Exercice 4
Implémentez une contrainte déclarative empêchant les livraisons les premiers mai de chaque année.

Exercice 5
Implémentez une contrainte déclarative obligeant les noms des produits à commencer par une majuscule
et à ne comporter ensuite sur des minuscules. Si l’ajout d’une des contraintes est refusée, demandez vous
pourquoi et faites le nécessaire (une commande UPDATE sera la bienvenue...) pour y remédier.

68
2.8 Révisions
Nous utiliserons pour ce tp les mêmes données que dans le tp précédent.

Exercice 1
Donner le nombre de fournisseurs ayant effectué un nombre de livraisons supérieur au égal à deux.

Exercice 2
Quelles sont les années pendant lesquelles le plus de livraisons ont été effectuées ?

Exercice 3
Parmi les fournisseurs qui ont livré au moins une fois chaque produit qu’ils proposent, quels sont les
derniers à avoir effectué une livraison.

69
2.9 Examen Type
Soit les données suivantes :
– ETUDIANT(numEtud, nom, prenom, datenaiss, civilite, patronyme, numsecu)
Répertorie les étudiants. Un numéro de sécu comporte 15 chiffres.
– MODULE(codMod, nomMod, effecMax)
Répertorie les modules
– EXAMEN(codMod, codeExam, dateExam)
CodeExam numérote les examens à l’intérieur de chaque module.
– INSCRIPTION(numEtud, codMmod, dateInsc)
Inscription d’un élève à un module.
– RESULTAT(numEtud, codMmod, CodeExam, note)
Résultat de l’étudiant numEtud à l’examen (codMod, codeExam).
– PREREQUIS(codMod, codeModPrereq, noteMin)
Pour s’inscrire au module codMod il est nécessaire d’avoir eu au moins la note noteMin au module
numéro codeModPrereq.

Exercice 1 - CREATE TABLE


Ecrire les CREATE TABLE correspondant à ces données, sans les contraintes. Choisissez les types judicieu-
sement.

Exercice 2 - Contraintes de clé


1. Localiser les clés primaires, les déclarer avec des ordres ALTER TABLE.
2. Faire de même avec les clés étrangères.

Exercice 3 - Contraintes d’attributs


Comment modifier le script de création de tables pour
1. forcer la saisie de noteMin dans la table PREREQUIS.
2. forcer la saisie du numéro de sécurité sociale
3. mettre l’effectif maximum d’un Module à 30 par défaut.
4. obliger la civilité à être une des trois valeurs Mr, Mme, Mlle
5. empêcher la saisie d’un patronyme si l’étudiant n’est pas de sexe féminin.
6. vérifier si le numéro de sécurité sociale comporte bien 15 chiffres
7. vérifier que le premier chiffre du numéro de sécurité sociale est est 1 si l’étudiant est de sexe masculin,
2 s’il est de sexe féminin.
8. vérifier si les deuxième et troisième chiffres correspondent bien à l’année de naissance.
9. Est-il possible de contrôler avec des contraintes déclaratives si l’effectif maximum dans un module
n’est pas dépassé.

Exercice 4 - Manipulation des données


On ne sait pas si la base de données est vide ou non. Vous placerez des sous-requêtes dans les ordres
suivants pour vous assurer que les modifications ou insertions ne seront pas refusés.
1. Insérer un élève appelé JosephF ourier.
2. Créer un module M aths
3. Inscrire JosephF ourier en M aths.
4. Créer un examen de M aths le deux janvier 2006.
5. Donner à JosephF ourier un 19 à cet examen.
6. Modifier la note précédente pour l’amener à 20.

70
Exercice 5 - Requêtes
Vous n’hésiterez pas à ajouter des données pour tester la validité de vos requêtes. Si un étudiant a eu
plusieurs notes à un même module, sa note définitive est la plus élevée.
1. Liste des noms des étudiants.
2. Liste des noms des étudiants inscrits en maths.
3. Liste des noms des étudiants avec leur note (définitive) de maths.
4. Liste des noms des étudiants ayant validé leur examen de maths.
5. Liste des noms des étudiants n’ayant pas passé leur examen de maths.
6. Le(s) nom(s) de(s) (l’)étudiant(s) ayant eu la meilleure note en maths.
7. Le(s) nom(s) de(s) (l’)étudiant(s) dont la note la plus basse est la plus élevée.
8. Les noms des modules dans lesquels peut s’inscrire JosephF ourier.

71
2.10 Introduction au PL/SQL
Exercice 1
Ecrivez un programme affectant les valeurs 1 et 2 à deux variables a et b, puis permutant les valeurs de
ces deux variables.

Exercice 2
Ecrivez un programme plaçant la valeur 10 dans une variable a, puis affichant la factorielle de a.

Exercice 3
Ecrivez un programme plaçant les valeurs 48 et 84 dans deux variables a et b puis affichant le pgcd de a
et b.

72
2.11 Tableaux et Structures
Exercice 1
1. Créez un type tableau pouvant contenir jusqu’à 50 entiers.
2. Créez une variable de ce type , faites une allocation dynamique et dimensionnez ce tableau à 20
emplacements.
3. Placez dans ce tableau la liste des 20 premiers carrés parfaits : 1, 4, 9, 16, 25, . . .
4. Inversez l’ordre des éléments du tableau
5. Affichez le tableau.

Exercice 2
Triez le tableau précédent avec la méthode du tri à bulle.

Exercice 3
Recherchez, par dichotomie, si l’élément 225 se trouve dans le tableau.

Exercice 4
On implémente des listes chaı̂nées avec des tableaux de la sorte,

SET SERVEROUTPUT ON
DECLARE
-- Maillon d’une liste cha^ ınée
TYPE CELL IS RECORD
(
-- Donnée de chaque maillon
data INTEGER,
-- Indice du maillon précédent 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 élément de la liste
first integer;
-- indice du dernier élément 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;

73
first := 1;
last := 19;
t(first).previous := -1;
t(last).next := -1;

-- 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 éléments de la liste, sans changer les indices des maillons (seulement en modifiant le
chaı̂nage).

Exercice 5
Utilisez le tri à bulle pour remettre les éléments dans l’ordre. Les indications sont les mêmes : ne déplacez
pas les maillons, vous n’avez le droit de toucher qu’au chaı̂nage. Bon courage, l’aspirine n’est pas fournie.

74
2.12 Applications du PL/SQL
Nous travaillerons sur les données suivantes :

DROP TABLE COMPTECLIENT;


DROP TABLE OPERATION;
DROP TABLE TYPECCL;
DROP TABLE TYPEOPERATION;
DROP TABLE PERSONNEL;
DROP TABLE CLIENT;

CREATE TABLE CLIENT


(numcli number,
nomcli varchar2(30),
prenomcli varchar2(30),
adresse varchar2(60),
tel varchar(10)
);

CREATE TABLE PERSONNEL


(numpers number,
nompers varchar2(30),
prenompers varchar2(30),
manager number,
salaire number
);

CREATE TABLE TYPECCL


(numtypeccl number,
nomtypeccl varchar2(30)
);

CREATE TABLE COMPTECLIENT


(numcli number,
numccl number,
numtypeccl number,
dateccl date default sysdate not null,
numpers number
);

CREATE TABLE TYPEOPERATION


(numtypeoper number,
nomtypeoper varchar2(30)
);

CREATE TABLE OPERATION


(numcli number,
numccl number,
numoper number,
numtypeoper number,
dateoper date default sysdate not null,
montantoper number not null,
libeloper varchar2(30)
);

75
ALTER TABLE CLIENT ADD
(
CONSTRAINT pk_client PRIMARY KEY (numcli),
CONSTRAINT ck_telephone CHECK(LENGTH(tel)=10)
);

ALTER TABLE PERSONNEL ADD


(
CONSTRAINT pk_personnel PRIMARY KEY (numpers),
CONSTRAINT ck_salaire CHECK(SALAIRE >= 1254.28)
);

ALTER TABLE TYPECCL ADD


CONSTRAINT pk_typeccl PRIMARY KEY (numtypeccl);

ALTER TABLE TYPEOPERATION ADD


CONSTRAINT pk_typeoperation PRIMARY KEY (numtypeoper);

ALTER TABLE COMPTECLIENT ADD


(
CONSTRAINT pk_compteclient
PRIMARY KEY (numcli, numccl),
CONSTRAINT fk_ccl_typeccl
FOREIGN KEY (numtypeccl)
REFERENCES TYPECCL (numtypeccl),
REFERENCES CLIENT (numcli),
CONSTRAINT fk_ccl_client
FOREIGN KEY (numcli)
CONSTRAINT fk_ccl_personnel
FOREIGN KEY (numpers)
REFERENCES PERSONNEL (numpers)
);

ALTER TABLE COMPTECLIENT ADD


(
CONSTRAINT pk_compteclient
PRIMARY KEY (numcli, numccl),
CONSTRAINT fk_ccl_typeccl
FOREIGN KEY (numtypeccl)
REFERENCES TYPECCL (numtypeccl),
CONSTRAINT fk_ccl_client
FOREIGN KEY (numcli)
REFERENCES CLIENT (numcli),
CONSTRAINT fk_ccl_personnel
FOREIGN KEY (numpers)
REFERENCES PERSONNEL (numpers)
);

ALTER TABLE OPERATION ADD


(
CONSTRAINT pk_operation
PRIMARY KEY (numcli, numccl, numoper),
CONSTRAINT fk_oper_ccl
FOREIGN KEY (numcli, numoper)

76
REFERENCES COMPTECLIENT (numcli, numccl),
CONSTRAINT fk_oper_codeoper
FOREIGN KEY (numtypeoper)
REFERENCES typeoperation (numtypeoper),
CONSTRAINT montant_operation
CHECK(montantoper <> 0)
);

INSERT INTO TYPECCL VALUES (


(SELECT nvl(MAX(numtypeccl), 0) + 1
FROM TYPECCL
),
’Compte courant’);

INSERT INTO TYPECCL VALUES (


(SELECT nvl(MAX(numtypeccl), 0) + 1
FROM TYPECCL
),
’livret’);

INSERT INTO TYPECCL VALUES (


(SELECT nvl(MAX(numtypeccl), 0) + 1
FROM TYPECCL
),
’PEL’);

INSERT INTO TYPEOPERATION VALUES (


(SELECT nvl(MAX(numtypeoper), 0) + 1
FROM TYPEOPERATION
),
’dép^
ot espèces’);

INSERT INTO TYPEOPERATION VALUES (


(SELECT nvl(MAX(numtypeoper), 0) + 1
FROM TYPEOPERATION
),
’prélèvement’);

INSERT INTO TYPEOPERATION VALUES (


(SELECT nvl(MAX(numtypeoper), 0) + 1
FROM TYPEOPERATION
),
’virement’);

INSERT INTO TYPEOPERATION VALUES (


(SELECT nvl(MAX(numtypeoper), 0) + 1
FROM TYPEOPERATION
),
’retrait’);

DROP TABLE PERSONNE;

CREATE TABLE PERSONNE


(numpers number PRIMARY KEY,

77
nom varchar2(30) NOT NULL,
prenom varchar2(30),
pere REFERENCES PERSONNE(numpers),
mere REFERENCES PERSONNE(numpers)
);

INSERT INTO PERSONNE VALUES (1, ’de Montmirail, dit le Hardi’, ’Godefroy’, NULL, NULL);
INSERT INTO PERSONNE VALUES (16, ’Canat de Chizy’, ’Edith’, NULL, NULL);
INSERT INTO PERSONNE VALUES (2, ’Le Croquant’, ’Jacqou’, 1, 16);
INSERT INTO PERSONNE VALUES (3, ’La Fripouille’, ’Jacqouille’, 1, 16);
INSERT INTO PERSONNE VALUES (4, ’Bush’, ’Kate’, NULL, NULL);
INSERT INTO PERSONNE VALUES (13, ’Granger’, ’Hermione’, NULL, NULL);
INSERT INTO PERSONNE VALUES (5, ’Du Fémur’, ’Médor’, 3,4 );
INSERT INTO PERSONNE VALUES (12, ’Kobalevskaı̈a’, ’Sofia’, NULL, NULL);
INSERT INTO PERSONNE VALUES (6, ’Rieu’, ’André’, NULL, NULL);
INSERT INTO PERSONNE VALUES (7, ’Bontoutou’, ’Rex’, 6, 4);
INSERT INTO PERSONNE VALUES (8, ’Dijkstra’, ’Edvard’, 2, 13);
INSERT INTO PERSONNE VALUES (9, ’Leibniz’, ’Gottfrie1d Wilhem’, 8, 12);
INSERT INTO PERSONNE VALUES (10, ’Bach’, ’Johann Sebastien’, 5, 12);
INSERT INTO PERSONNE VALUES (17, ’Mathieu’, ’Mireille’, NULL, NULL);
INSERT INTO PERSONNE VALUES (11, ’Lemarchal’, ’Gregory’, 10, 17);
INSERT INTO PERSONNE VALUES (15, ’Socrate’, NULL, 3, 13);
INSERT INTO PERSONNE VALUES (19, ’Leroy’, ’Nolwen’, NULL, NULL);
INSERT INTO PERSONNE VALUES (20, ’Bartoli’, ’Jennifer’, 9, 19);
INSERT INTO PERSONNE VALUES (21, ’Fabian’, ’Lara’, 10, 17);
INSERT INTO PERSONNE VALUES (14, ’Stone’, ’Sharon’, 15, 20);
INSERT INTO PERSONNE VALUES (18, ’Frege’, ’Elodie’, 7, 13);

COMMIT;

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équence de nombres de
1 à 21. Utilisez une boucle dans laquelle vous placerez une requête pour recopier les couples nom/prénom
de la table personne dans la table CLIENT.

Exercice 2
Ecrivez un script récupérant le client de clé primaire la plus élevée, et injectant ce client dans la table
PERSONNEL.

Exercice 3
Ouvrez un compte courant pour chaque personne, effectuez un dépôt en espèce égal à 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.

78
2.13 Exceptions
Nous utiliserons les données suivantes, même si cela annihile le travail de la séance précédente...

DROP TABLE COMPTECLIENT;


DROP TABLE OPERATION;
DROP TABLE TYPECCL;
DROP TABLE TYPEOPERATION;
DROP TABLE PERSONNEL;
DROP TABLE CLIENT;

CREATE TABLE CLIENT


(numcli number,
nomcli varchar2(30),
prenomcli varchar2(30),
adresse varchar2(60),
tel varchar(10)
);

CREATE TABLE PERSONNEL


(numpers number,
nompers varchar2(30),
prenompers varchar2(30),
manager number,
salaire number
);

CREATE TABLE TYPECCL


(numtypeccl number,
nomtypeccl varchar2(30)
);

CREATE TABLE COMPTECLIENT


(numcli number,
numccl number,
numtypeccl number,
dateccl date default sysdate not null,
numpers number
);

CREATE TABLE TYPEOPERATION


(numtypeoper number,
nomtypeoper varchar2(30)
);

CREATE TABLE OPERATION


(numcli number,
numccl number,
numoper number,
numtypeoper number,
dateoper date default sysdate not null,
montantoper number not null,
libeloper varchar2(30)
);

79
ALTER TABLE CLIENT ADD
(
CONSTRAINT pk_client PRIMARY KEY (numcli),
CONSTRAINT ck_telephone CHECK(LENGTH(tel)=10)
);

ALTER TABLE PERSONNEL ADD


(
CONSTRAINT pk_personnel PRIMARY KEY (numpers),
CONSTRAINT ck_salaire CHECK(SALAIRE >= 1254.28)
);

ALTER TABLE TYPECCL ADD


CONSTRAINT pk_typeccl PRIMARY KEY (numtypeccl);

ALTER TABLE TYPEOPERATION ADD


CONSTRAINT pk_typeoperation PRIMARY KEY (numtypeoper);

ALTER TABLE COMPTECLIENT ADD


(
CONSTRAINT pk_compteclient
PRIMARY KEY (numcli, numccl),
CONSTRAINT fk_ccl_typeccl
FOREIGN KEY (numtypeccl)
REFERENCES TYPECCL (numtypeccl),
CONSTRAINT fk_ccl_client
FOREIGN KEY (numcli)
REFERENCES CLIENT (numcli),
CONSTRAINT fk_ccl_personnel
FOREIGN KEY (numpers)
REFERENCES PERSONNEL (numpers)
);

ALTER TABLE OPERATION ADD


(
CONSTRAINT pk_operation
PRIMARY KEY (numcli, numccl, numoper),
CONSTRAINT fk_oper_ccl
FOREIGN KEY (numcli, numoper)
REFERENCES COMPTECLIENT (numcli, numccl),
CONSTRAINT fk_oper_codeoper
FOREIGN KEY (numtypeoper)
REFERENCES typeoperation (numtypeoper),
CONSTRAINT montant_operation
CHECK(montantoper <> 0 AND montantoper >= -1000 AND montantoper <= 1000)
);

INSERT INTO TYPECCL VALUES (


(SELECT nvl(MAX(numtypeccl), 0) + 1
FROM TYPECCL
),
’Compte courant’);

INSERT INTO TYPECCL VALUES (

80
(SELECT nvl(MAX(numtypeccl), 0) + 1
FROM TYPECCL
),
’livret’);

INSERT INTO TYPECCL VALUES (


(SELECT nvl(MAX(numtypeccl), 0) + 1
FROM TYPECCL
),
’PEL’);

INSERT INTO TYPEOPERATION VALUES (


(SELECT nvl(MAX(numtypeoper), 0) + 1
FROM TYPEOPERATION
),
’dép^
ot espèces’);

INSERT INTO TYPEOPERATION VALUES (


(SELECT nvl(MAX(numtypeoper), 0) + 1
FROM TYPEOPERATION
),
’prélèvement’);

INSERT INTO TYPEOPERATION VALUES (


(SELECT nvl(MAX(numtypeoper), 0) + 1
FROM TYPEOPERATION
),
’virement’);

INSERT INTO TYPEOPERATION VALUES (


(SELECT nvl(MAX(numtypeoper), 0) + 1
FROM TYPEOPERATION
),
’retrait’);

DROP TABLE PERSONNE;

CREATE TABLE PERSONNE


(numpers number PRIMARY KEY,
nom varchar2(30) NOT NULL,
prenom varchar2(30),
pere REFERENCES PERSONNE(numpers),
mere REFERENCES PERSONNE(numpers)
);

INSERT INTO PERSONNE VALUES (1, ’de Montmirail, dit le Hardi’, ’Godefroy’, NULL, NULL);
INSERT INTO PERSONNE VALUES (16, ’Canat de Chizy’, ’Edith’, NULL, NULL);
INSERT INTO PERSONNE VALUES (2, ’Le Croquant’, ’Jacqou’, 1, 16);
INSERT INTO PERSONNE VALUES (3, ’La Fripouille’, ’Jacqouille’, 1, 16);
INSERT INTO PERSONNE VALUES (4, ’Bush’, ’Kate’, NULL, NULL);
INSERT INTO PERSONNE VALUES (13, ’Granger’, ’Hermione’, NULL, NULL);
INSERT INTO PERSONNE VALUES (5, ’Du Fémur’, ’Médor’, 3,4 );
INSERT INTO PERSONNE VALUES (12, ’Kobalevskaı̈a’, ’Sofia’, NULL, NULL);
INSERT INTO PERSONNE VALUES (6, ’Rieu’, ’André’, NULL, NULL);

81
INSERT INTO PERSONNE VALUES (7, ’Bontoutou’, ’Rex’, 6, 4);
INSERT INTO PERSONNE VALUES (8, ’Dijkstra’, ’Edvard’, 2, 13);
INSERT INTO PERSONNE VALUES (9, ’Leibniz’, ’Gottfrie1d Wilhem’, 8, 12);
INSERT INTO PERSONNE VALUES (10, ’Bach’, ’Johann Sebastien’, 5, 12);
INSERT INTO PERSONNE VALUES (17, ’Mathieu’, ’Mireille’, NULL, NULL);
INSERT INTO PERSONNE VALUES (11, ’Lemarchal’, ’Gregory’, 10, 17);
INSERT INTO PERSONNE VALUES (15, ’Socrate’, NULL, 3, 13);
INSERT INTO PERSONNE VALUES (19, ’Leroy’, ’Nolwen’, NULL, NULL);
INSERT INTO PERSONNE VALUES (20, ’Bartoli’, ’Jennifer’, 9, 19);
INSERT INTO PERSONNE VALUES (21, ’Fabian’, ’Lara’, 10, 17);
INSERT INTO PERSONNE VALUES (14, ’Stone’, ’Sharon’, 15, 20);
INSERT INTO PERSONNE VALUES (18, ’Frege’, ’Elodie’, 7, 13);

COMMIT;

Vous êtes invités à modifier le code de la séance précédente. Chaque fois qu’un SELECT ... INTO ...
sera effectué, 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ées des tables CLIENT ne puissent être exécutés qu’une
seule fois.

Exercice 2
Les scripts remplissant la table Operation ne fonctionneront pas aujourd’hui... Même s’il fonctionnaient
la dernière fois. Trouvez les codes d’erreurs des exceptions levées par ces scripts, rattrapez-les de la façon
la plus appropriée qui soit.

82
2.14 Sous-programmes
Exercice 1
Ecrire une fonction récursive retournant bn , avec n entier positif ou nul.

Exercice 2
Améliorer la fonction précédente en utilisant le fait que
n
bn = (b2 ) 2
si n est pair.

Pour les questions suivantes, utilisez ce code :


DROP TABLE PERSONNE;

CREATE TABLE PERSONNE


(numpers number PRIMARY KEY,
nom varchar2(30) NOT NULL,
prenom varchar2(30),
pere REFERENCES PERSONNE(numpers),
mere REFERENCES PERSONNE(numpers)
);

INSERT INTO PERSONNE VALUES (1, ’de Montmirail, dit le Hardi’, ’Godefroy’, NULL, NULL);
INSERT INTO PERSONNE VALUES (16, ’Canat de Chizy’, ’Edith’, NULL, NULL);
INSERT INTO PERSONNE VALUES (2, ’Le Croquant’, ’Jacqou’, 1, 16);
INSERT INTO PERSONNE VALUES (3, ’La Fripouille’, ’Jacqouille’, 1, 16);
INSERT INTO PERSONNE VALUES (4, ’Bush’, ’Kate’, NULL, NULL);
INSERT INTO PERSONNE VALUES (13, ’Granger’, ’Hermione’, NULL, NULL);
INSERT INTO PERSONNE VALUES (5, ’Du Fémur’, ’Médor’, 3,4 );
INSERT INTO PERSONNE VALUES (12, ’Kobalevskaı̈a’, ’Sofia’, NULL, NULL);
INSERT INTO PERSONNE VALUES (6, ’Rieu’, ’André’, NULL, NULL);
INSERT INTO PERSONNE VALUES (7, ’Bontoutou’, ’Rex’, 6, 4);
INSERT INTO PERSONNE VALUES (8, ’Dijkstra’, ’Edvard’, 2, 13);
INSERT INTO PERSONNE VALUES (9, ’Leibniz’, ’Gottfrie1d Wilhem’, 8, 12);
INSERT INTO PERSONNE VALUES (10, ’Bach’, ’Johann Sebastien’, 5, 12);
INSERT INTO PERSONNE VALUES (17, ’Mathieu’, ’Mireille’, NULL, NULL);
INSERT INTO PERSONNE VALUES (11, ’Lemarchal’, ’Gregory’, 10, 17);
INSERT INTO PERSONNE VALUES (15, ’Socrate’, NULL, 3, 13);
INSERT INTO PERSONNE VALUES (19, ’Leroy’, ’Nolwen’, NULL, NULL);
INSERT INTO PERSONNE VALUES (20, ’Bartoli’, ’Jennifer’, 9, 19);
INSERT INTO PERSONNE VALUES (21, ’Fabian’, ’Lara’, 10, 17);
INSERT INTO PERSONNE VALUES (14, ’Stone’, ’Sharon’, 15, 20);
INSERT INTO PERSONNE VALUES (18, ’Frege’, ’Elodie’, 7, 13);

COMMIT;

Exercice 3
Ecrire une fonction demi-freres prenant deux numéros de personnes en paramètre et retournant vrai si et
seulement si ces deux personnes ont un parent en commun.

83
Exercice 4
Ecrire une fonction cousins germains prenant deux numéros de personnes en paramètre et retournant vrai
si et seulement si ces deux deux individus sont cousins germains.

Exercice 5
Ecrire une procédure récursive affichant le nom de la personne dont le numéro est passé en paramètre et
se rappellant récursivement sur le père de cette personne. Faites de sorte à ne pas utiliser d’exceptions.

Exercice 6
Ecrire une procédure récursive affichant les noms des ascendants de sexe masculin de la personne dont le
numéro est passé en paramètre.

Exercice 7
Ecrire une fonction récursive prenant deux numéros de personne A et B et retournant vrai si A est un
ascendant de B.

Exercice 8
Ecrire une fonction prenant en paramètre deux numéros de personne A et B et retournant, si l’un est un
ascendant de l’autre, le nombre de générations les séparant, −1 si l’un n’est pas un ascendant de l’autre.

Exercice 9
Préparez un verre d’aspirine et écrivez une requête retournant le(s) couples(s) personnes séparées par le
plus de générations.

Exercice 10
Reprendre le code du tp précédent, le découper en sous-programmes de la façon la moins inintelligente
possible. Bon courage.

84
2.15 Curseurs
Exercice 1
Refaites le td application du PL/SQL en utilisant les curseurs.

Exercice 2
En utlisant la table PERSONNE du tp précédent, ecrivez une fonction affichant toute la descendance d’une
personne.

85
2.16 Curseurs parametrés
L’intérêt de ce tp étant de vous familiariser avec les curseurs paramétrés, vous ferez en sorte de ne pas
contourner leur usage.

Exercice 1
Ecrire une procédure qui affiche tous les clients, et pour chaque client, la liste des comptes.

Exercice 2
Ecrire une procédure qui affiche tous les clients, et pour chaque client, la liste des comptes, et pour chacun
de ces comptes, l’historique des opérations.

86
2.17 Triggers
Étant donnée la base suivante :

DROP TABLE RESULTAT;


DROP TABLE EXAMEN;
DROP TABLE PREREQUIS;
DROP TABLE INSCRIPTION;
DROP TABLE MODULE;
DROP TABLE ETUDIANT;

CREATE TABLE ETUDIANT


(numEtud number,
nom varchar2(40),
prenom varchar2(40),
datenaiss date,
civilite varchar2(4),
patronyme varchar2(40),
numsecu varchar2(15) NOT NULL);

CREATE TABLE MODULE


(codMod number,
nomMod varchar2(15),
effecMax number DEFAULT 30);

CREATE TABLE EXAMEN


(codMod number,
codExam number,
dateExam date);

CREATE TABLE INSCRIPTION


(numEtud number,
codMod number,
dateInsc date default sysdate);

CREATE TABLE PREREQUIS


(codMod number,
codModPrereq number,
noteMin number(4, 2) NOT NULL);

CREATE TABLE RESULTAT


(codMod number,
codExam number,
numEtud number,
note number(4, 2));

ALTER TABLE ETUDIANT ADD


CONSTRAINT pk_etudiant
PRIMARY KEY (numEtud);
ALTER TABLE MODULE ADD
CONSTRAINT pk_module
PRIMARY KEY (codMod);
ALTER TABLE EXAMEN ADD
CONSTRAINT pk_examen
PRIMARY KEY (codMod, codExam);

87
ALTER TABLE PREREQUIS ADD
CONSTRAINT pk_prerequis
PRIMARY KEY (codMod, codModPrereq);
ALTER TABLE INSCRIPTION ADD
CONSTRAINT pk_inscription
PRIMARY KEY (codMod, numEtud);
ALTER TABLE RESULTAT ADD
CONSTRAINT pk_resultat
PRIMARY KEY (codMod, numEtud, codExam);

ALTER TABLE INSCRIPTION ADD


(CONSTRAINT fk_inscription_etudiant
FOREIGN KEY (numEtud)
REFERENCES ETUDIANT(numEtud),
CONSTRAINT fk_inscription_module
FOREIGN KEY (codMod)
REFERENCES MODULE(codMod));
ALTER TABLE PREREQUIS ADD
(CONSTRAINT fk_prerequis_codmod
FOREIGN KEY (codMod)
REFERENCES MODULE(codMod),
CONSTRAINT fk_prerequis_codmodprereq
FOREIGN KEY (codModPrereq)
REFERENCES MODULE(codMod));
ALTER TABLE EXAMEN ADD
CONSTRAINT fk_examen
FOREIGN KEY (codMod)
REFERENCES MODULE(codMod);
ALTER TABLE RESULTAT ADD
(CONSTRAINT fk_resultat_examen
FOREIGN KEY (codMod, codExam)
REFERENCES EXAMEN(codMod, codExam),
CONSTRAINT fk_resultat_inscription
FOREIGN KEY (codMod, numEtud)
REFERENCES INSCRIPTION(codMod,numEtud));

ALTER TABLE ETUDIANT ADD


(CONSTRAINT ck_civilite
CHECK
(
civilite IN (’Mr’, ’Mme’, ’Mlle’)
),
CONSTRAINT ck_civilite_numsecu
CHECK
(
SUBSTR(numsecu, 1, 1) = ’2’ OR patronyme IS NULL
),
CONSTRAINT ck_length_numsecu
CHECK
(
length(numsecu) = 15
),
CONSTRAINT ck_annee_numsecu CHECK
(

88
to_char(datenaiss, ’yy’) = substr(numsecu, 2, 2)
)
);

Implémentez les contraintes suivantes. Vous ferez des sous-programme tenant sur une page, et ne contenant
pas plus de trois niveaux d’imbrication. Vous répertorierez les numéros d’erreurs que vous affecterez à
chaque levée d’exception.
1. Il ne doit pas être possible de modifier la note min dans la table prerequis.
2. Dans un module, il ne doit pas y avoir plus de effecMax élèves inscrits.
3. On ne peut créer un examen pour un module que s’il y a des élèves inscrits dans ce module.
4. Un élève ne peut passer un examen que si sa date d’inscription est antérieure à la date de l’examen.
5. Il ne doit pas y avoir de circuit dans la table prerequis (il existe une façon de la vérifier en PL/SQL,
mais comme vous ne la connaissez pas, faites un parcours en profondeur du graphe des pré-requis)
6. Un élève s’inscrivant à un module doit avoir eu au moins la note min à tous les modules pré-requis.
7. Ajouter dans étudiant un champ moyenne, celui-ci contiendra la moyenne de chaque étudiant s’il a
passé les examens de tous les modules dans lesquels il est inscrit.
8. Revenez sur la première contrainte : il ne doit être possible de modifier une note min dans la table
prerequis que s’il n’existe pas d’élève dont une inscription serait invalidée.
9. Il ne doit être possible de modifier effecMax que si des étudiants ne se retrouvent pas avec une
inscription invalidée.
Libre à vous par la suite de trouver d’autres contraintes et de les implémenter.

89
Chapitre 3

Corrigés

3.1 Contraintes déclaratives


−− q u e s t i o n s 1 , 2 e t 3

DROP TABLE DETAILLIVRAISON ;


DROP TABLE LIVRAISON ;
DROP TABLE PROPOSER;
DROP TABLE PRODUIT ;
DROP TABLE FOURNISSEUR ;

CREATE TABLE PRODUIT


( numprod number PRIMARY KEY,
nomprod varchar2 ( 3 0 ) ) ;

CREATE TABLE FOURNISSEUR


( numfou number PRIMARY KEY,
nomfou varchar2 ( 3 0 ) ) ;

CREATE TABLE PROPOSER


( numfou number ,
numprod number ,
p r i x number NOT NULL,
PRIMARY KEY ( numfou , numprod ) ,
FOREIGN KEY ( numfou ) REFERENCES f o u r n i s s e u r ( numfou ) ,
FOREIGN KEY ( numprod ) REFERENCES p r o d u i t ( numprod ) ) ;

CREATE TABLE LIVRAISON


( numfou number ,
numli number ,
d a t e l i date d e f a u l t s y s d a t e ,
PRIMARY KEY ( numfou , numli ) ,
FOREIGN KEY ( numfou ) REFERENCES f o u r n i s s e u r ( numfou ) ) ;

CREATE TABLE DETAILLIVRAISON


( numfou number ,
numli number ,
numprod number ,
q t e number NOT NULL,
PRIMARY KEY ( numfou , numli , numprod ) ,
FOREIGN KEY ( numfou , numli ) REFERENCES l i v r a i s o n ( numfou , numli ) ,
FOREIGN KEY ( numfou , numprod ) REFERENCES p r o p o s e r ( numfou , numprod ) ) ;

−− q u e s t i o n 4

INSERT INTO PRODUIT values (1 , ’ Roue de s e c o u r s ’ ) ;


INSERT INTO PRODUIT values (2 , ’ Poupée Batman ’ ) ;
INSERT INTO PRODUIT values (3 , ’ Cotons t i g e s ’ ) ;
INSERT INTO PRODUIT values (4 , ’ Cornichons ’ ) ;

INSERT INTO FOURNISSEUR values (1 , ’ f1 ’ );


INSERT INTO FOURNISSEUR values (2 , ’ f2 ’ );
INSERT INTO FOURNISSEUR values (3 , ’ f3 ’ );
INSERT INTO FOURNISSEUR values (4 , ’ f4 ’ );

INSERT INTO PROPOSER values (1 , 1, 200);


INSERT INTO PROPOSER values (1 , 2, 15);
INSERT INTO PROPOSER values (2 , 2, 1);
INSERT INTO PROPOSER values (3 , 3, 2);

90
INSERT INTO LIVRAISON ( numfou , numli ) values ( 1 , 1);
INSERT INTO LIVRAISON ( numfou , numli ) values ( 1 , 2);
INSERT INTO LIVRAISON ( numfou , numli ) values ( 3 , 1);

INSERT INTO DETAILLIVRAISON values (3 , 1, 3, 10);


INSERT INTO DETAILLIVRAISON values (1 , 1, 1, 25);
INSERT INTO DETAILLIVRAISON values (1 , 1, 2, 20);
INSERT INTO DETAILLIVRAISON values (1 , 2, 1, 15);
INSERT INTO DETAILLIVRAISON values (1 , 2, 2, 17);

−− q u e s t i o n 5

−− Le s c r i p t c i −d e s s o u s va vous a f f i c h e r l a s o l u t i o n .
−− Vous pouvez p r o cé d e r de deux f a ç o n s :
−− ∗ c o p i e r −c o l l e r c e t t e s o l u t i o n a f f i c h é e
−− par c e t t e s é r i e de commandes

s e t und o f f
set heading o f f
set f e e d o f f
s e l e c t ’ a l t e r t a b l e ’ | | t a b l e n a m e | | ’ drop c o n s t r a i n t ’ ||
c o n s t r a i n t n a m e | | ’ ; ’ from u s e r c o n s t r a i n t s
where t a b l e n a m e in
( ’PRODUIT ’ , ’FOURNISSEUR ’ , ’PROPOSER ’ ,
’LIVRAISON ’ , ’DETAILLIVRAISON ’ )
AND c o n s t r a i n t t y p e IN ( ’R ’ , ’P ’ )
ORDER BY c o n s t r a i n t t y p e DESC ;
s e t und on
s e t h e a d i n g on
s e t f e e d on

−− ∗ p l a c e r c e c i dans l e f i c h i e r dp . s q l
−− e t l ’ e x é c u t e r en s a i s i s s a n t @<cheminabsolu >/dp . s q l

set trimout o f f ;
Set f e e d o f f ;
set echo o f f ;
set heading o f f ;
s e t termou t o f f ;
set v e r i f y o f f ;
s e t space 0 ;
SET NEWPAGE 0 ;
SET PAGESIZE 0 ;
spool drop constraints . l s t
s e l e c t ’ a l t e r t a b l e ’ | | t a b l e n a m e | | ’ drop c o n s t r a i n t ’ ||
c o n s t r a i n t n a m e | | ’ ; ’ from u s e r c o n s t r a i n t s
where t a b l e n a m e in
( ’PRODUIT ’ , ’FOURNISSEUR ’ ,
’PROPOSER ’ , ’LIVRAISON ’ , ’DETAILLIVRAISON ’ )
AND c o n s t r a i n t t y p e IN ( ’R ’ , ’P ’ )
ORDER BY c o n s t r a i n t t y p e DESC ;
spool o f f
@drop constraints . l s t
s e t t r i m o u t on ;
Set f e e d on ;
s e t e c h o on ;
s e t h e a d i n g on ;
s e t termou t on ;
s e t v e r i f y on ;

−− q u e s t i o n 6

a l t e r t a b l e p r o d u i t add
constraint p k p r o d u i t
PRIMARY KEY ( numprod ) ;
a l t e r t a b l e f o u r n i s s e u r add
constraint p k f o u r n i s s e u r
PRIMARY KEY ( numfou ) ;
a l t e r t a b l e p r o p o s e r add
constraint p k p r o p o s e r
PRIMARY KEY ( numfou , numprod ) ;
a l t e r t a b l e l i v r a i s o n add
constraint p k l i v r a i s o n
PRIMARY KEY ( numfou , numli ) ;
a l t e r t a b l e d e t a i l l i v r a i s o n add
constraint p k d e t a i l l i v r a i s o n
PRIMARY KEY ( numfou , numli , numprod ) ;
a l t e r t a b l e p r o p o s e r add
constraint f k p r o p o s e r f o u r n i s s e u r
FOREIGN KEY ( numfou )

91
REFERENCES f o u r n i s s e u r ( numfou ) ;
a l t e r t a b l e p r o p o s e r add c o n s t r a i n t f k p r o p o s e r p r o d u i t
FOREIGN KEY ( numprod )
REFERENCES p r o d u i t ( numprod ) ;
a l t e r t a b l e l i v r a i s o n add c o n s t r a i n t f k l i v r a i s o n
FOREIGN KEY ( numfou )
REFERENCES f o u r n i s s e u r ( numfou ) ;
a l t e r t a b l e d e t a i l l i v r a i s o n add c o n s t r a i n t f k d e t a i l l i v r a i s o n
FOREIGN KEY ( numfou , numli )
REFERENCES l i v r a i s o n ( numfou , numli ) ;
a l t e r t a b l e d e t a i l l i v r a i s o n add c o n s t r a i n t f k d e t a i l l i v r a i s o n p r o p o s e r
FOREIGN KEY ( numfou , numprod )
REFERENCES p r o p o s e r ( numfou , numprod ) ;

92
3.2 Requêtes monotabulaires
−− E x e r c i c e 1

SELECT nomMod
FROM MODULE;

−− E x e r c i c e 2

SELECT DISTINCT numModPrereq


FROM PREREQUIS

−− E x e r c i c e 3

SELECT nomMod
FROM MODULE
WHERE numMod IN ( 1 , 3 , 5 ) ;

−− E x e r c i c e 4

SQL> SELECT ∗ FROM MODULE WHERE nomMod = ’ Algo a v a n cé e ’ ;

NUMMOD NOMMOD
−−−−−−−−−− −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
8 Algo a v a n cé e

1 ligne s é l e c t i o n n é e .

SQL> UPDATE p r e r e q u i s SET noteMin = 12 WHERE numMod = 8 ;


SQL> SELECT ∗ FROM module WHERE nomMod = ’PL/SQL O r a c l e ’ ;

NUMMOD NOMMOD
−−−−−−−−−− −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
6 PL/SQL O r a c l e

1 l i g n e s é l e c t i o n n é e .
SQL> UPDATE p r e r e q u i s SET noteMin = 11 WHERE numMod = 6 ;

−− E x e r c i c e 5

SELECT numModPrereq , noteMin


FROM PREREQUIS
WHERE numMod = 6
ORDER BY noteMin ;

−− E x e r c i c e 6

SELECT numMod
FROM p r e r e q u i s
WHERE numModPrereq = 5
AND noteMin > 1 0 ;

−− E x e r c i c e 7

SELECT nomMod
FROM module
WHERE nomMod LIKE ’%Algo% ’
OR nomMod LIKE ’%SQL% ’ ;

−− E x e r c i c e 8

DELETE FROM i n t e r v a l l e
WHERE borneSup < b o r n e I n f ;

−− E x e r c i c e 9

DELETE FROM r e c t a n g l e
WHERE xHautGauche = x B a s D r o i t
OR yHautGauche = y B a s D r o i t ;

−− E x e r c i c e 10

SELECT ∗
FROM i n t e r v a l l e
WHERE 10 BETWEEN b o r n e I n f AND borneSup ;

−− E x e r c i c e 11

SELECT ∗
FROM i n t e r v a l l e

93
WHERE b o r n e I n f <= 5 AND borneSup >= 7 ;

SELECT ∗
FROM i n t e r v a l l e
WHERE b o r n e I n f >= 5 AND borneSup <= 3 5 ;

SELECT ∗
FROM i n t e r v a l l e
WHERE ( 1 5 BETWEEN b o r n e I n f AND borneSup )
OR ( 2 0 BETWEEN b o r n e I n f AND borneSup )
OR ( b o r n e I n f BETWEEN 15 AND 2 0 ) ;

−− E x e r c i c e 12

SELECT ∗
FROM r e c t a n g l e
WHERE ( xHautGauche > x B a s D r o i t )
OR ( yHautGauche < y B a s D r o i t ) ;

−− E x e r c i c e 13

UPDATE r e c t a n g l e SET
xHautGauche = xBasDroit ,
x B a s D r o i t = xHautGauche
WHERE xHautGauche > x B a s D r o i t ;

UPDATE r e c t a n g l e SET
yHautGauche = yBasDroit ,
y B a s D r o i t = yHautGauche
WHERE yHautGauche < y B a s D r o i t ;

−− E x e r c i c e 14

SELECT ∗
FROM r e c t a n g l e
WHERE ( 2 BETWEEN xHautGauche AND x B a s D r o i t )
AND ( 2 BETWEEN y B a s D r o i t AND yHautGauche ) ;

94
3.3 Requêtes multitabulaires
−− E x e r c i c e 1

SELECT d i s t i n c t nomprod
FROM p r o d u i t , p r o p o s e r
WHERE p r o d u i t . numprod = p r o p o s e r . numprod ;

−− E x e r c i c e 2

SELECT d i s t i n c t nomfou
FROM f o u r n i s s e u r f , p r o p o s e r p
WHERE f . numfou = p . numfou ;

−− E x e r c i c e 3

SELECT nomfou , nomprod


FROM f o u r n i s s e u r f , p r o d u i t p , p r o p o s e r pr
WHERE f . numfou = pr . numfou
AND pr . numprod = p . numprod ;

−− E x e r c i c e 4

SELECT nomfou , p r i x
FROM f o u r n i s s e u r f , p r o d u i t p , p r o p o s e r pr
WHERE f . numfou = pr . numfou
AND pr . numprod = p . numprod
AND nomProd = ’ Poupée Batman ’
ORDER BY p r i x ;

−− E x e r c i c e 5

SELECT d a t e l i
FROM l i v r a i s o n l , f o u r n i s s e u r f
WHERE l . numfou = f . numfou
AND f . nomFou = ’ f 1 ’ ;

−− E x e r c i c e 6

SELECT nomprod
FROM f o u r n i s s e u r f , p r o d u i t p , detaillivraison d
WHERE nomfou = ’ f 3 ’
AND f . numfou = d . numfou
AND d . numprod = p . numprod ;

−− E x e r c i c e 7

SELECT l . numfou , l . numli , d a t e l i


FROM p r o d u i t p , l i v r a i s o n l , d e t a i l l i v r a i s o n d
WHERE p . numprod = d . numprod
AND l . numfou = d . numfou
AND l . numli = d . numli
AND p . nomprod = ’ Poupée Batman ’ ;

−− E x e r c i c e 8

SELECT e n f . nom , e n f . prenom


FROM p e r s o n n e s f , p e r s o n n e e n f
WHERE e n f . mere = s f . numpers
AND s f . prenom = ’ S o f i a ’ ;

−− E x e r c i c e 9

SELECT p a r . nom , p a r . prenom


FROM p e r s o n n e ed , p e r s o n n e p a r
WHERE ( ed . p e r e = p a r . numpers OR ed . mere = p a r . numpers )
AND ed . nom = ’ D i j k s t r a ’ ;

−− E x e r c i c e 10

SELECT e . nom , e . prenom


FROM p e r s o n n e e , p e r s o n n e p , p e r s o n n e m
WHERE e . p e r e = p . numpers
AND e . mere = m. numpers
AND p . nom = ’ Bach ’
AND m. nom = ’ Mathieu ’ ;

−− E x e r c i c e 11

SELECT f . nom , f . prenom


FROM p e r s o n n e f , p e r s o n n e j

95
WHERE f . p e r e = j . p e r e
AND f . mere = j . mere
AND j . nom = ’ La F r i p o u i l l e ’
AND j . nom <> f . nom ;

−− E x e r c i c e 12

SELECT c . nom , c . prenom


FROM p e r s o n n e c , p e r s o n n e o , p e r s o n n e p , p e r s o n n e d
WHERE d . nom = ’ D i j k s t r a ’
AND d . p e r e = p . numpers
AND p . p e r e = o . p e r e
AND p . mere = o . mere
AND p . numpers <> o . numpers
AND c . p e r e = o . numpers ;

−− E x e r c i c e 13

SELECT dm . nom , dm . prenom


FROM p e r s o n n e dm, p e r s o n n e l f , p e r s o n n e p
WHERE l f . nom = ’ Fabian ’
AND p . numpers = l f . p e r e
AND p . mere = dm . mere
AND p . numpers <> dm . numpers ;

−− E x e r c i c e 14

SELECT p . nom , p . prenom


FROM p e r s o n n e p , p e r s o n n e kb , p e r s o n n e e n f
WHERE kb . nom = ’ Bush ’
AND e n f . mere = kb . numpers
AND e n f . p e r e = p . numpers ;

−− E x e r c i c e 15

SELECT nev . nom , nev . prenom


FROM p e r s o n n e nev , p e r s o n n e j l c , p e r s o n n e f r
WHERE j l c . prenom = ’ Jacqou ’
AND f r . p e r e = j l c . p e r e
AND f r . mere = j l c . mere
AND f r . numpers <> j l c . numpers
ANd ( nev . p e r e = f r . numpers OR nev . mere = f r . numpers ) ;

−− E x e r c i c e 16

SELECT m. nom , m. prenom


FROM p e r s o n n e ar , p e r s o n n e f , p e r s o n n e m
WHERE f . p e r e = a r . numpers
AND a r . nom = ’ Rieu ’
AND f . mere = m. numpers ;

−− E x e r c i c e 17

SELECT DISTINCT gp . nom , gp . prenom


FROM p e r s o n n e sh , p e r s o n n e p , p e r s o n n e gp
WHERE sh . nom = ’ S t o n e ’
AND (
( sh . p e r e = gp . numpers )
OR ( sh . mere = gp . numpers )
OR (
( sh . mere = p . numpers OR sh . p e r e = p . numpers )
AND ( p . mere = gp . numpers OR p . p e r e = gp . numpers )
)
);

96
3.4 Agrégation de données
−− E x e r c i c e 1

SELECT COUNT( ∗ )
FROM FOURNISSEUR ;

−− E x e r c i c e 2

SELECT COUNT(DISTINCT NUMFOU)


FROM LIVRAISON ;

−− E x e r c i c e 3

SELECT MAX( p r i x ) AS PRIX MAX


FROM PROPOSER PR, FOURNISSEUR F
WHERE F . numfou = PR . numfou
AND nomfou = ’ f 1 ’ ;

−− E x e r c i c e 4

SELECT nomfou , count (DISTINCT numprod ) AS NB PROD PROPOSES


FROM FOURNISSEUR F , PROPOSER P
WHERE F . numfou = P . numfou
GROUP BY nomfou ;

−− E x e r c i c e 5

SELECT COUNT(DISTINCT P . numprod ) − count (DISTINCT PR . numprod )


FROM PRODUIT P , PROPOSER PR ;

−− E x e r c i c e 6

SELECT nomprod , COUNT(DISTINCT D. numfou )


FROM PRODUIT P , DETAILLIVRAISON D
WHERE P . numprod = D. numprod
GROUP BY nomprod ;

−− E x e r c i c e 7

SELECT nomfou , L . numli , d a t e l i , COUNT( numprod ) AS NB PRODUITS


FROM FOURNISSEUR F , LIVRAISON L , DETAILLIVRAISON D
WHERE F . numfou = L . numfou
AND D. numfou = L . numfou
AND D. numli = L . numli
GROUP BY nomfou , L . numli , d a t e l i ;

−− E x e r c i c e 8

SELECT nomfou , L . numli , d a t e l i , SUM( q t e ∗ p r i x ) AS TOTAL


FROM FOURNISSEUR F , LIVRAISON L , DETAILLIVRAISON D, PROPOSER P
WHERE F . numfou = L . numfou
AND D. numfou = L . numfou
AND D. numli = L . numli
AND P . numfou = F . numfou
AND D. numprod = P . numprod
GROUP BY nomfou , L . numli , d a t e l i ;

−− E x e r c i c e 9

SELECT nomprod
FROM PRODUIT P , PROPOSER PR
WHERE P . numprod = PR . numprod
GROUP BY nomprod
HAVING COUNT(D. numfou ) = 1 ;

−− E x e r c i c e 10

SELECT nomfou
FROM FOURNISSEUR F , PROPOSER P , DETAILLIVRAISON L
WHERE F . numfou = P . numfou
AND L . numfou = F . numfou
GROUP BY nomfou
HAVING COUNT(DISTINCT P . numprod ) = COUNT(DISTINCT L . numprod ) ;

97
3.5 Vues
−− E x e r c i c e 1

CREATE VIEW QUANTITE LIVREE PAR PRODUIT AS


SELECT numprod , SUM( q t e ) AS QUANTITE LIVREE
FROM DETAILLIVRAISON
GROUP BY numprod ;

−− E x e r c i c e 2

SELECT MAX(QUANTITE LIVREE)


FROM QUANTITE LIVREE PAR PRODUIT ;

−− E x e r c i c e 3

CREATE VIEW FACTURE PAR LIVRAISON AS


SELECT D. numfou , D. numli , SUM( q t e ∗ p r i x ) AS MONTANT FACTURE
FROM PROPOSER PR, DETAILLIVRAiSON D
wHERE PR . numfou = D. numfou
AND D. numprod = PR . numprod
GROUP BY D. numfou , D. numli ;

−− E x e r c i c e 4

CREATE VIEW FACTURE PAR FOURNISSEUR AS


SELECT numfou , SUM(MONTANT FACTURE) AS TOTAL FACTURE
FROM FACTURE PAR LIVRAISON
GROUP BY numfou ;

−− E x e r c i c e 5

SELECT MIN(TOTAL FACTURE)


FROM FACTURE PAR FOURNISSEUR ;

−− E x e r c i c e 6

CREATE VIEW NB PROD DIST LIVRES PAR FOU AS


SELECT DISTINCT numfou ,
COUNT(DISTINCT numprod ) AS NB PRODUITS DISTINCTS LIVRES
FROM DETAILLIVRAISON
GROUP BY numfou ;

SELECT MAX( NB PRODUITS DISTINCTS LIVRES )


FROM NB PROD DIST LIVRES PAR FOU ;

98
3.6 Requêtes imbriquées
−− E x e r c i c e 1

SELECT nomfou ,
(SELECT COUNT( numprod )
FROM PROPOSER P
WHERE P . numfou = F . numfou
) AS NB PROD PROPOSES
FROM FOURNISSEUR F ;

−− E x e r c i c e 2

SELECT nomfou
FROM FOURNISSEUR
WHERE numfou IN
(SELECT numfou
FROM PROPOSER
WHERE numprod = 2 ) ;

−− E x e r c i c e 3

SELECT nomfou
FROM FOURNISSEUR
WHERE numfou IN
(SELECT numfou
FROM PROPOSER
WHERE numprod =
(SELECT numprod
FROM PRODUIT
WHERE nomprod = ’ Poupée Batman ’
)
);

−− E x e r c i c e 4

SELECT nomfou
FROM FOURNISSEUR
WHERE numfou IN
(SELECT numfou
FROM DETAILLIVRAISON
WHERE numprod IN
(SELECT numprod
FROM PRODUIT
WHERE nomprod = ’ Poupée Batman ’
)
);

−− E x e r c i c e 5

SELECT nomfou
FROM FOURNISSEUR F
WHERE
(SELECT COUNT( ∗ )
FROM PROPOSER PR
WHERE F . numfou = PR . numfou
) > 0
AND
(SELECT COUNT(DISTINCT numprod )
FROM DETAILLIVRAISON D
WHERE F . numfou = D. numfou
)
=
(SELECT COUNT( ∗ )
FROM PROPOSER PR
WHERE F . numfou = PR . numfou
);

−− E x e r c i c e 6

SELECT nomfou ,
(SELECT nomprod
FROM PRODUIT P
WHERE P . numprod IN
(SELECT numprod
FROM PROPOSER PR1
WHERE PR1 . numfou = F . numfou
AND p r i x =
(SELECT MAX( p r i x )
FROM PROPOSER PR2
WHERE PR2 . numfou = F . numfou

99
)
)
)
FROM FOURNISSEUR F ;

−− E x e r c i c e 7

CREATE VIEW NB PROD LIVRES PAR FOU AS


SELECT numfou , numprod , SUM( q t e ) AS QTE
FROM DETAILLIVRAISON
GROUP BY numfou , numprod ;

SELECT nomprod , nomfou


FROM FOURNISSEUR F , PRODUIT P
WHERE
(SELECT QTE
FROM NB PROD LIVRES PAR FOU D
WHERE D. numprod = P . numprod
AND D. numfou = F . numfou
)
=
(SELECT MAX(QTE)
FROM NB PROD LIVRES PAR FOU D
WHERE D. numprod = P . numprod
);

−− E x e r c i c e 8

SELECT MIN(NB PROD)


FROM
(SELECT
(SELECT COUNT( ∗ )
FROM PROPOSER PR
WHERE PR . numfou = F . numfou
) AS NB PROD
FROM FOURNISSEUR F
);

−− E x e r c i c e 9

SELECT nomfou
FROM FOURNISSEUR
WHERE numfou IN
(sELECT numfou
FROM
(SELECT numfou ,
(SELECT COUNT( ∗ )
FROM PROPOSER PR
WHERE F . numfou = PR . numfou
) AS NB PROD
FROM FOURNISSEUR F
)
WHERE NB PROD =
(SELECT MIN(NB PROD)
FROM
(SELECT numfou ,
(SELECT COUNT( ∗ )
FROM PROPOSER PR
WHERE F . numfou = PR . numfou
) AS NB PROD
FROM FOURNISSEUR F
)
)
);

−− E x e r c i c e 10

SELECT nomprod , nomfou


FROM PRODUIT P , FOURNISSEUR F ,
(SELECT F1 . numfou , P1 . numprod
FROM FOURNISSEUR F1 , PRODUIT P1
WHERE
(SELECT SUM(QTE)
FROM DETAILLIVRAiSON D
WHERE D. numfou = F1 . numfou
AND D. numprod = P1 . numprod
)
=
(SELECT MAX( NB LIV )
FROM

100
(SELECT numprod , SUM(QTE) AS NB LIV
FROM DETAILLIVRAiSON D
GROUP BY numprod , numfou
) Q
WHERE Q. numprod = P1 . numprod
)
) M
WHERE P . numprod = M. numprod
AND F . numfou = M. numfou ;

101
3.7 Compléments sur les types
−− E x e r c i c e 1

ALTER TABLE LIVRAISON ADD CONSTRAINT c k d a t e m a n d a t o r y


CHECK ( d a t e l i I S NOT NULL) ;

ALTER TABLE PROPOSER ADD CONSTRAINT c k p r i c e m a n d a t o r y


CHECK ( p r i x I S NOT NULL) ;

ALTER TABLE DETAILLIVRAISON ADD CONSTRAINT c k q t e m a n d a t o r y


CHECK ( q t e I S NOT NULL) ;

−− E x e r c i c e 2

ALTER TABLE PROPOSER ADD CONSTRAINT c k p r i c e p o s i t i v e


CHECK ( p r i x > 0 ) ;

ALTER TABLE DETAILLIVRAISON ADD CONSTRAINT c k q t e p o s i t i v e


CHECK ( q t e > 0 ) ;

−− E x e r c i c e 3

ALTER TABLE LIVRAISON ADD CONSTRAINT c k o c t o b r e 2 0 0 6


CHECK ( t o c h a r ( d a t e l i , ’yyyymm ’ ) >= ’ 200610 ’ ) ;

−− E x e r c i c e 4

ALTER TABLE LIVRAISON ADD CONSTRAINT c k f e t e d u t r a v a i l


CHECK ( t o c h a r ( d a t e l i , ’mmdd ’ ) <> ’ 0501 ’ ) ;

−− E x e r c i c e 5

UPDATE PRODUIT SET


nomprod = upper ( substr ( nomprod , 1 , 1 ) ) | |
substr ( nomprod , 2 , LENGTH( nomprod ) − 1 ) ;

ALTER TABLE PRODUIT ADD


CONSTRAINT c k m a j u s c u l e p r o d u i t
CHECK ( upper ( substr ( nomprod , 1 , 1 ) ) = substr ( nomprod , 1 , 1 ) ) ;

UPDATE FOURNISSEUR SET


nomfou = upper ( substr ( nomfou , 1 , 1 ) ) | |
substr ( nomfou , 2 , LENGTH( nomfou ) − 1 ) ;

ALTER TABLE FOURNISSEUR ADD


CONSTRAINT c k m a j u s c u l e f o u r n i s s e u r
CHECK ( upper ( substr ( nomfou , 1 , 1 ) ) = substr ( nomfou , 1 , 1 ) ) ;

102
3.8 Révisions
−− E x e r c i c e 1

SELECT nomfou
FROM FOURNISSEUR F
WHERE
(
SELECT COUNT( ∗ )
FROM LIVRAISON L
WHERE L . numfou = F . numfou
)
>= 2 ;

−− E x e r c i c e 2

CREATE VIEW LIVRAISONS PAR ANNEE AS


SELECT ANNEE, COUNT( ∗ ) AS NB LIVRAISONS
FROM
(
SELECT t o c h a r ( d a t e l i , ’ yyyy ’ ) AS ANNEE, numfou , numli
FROM LIVRAISON
)
GROUP BY ANNEE;

SELECT ANNEE
FROM LIVRAISONS PAR ANNEE
WHERE NB LIVRAISONS =
(
SELECT MAX( NB LIVRAISONS )
FROM LIVRAISONS PAR ANNEE
);

−− E x e r c i c e 3

CREATE VIEW FOU KI ONT TOU LIVRE AS


SELECT numfou
FROM FOURNISSEUR F
WHERE
(SELECT COUNT( ∗ )
FROM PROPOSER PR
WHERE PR . numfou = F . numfou )
=
(SELECT COUNT(DISTINCT numprod )
FROM DETAILLIVRAISON D
WHERE D. numfou = F . numfou
);

CREATE VIEW DERNIERE LI PAR FOU AS


SELECT numfou , MAX( d a t e l i ) AS DATE MAX
FROM LIVRAISON
GROUP BY numfou ;

SELECT nomfou
FROM FOURNISSEUR
WHERE numfou IN
(
SELECT F . numfou
FROM FOU KI ONT TOU LIVRE F , DERNIERE LI PAR FOU D
WHERE F . numfou = D. numfou
AND DATE MAX =
(
SELECT MAX(DATE MAX)
FROM FOU KI ONT TOU LIVRE F , DERNIERE LI PAR FOU D
WHERE F . numfou = D. numfou
)
);

103
3.9 Examen Type
DROP TABLE RESULTAT;
DROP TABLE EXAMEN;
DROP TABLE PREREQUIS ;
DROP TABLE INSCRIPTION ;
DROP TABLE MODULE;
DROP TABLE ETUDIANT;

−− E x e r c i c e 1 e t 3

CREATE TABLE ETUDIANT


( numEtud number ,
nom varchar2 ( 4 0 ) ,
prenom varchar2 ( 4 0 ) ,
d a t e n a i s s date ,
c i v i l i t e varchar2 ( 4 ) ,
patronyme varchar2 ( 4 0 ) ,
numsecu varchar2 ( 1 5 ) NOT NULL) ;

CREATE TABLE MODULE


( codMod number ,
nomMod varchar2 ( 1 5 ) ,
e f f e c M a x number DEFAULT 3 0 ) ;

CREATE TABLE EXAMEN


( codMod number ,
codExam number ,
dateExam date ) ;

CREATE TABLE INSCRIPTION


( numEtud number ,
codMod number ,
d a t e I n s c date d e f a u l t s y s d a t e ) ;

CREATE TABLE PREREQUIS


( codMod number ,
codModPrereq number ,
noteMin number ( 4 , 2 ) NOT NULL) ;

CREATE TABLE RESULTAT


( codMod number ,
codExam number ,
numEtud number ,
n o t e number ( 4 , 2 ) ) ;

−− E x e r c i c e 2

ALTER TABLE ETUDIANT ADD


CONSTRAINT p k e t u d i a n t
PRIMARY KEY ( numEtud ) ;
ALTER TABLE MODULE ADD
CONSTRAINT pk module
PRIMARY KEY ( codMod ) ;
ALTER TABLE EXAMEN ADD
CONSTRAINT pk examen
PRIMARY KEY ( codMod , codExam ) ;
ALTER TABLE PREREQUIS ADD
CONSTRAINT p k p r e r e q u i s
PRIMARY KEY ( codMod , codModPrereq ) ;
ALTER TABLE INSCRIPTION ADD
CONSTRAINT p k i n s c r i p t i o n
PRIMARY KEY ( codMod , numEtud ) ;
ALTER TABLE RESULTAT ADD
CONSTRAINT p k r e s u l t a t
PRIMARY KEY ( codMod , numEtud , codExam ) ;

ALTER TABLE INSCRIPTION ADD


(CONSTRAINT f k i n s c r i p t i o n e t u d i a n t
FOREIGN KEY ( numEtud )
REFERENCES ETUDIANT( numEtud ) ,
CONSTRAINT f k i n s c r i p t i o n m o d u l e
FOREIGN KEY ( codMod )
REFERENCES MODULE( codMod ) ) ;
ALTER TABLE PREREQUIS ADD
(CONSTRAINT f k p r e r e q u i s c o d m o d
FOREIGN KEY ( codMod )
REFERENCES MODULE( codMod ) ,
CONSTRAINT f k p r e r e q u i s c o d m o d p r e r e q
FOREIGN KEY ( codModPrereq )
REFERENCES MODULE( codMod ) ) ;

104
ALTER TABLE EXAMEN ADD
CONSTRAINT f k e x a m e n
FOREIGN KEY ( codMod )
REFERENCES MODULE( codMod ) ;
ALTER TABLE RESULTAT ADD
(CONSTRAINT f k r e s u l t a t e x a m e n
FOREIGN KEY ( codMod , codExam )
REFERENCES EXAMEN( codMod , codExam ) ,
CONSTRAINT f k r e s u l t a t i n s c r i p t i o n
FOREIGN KEY ( codMod , numEtud )
REFERENCES INSCRIPTION ( codMod , numEtud ) ) ;

−− E x e r c i c e 3

−− I c i s e t r o u v e l e s c o n s t r a i n t e s de t y p e CHECK q u i n ’ ont pas é t é p l a c é e s


−− au n i v e a u de l a t a b l e pour d e s r a i s o n s de l i s i b i l i t é .

ALTER TABLE ETUDIANT ADD


(CONSTRAINT c k c i v i l i t e
CHECK
(
c i v i l i t e IN ( ’Mr ’ , ’Mme ’ , ’ M l l e ’ )
),
CONSTRAINT c k c i v i l i t e n u m s e c u
CHECK
(
SUBSTR( numsecu , 1 , 1 ) = ’ 2 ’ OR patronyme I S NULL
),
CONSTRAINT c k l e n g t h n u m s e c u
CHECK
(
l e n g t h ( numsecu ) = 15
),
CONSTRAINT c k a n n e e n u m s e c u CHECK
(
t o c h a r ( d a t e n a i s s , ’ yy ’ ) = substr ( numsecu , 2 , 2 )
)
);

−− I l i m p o s s i b l e de l i m i t e r de f a ç o n d é c l a r a t i v e l e nombre d ’ é t u d i a n t s
−− i n s c r i t s à un module .

−− E x e r c i c e 4

INSERT INTO ETUDIANT VALUES


( (SELECT n v l (MAX( numEtud ) , 0 ) + 1 FROM ETUDIANT) ,
’ Fourier ’ ,
’ Joseph ’ ,
t o d a t e ( ’ 2 1 0 3 1 7 6 8 ’ , ’ ddmmyyyy ’ ) ,
’Mr ’ ,
NULL,
’ 168031234567890 ’
);

INSERT INTO MODULE ( codMod , nomMod) VALUES


(
(SELECT n v l (MAX( codMod ) , 0 ) + 1 FROM MODULE) ,
’ Maths ’
);

INSERT INTO INSCRIPTION ( codMod , numEtud ) VALUES


( (SELECT numEtud FROM ETUDIANT WHERE nom = ’ F o u r i e r ’ ) ,
(SELECT codMod FROM MODULE WHERE nomMod = ’ Maths ’ ) ) ;

INSERT INTO EXAMEN VALUES


(
(SELECT codMod FROM MODULE WHERE nomMod = ’ Maths ’ ) ,
1,
t o d a t e ( ’ 0 2 0 1 2 0 0 7 ’ , ’ ddmmyyyy ’ )
);

INSERT INTO RESULTAT VALUES


(
(SELECT codMod FROM MODULE WHERE nomMod = ’ Maths ’ ) ,
1,
(SELECT numEtud FROM ETUDIANT WHERE nom = ’ F o u r i e r ’ ) ,
19
);

105
UPDATE RESULTAT SET n o t e = 20
wHERE
numEtud = (SELECT numEtud FROM ETUDIANT WHERE nom = ’ F o u r i e r ’ )
AND codMod = (SELECT codMod FROM MODULE WHERE nomMod = ’ Maths ’ )
AND codExam = 1 ;

−− E x e r c i c e 5

−− r e q u ê t e 1

SELECT nom
FROM ETUDIANT;

−− r e q u ê t e 2

SELECT nom
FROM ETUDIANT
WHERE numEtud IN
(
SELECT numEtud
FROM INSCRIPTION
WHERE codMod IN
(
SELECT codMod
FROM MODULE
WHERE nomMod = ’ Maths ’
)
);

−− r e q u ê t e 3

SELECT nom , prenom ,


(
SELECT MAX(NOTE)
FROM RESULTAT R
WHERE R . numEtud = E . numEtud
AND codMod =
(
SELECT codMod
FROM MODULE
WHERE nomMod = ’ Maths ’
)
) AS NOTE DEFINITIVE
FROM ETUDIANT E ;

−− r e q u ê t e 4

SELECT nom , prenom


FROM ETUDIANT E
WHERE
0 <=
(
SELECT count ( ∗ )
FROM RESULTAT R
WHERE R . numEtud = E . numEtud
AND n o t e >= 10
AND codMod =
(
SELECT codMod
FROM MODULE
WHERE nomMod = ’ Maths ’
)
);

−− r e q u ê t e 5

SELECT nom , prenom


FROM ETUDIANT E
WHERE
(
SELECT count ( ∗ )
FROM RESULTAT R
WHERE R . numEtud = E . numEtud
AND codMod =
(
SELECT codMod
FROM MODULE
WHERE nomMod = ’ Maths ’
)

106
) = 0 ;

−− r e q u ê t e 6

CREATE VIEW NOTE MATHS PAR ETU AS


SELECT numEtud ,
(
SELECT MAX(NOTE)
FROM RESULTAT R
WHERE R . numEtud = E . numEtud
AND codMod =
(
SELECT codMod
FROM MODULE
WHERE nomMod = ’ Maths ’
)
) AS NOTE MATHS
FROM ETUDIANT E ;

SELECT nom , prenom


FROM ETUDIANT
WHERE numEtud IN
(
SELECT numEtud
FROM NOTE MATHS PAR ETU
WHERE NOTE MATHS
=
(
SELECT MAX(NOTE MATHS)
FROM NOTE MATHS PAR ETU
)
);

−− r e q u ê t e 7

CREATE VIEW NOTE MIN MATHS PAR ETU AS


SELECT numEtud ,
(
SELECT MIN(NOTE)
FROM RESULTAT R
WHERE R . numEtud = E . numEtud
AND codMod =
(
SELECT codMod
FROM MODULE
WHERE nomMod = ’ Maths ’
)
) AS NOTE MATHS
FROM ETUDIANT E ;

SELECT nom , prenom


FROM ETUDIANT
WHERE numEtud IN
(
SELECT numEtud
FROM NOTE MATHS PAR ETU
WHERE NOTE MATHS
=
(
SELECT MAX(NOTE MATHS)
FROM NOTE MIN MATHS PAR ETU
)
);

−− r e q u ê t e 8

CREATE VIEW NOTE PAR ETU MOD AS


SELECT numEtud , codMod ,
(
SELECT MAX( n o t e )
FROM RESULTAT R
WHERE R . numEtud = I . numEtud
AND R . codMod = I . codMod
) AS NOTE DEF
FROM INSCRIPTION I ;

SELECT nomMod
FROM MODULE M
WHERE
(
SELECT COUNT( ∗ )

107
FROM PREREQUIS P
WHERE M. codMod = P . codMod
AND noteMin >
(
SELECT NOTE DEF
FROM NOTE PAR ETU MOD N
WHERE N . codMod = P . codModPrereq
AND N . numEtud =
(
SELECT numEtud
FROM ETUDIANT
WHERE nom = ’ F o u r i e r ’
)
)
) = 0
AND M. codMod NOT IN
(
SELECT codMod
FROM INSCRIPTION
WHERE numEtud IN
(
SELECT numEtud
FROM ETUDIANT
WHERE nom = ’ F o u r i e r ’
)
);

108
3.10 Introduction au PL/SQL
−− E x e r c i c e 1

DECLARE
a NUMBER;
b NUMBER;
t NUMBER;
BEGIN
a := 1 ;
b := 2 ;
DBMS OUTPUT. PUT LINE ( ’ a = ’ | | a ) ;
DBMS OUTPUT. PUT LINE ( ’ b = ’ | | b ) ;
DBMS OUTPUT. PUT LINE ( ’ Let ’ ’ s swap a and b . . . The r e s u l t is : ’ );
t := a ;
a := b ;
b := t ;
DBMS OUTPUT. PUT LINE ( ’ a = ’ | | a ) ;
DBMS OUTPUT. PUT LINE ( ’ b = ’ | | b ) ;
END;
/

−− E x e r c i c e 2

DECLARE
a NUMBER;
r e s NUMBER;
c o u n t e r NUMBER;
BEGIN
a := 1 0 ;
r e s := 1 ;
c o u n t e r := a ;
WHILE c o u n t e r > 0 LOOP
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 LOOP;
DBMS OUTPUT. PUT LINE ( a | | ’ != ’ | | r e s ) ;
END;
/

−− E x e r c i c e 3

DECLARE
a NUMBER := 4 8 ;
b NUMBER := 8 4 ;
amodb NUMBER;
BEGIN
DBMS OUTPUT.PUT( ’PGCD( ’ | | a | | ’ , ’ | | b | | ’ ) = ’ ) ;
WHILE b > 0 LOOP
amodb := a ;
WHILE amodb >= b LOOP
amodb := amodb − b ;
END LOOP;
a := b ;
b := amodb ;
END LOOP;
DBMS OUTPUT. PUT LINE ( a ) ;
END;
/

109
3.11 Tableaux et Structures
SET SERVEROUTPUT ON

−− Tableaux

DECLARE
TYPE montab I S VARRAY ( 5 0 ) OF INTEGER;
t montab ;
BEGIN
t := montab ( ) ;
t . extend ( 2 0 ) ;

−− I n i t i a l i s a t i o n
FOR i IN 1 . . 2 0 LOOP
t ( i ) := i ∗ i ;
END LOOP;

−− I n v e r s i o n de l ’ o r d r e d e s é lé m e n t s
DECLARE
temp i n t e g e r ;
BEGIN
FOR i IN 1 . . 1 0 LOOP
temp := t ( i ) ;
t ( i ) := t (20− i + 1 ) ;
t (20− i +1) := temp ;
END LOOP;
END;

−− A f f i c h a g e
FOR i IN 1 . . 2 0 LOOP
DBMS OUTPUT. PUT LINE ( ’ t ( ’ | |
i || ’) = ’ || t( i ));
END LOOP;

−− Tri à b u l l e
DECLARE
temp i n t e g e r ;
BEGIN
FOR i IN REVERSE 2 . . 2 0 LOOP
FOR j IN 2 . . i LOOP
IF t ( j − 1 ) > t ( j ) THEN
temp := t ( j ) ;
t ( j ) := t ( j − 1 ) ;
t ( j −1) := temp ;
END IF ;
END LOOP;
END LOOP;
END;

−− A f f i c h a g e
FOR i IN 1 . . 2 0 LOOP
DBMS OUTPUT. PUT LINE ( ’ t ( ’ | |
i || ’) = ’ || t( i ));
END LOOP;

−− Recherche par d i c h o t o m i e de l ’ é lé m e n t 225


DECLARE
i n f INTEGER := 1 ;
sup INTEGER := 2 0 ;
m INTEGER;
X INTEGER := 4 0 0 ;
BEGIN
LOOP
DBMS OUTPUT. PUT LINE ( ’ i n f = ’ | | i n f ||
’ ; sup = ’ | | sup ) ;
m := ( i n f + sup ) / 2 ;
EXIT WHEN
t (m) = X OR i n f = sup ;
IF t (m) > X THEN
sup := m−1;
ELSE
i n f := m+1;
END IF ;
END LOOP;
IF t (m) = X THEN
DBMS OUTPUT. PUT LINE (X | |
’ e s t dans l e t a b l e a u ’ ) ;
ELSE

110
DBMS OUTPUT. PUT LINE (X | |
’ n” e s t p as dans l e t a b l e a u ’ ) ;
END IF ;
END;
END;
/

−− S t r u c t u r e s

DECLARE
−− M a i l l o n d ’ une l i s t e c h aı̂ né e
TYPE CELL I S RECORD
(
−− Donnée de chaque 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é cé d e n t de l a l i s t e ,
−− −1 s ’ i l n ’ y en a pas
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 pas
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
TYPE TREE I S VARRAY ( 1 9 ) OF CELL ;
−− Tableau 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 TREE;
−− i n d i c e du premier é lé m e n t de l a l i s t e
f i r s t integer ;
−− i n d i c e du d e r n i e r é lé m e n t de l a l i s t e
l a s t integer ;
BEGIN
t := TREE ( ) ;
t . extend ( 1 9 ) ;

−− I n i t i a l i s a t i o n
FOR i IN 1 . . 1 9 LOOP
t ( i ) . d a t a := power ( i , 5 ) mod 19 ;
t ( i ) . p r e v i o u s := i −1;
t ( i ) . next := i +1;
END LOOP;
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
DECLARE
p i n t e g e r := f i r s t ;
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;

−− I n v e r s i o n de l ’ o r d r e d e s é lé m e n t s
DECLARE
temp INTEGER;
BEGIN
FOR i IN 1 . . 1 9 LOOP
temp := 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 := temp ;
END LOOP;
f i r s t := 1 9 ;
l a s t := 1 ;
END;

−− A f f i c h a g e
DECLARE
p i n t e g e r := f i r s t ;
BEGIN
WHILE p <> −1 LOOP
DBMS OUTPUT. PUT LINE ( ’ ( ’ | |
p || ’ , ’ ||
t ( p ) . data | | ’ , ’ | |
t (p ) . previous | | ’ , ’ ||
t ( p ) . next | | ’ ) ’ ) ;

111
p := t ( p ) . next ;
END LOOP;
END;

−− Tri à b u l l e
DECLARE
i i n t e g e r := l a s t ;
j integer ;
BEGIN
WHILE t ( t ( i ) . p r e v i o u s ) . p r e v i o u s <> −1 LOOP
j := f i r s t ;
WHILE i <>j LOOP

IF ( t ( j ) . d a t a > t ( t ( j ) . next ) . d a t a ) THEN

−− 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
DECLARE
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 ;
BEGIN
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 ;
IF t ( j ) . next <> −1 THEN
t ( t ( j ) . next ) . p r e v i o u s := j ;
ELSE
l a s t := j ;
END IF ;
IF t ( a f t e r J ) . p r e v i o u s <> −1 THEN
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 IF ;
IF a f t e r J = i THEN
i := j ;
END IF ;
END;

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

−− A f f i c h a g e
DECLARE
p i n t e g e r := f i r s t ;
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;

END;
/

112
3.12 Application du PL/SQL et Exceptions
SET SERVEROUTPUT ON
SET AUTOCOMMIT OFF

−− E x e r c i c e 1

DECLARE
u n C l i e n t PERSONNE%ROWTYPE;
numClient PERSONNE. numpers%t y p e ;
Y A EU UNE MERDE EXCEPTION;
BEGIN
FOR numClient IN 1 . . 2 1 LOOP
BEGIN
SELECT ∗ INTO u n C l i e n t
FROM PERSONNE
WHERE numpers = numClient ;

INSERT INTO CLIENT ( numcli , n o m c l i , p r e n o m c l i )


VALUES
( u n C l i e n t . numpers ,
u n C l i e n t . nom ,
u n C l i e n t . prenom ) ;
EXCEPTION
WHEN NO DATA FOUND THEN
DBMS OUTPUT. PUT LINE (
’ P e r s o n n e n” a l ” i d e n t i f i a n t ’ | |
numClient ) ;
WHEN TOO MANY ROWS THEN
DBMS OUTPUT. PUT LINE (
’ 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 DUP VAL ON INDEX THEN
DBMS OUTPUT. PUT LINE (
’ C o n t r a i n t e de c l é v i o l é e ! Message SQL : ’ | |
SQLERRM) ;
WHEN OTHERS THEN
RAISE Y A EU UNE MERDE ;
END;
END LOOP;
COMMIT;
EXCEPTION
WHEN Y A EU UNE MERDE THEN
DBMS OUTPUT. PUT LINE ( ’SQLCODE = ’ | | SQLCODE ) ;
DBMS OUTPUT. PUT LINE ( ’ I l y a eu une Merde ! ’ ) ;
ROLLBACK;
END;
/

−− E x e r c i c e 2

DECLARE
u n C l i e n t CLIENT%rowtype ;
BEGIN
SELECT ∗ INTO u n C l i e n t
FROM CLIENT WHERE numCli =
(
SELECT MAX( n u m c l i )
FROM CLIENT
);
INSERT INTO PERSONNEL VALUES
(
1,
unClient . nomcli ,
unClient . prenomcli ,
NULL,
1254.28
);
COMMIT;
EXCEPTION
WHEN NO DATA FOUND THEN
DBMS OUTPUT. PUT LINE ( ’ Aucun c l i e n t ’ ) ;
WHEN DUP VAL ON INDEX THEN
DBMS OUTPUT. PUT LINE (
’ I l y a un g r o s p r o b lè m e . . . J ” comprends pas c ” q u i s ” p a s s e ’ ) ;
END;
/

−− E x e r c i c e 3

113
DECLARE
numClient CLIENT . n u m c l i%TYPE;
tCCL TYPECCL. n u m t y p e c c l%TYPE;
n t o TYPEOPERATION. numtypeoper%TYPE;
Y A UN GRO BLEME EXCEPTION;
BEGIN
SELECT numtypeoper INTO n t o
FROM TYPEOPERATION
WHERE nomtypeoper = ’ dé p ô t e s p è c e s ’ ;
SELECT n u m t y p e c c l INTO tCCL
FROM TYPECCL
WHERE nomtypeCCL = ’ Compte c o u r a n t ’ ;
FOR numClient IN 1 . . 2 1 LOOP
BEGIN
INSERT INTO COMPTECLIENT VALUES
(
numClient ,
1,
tCCL ,
SYSDATE,
1
);
INSERT INTO OPERATION VALUES
(
numClient ,
1,
1,
nto ,
SYSDATE,
numClient ∗ 1 0 0 ,
’ i n a u g u r a t i o n du compte ’
);
COMMIT;
EXCEPTION
WHEN OTHERS THEN
−− Adaptez l e numéro du code ,
−− c h e z moi ça donne −2290
IF SQLCODE = −2290 THEN
DECLARE
t o t a l OPERATION. montantoper%TYPE := numClient ∗ 1 0 0 ;
t o I n s e r t OPERATION. montantoper%TYPE;
c p t NUMBER := 1 ;
BEGIN
WHILE t o t a l > 0 LOOP
IF t o t a l > 1000 THEN
t o I n s e r t := 1 0 0 0 ;
ELSE
t o I n s e r t := t o t a l ;
END IF ;
INSERT INTO OPERATION VALUES
(
numClient ,
1,
(SELECT n v l (MAX( numoper ) , 0 ) + 1
FROM OPERATION
WHERE n u m c l i = numClient
AND numccl = 1
),
nto ,
SYSDATE,
toInsert ,
’ I n a u g u r a t i o n du compte ’ | | c p t
);
t o t a l := t o t a l − t o I n s e r t ;
c p t := c p t + 1 ;
END LOOP;
EXCEPTION
WHEN OTHERS THEN
DBMS OUTPUT. PUT LINE ( ’MOD( t o t a l , 1 0 0 0 ) = ’ | | MOD( t o t a l , 1000));
DBMS OUTPUT. PUT LINE ( ’SQLCODE = ’ | | SQLCODE ) ;
DBMS OUTPUT. PUT LINE ( ’SQLERRM = ’ | | SQLERRM) ;
RAISE Y A UN GRO BLEME ;
END;
ELSE
DBMS OUTPUT. PUT LINE ( ’SQLCODE = ’ | | SQLCODE ) ;
DBMS OUTPUT. PUT LINE ( ’SQLERRM = ’ | | SQLERRM) ;
ROLLBACK;
END IF ;
END;
END LOOP;
EXCEPTION

114
WHEN NO DATA FOUND THEN
DBMS OUTPUT. PUT LINE ( ’ Pas de d o n né e s ! ’ ) ;
WHEN TOO MANY ROWS THEN
DBMS OUTPUT. PUT LINE ( ’ Trop de d o n né e s ! ’ ) ;
WHEN Y A UN GRO BLEME THEN
DBMS OUTPUT. PUT LINE ( ’ I l y a un g r o s p r o b lè m e ! ’ ) ;
DBMS OUTPUT. PUT LINE ( ’SQLCODE = ’ | | SQLCODE ) ;
DBMS OUTPUT. PUT LINE ( ’SQLERRM = ’ | | SQLERRM) ;
WHEN OTHERS THEN
DBMS OUTPUT. PUT LINE ( ’SQLCODE = ’ | | SQLCODE ) ;
DBMS OUTPUT. PUT LINE ( ’SQLERRM = ’ | | SQLERRM) ;
END;
/

−− E x e r c i c e 4

DECLARE
numClient CLIENT . n u m c l i%TYPE := 2 ;
numCompteLivret TYPECCL. numtypeCCL%TYPE;
n t o TYPEOPERATION. numtypeoper%TYPE;
montant OPERATION. montantoper%TYPE;
Y A UN GRO BLEME EXCEPTION;
BEGIN
SELECT numtypeoper INTO n t o
FROM TYPEOPERATION
WHERE nomtypeoper = ’ v i r e m e n t ’ ;
SELECT n u m t y p e c c l INTO numCompteLivret
FROM TYPECCL
WHERE nomtypeCcl = ’ l i v r e t ’ ;
WHILE numClient <= 21 LOOP
BEGIN
montant := 100 ∗ numClient − 5 0 0 ;
INSERT INTO COMPTECLIENT VALUES
(
numClient ,
2,
numCompteLivret ,
SYSDATE,
1
);
INSERT INTO OPERATION VALUES
(
numClient ,
1,
(SELECT n v l (MAX( numoper ) , 0 ) + 1
FROM OPERATION
WHERE n u m c l i = numClient
AND numccl = 1 ) ,
nto ,
SYSDATE,
−montant ,
’ versement l i v r e t ’
);
INSERT INTO OPERATION VALUES
(
numClient ,
2,
(SELECT n v l (MAX( numoper ) , 0 ) + 1
FROM OPERATION
WHERE n u m c l i = numClient
AND numccl = 2 ) ,
nto ,
SYSDATE,
montant ,
’ versement l i v r e t ’
);
COMMIT;
EXCEPTION
WHEN OTHERS THEN
−− idem
IF SQLCODE = −2290 THEN
DECLARE
t o t a l OPERATION. montantoper%TYPE := montant ;
toMove OPERATION. montantoper%TYPE;
c p t NUMBER := 1 ;
BEGIN
WHILE t o t a l > 1000 LOOP
IF t o t a l > 1000 THEN
toMove := 1 0 0 0 ;
ELSE
tomove := t o t a l ;

115
END IF ;
INSERT INTO OPERATION VALUES
(
numClient ,
1,
(SELECT n v l (MAX( numoper ) , 0 ) + 1
FROM OPERATION
WHERE n u m c l i = numClient
AND numccl = 1 ) ,
nto ,
SYSDATE,
−toMove ,
’ versement l i v r e t ’ | | cpt
);
INSERT INTO OPERATION VALUES
(
numClient ,
2,
(SELECT n v l (MAX( numoper ) , 0 ) + 1
FROM OPERATION
WHERE n u m c l i = numClient
AND numccl = 2 ) ,
nto ,
SYSDATE,
toMove ,
’ versement l i v r e t ’ | | cpt
);
t o t a l := t o t a l − toMove ;
c p t := c p t + 1 ;
END LOOP;
COMMIT;
EXCEPTION
WHEN OTHERS THEN
RAISE Y A UN GRO BLEME ;
END;
ELSE
DBMS OUTPUT. PUT LINE ( ’SQLCODE = ’ | | SQLCODE ) ;
DBMS OUTPUT. PUT LINE ( ’SQLERRM = ’ | | SQLERRM) ;
ROLLBACK;
END IF ;
END;
COMMIT;
numClient := numClient + 2 ;
END LOOP;
EXCEPTION
WHEN NO DATA FOUND THEN
DBMS OUTPUT. PUT LINE ( ’ Pas de d o n né e s ! ’ ) ;
WHEN TOO MANY ROWS THEN
DBMS OUTPUT. PUT LINE ( ’ Trop de d o n né e s ! ’ ) ;
WHEN Y A UN GRO BLEME THEN
DBMS OUTPUT. PUT LINE ( ’ I l y a un g r o s p r o b lè m e ! ’ ) ;
DBMS OUTPUT. PUT LINE ( ’SQLCODE = ’ | | SQLCODE ) ;
DBMS OUTPUT. PUT LINE ( ’SQLERRM = ’ | | SQLERRM) ;
WHEN OTHERS THEN
DBMS OUTPUT. PUT LINE ( ’SQLCODE = ’ | | SQLCODE ) ;
DBMS OUTPUT. PUT LINE ( ’SQLERRM = ’ | | SQLERRM) ;
END;
/

116
3.13 Sous-programmes
−− E x e r c i c e 1

CREATE OR REPLACE FUNCTION


b a d p u i s s a n c e ( b NUMBER, n NUMBER)
RETURN NUMBER I S
BEGIN
IF ( n = 0 ) THEN
RETURN 1 ;
ELSE
RETURN b ∗ b a d p u i s s a n c e ( b , n − 1 ) ;
END IF ;
END;
/

−− E x e r c i c e 2

CREATE OR REPLACE FUNCTION


g o o d p u i s s a n c e ( b NUMBER, n NUMBER)
RETURN NUMBER I S
BEGIN
IF ( n = 0 ) THEN
RETURN 1 ;
END IF ;
IF ( MOD( n , 2 ) = 0 ) THEN
RETURN g o o d p u i s s a n c e ( b ∗ b , n / 2 ) ;
END IF ;
RETURN b ∗ g o o d p u i s s a n c e ( b , n − 1 ) ;
END;
/

−− E x e r c i c e 3

CREATE OR REPLACE FUNCTION


d e m i F r e r e s (A PERSONNE. numpers%type , B PERSONNE. numpers%t y p e )
RETURN BOOLEAN I S
rowA PERSONNE%rowtype ;
rowB PERSONNE%rowtype ;
BEGIN
SELECT ∗ INTO rowA FROM PERSONNE WHERE numpers = A ;
SELECT ∗ INTO rowB FROM PERSONNE WHERE numpers = B ;
RETURN rowA . p e r e = rowB . p e r e OR rowA . mere = rowB . mere ;
END;
/

−− E x e r c i c e 4

CREATE OR REPLACE FUNCTION


f r e r e s (A PERSONNE. numpers%type , B PERSONNE. numpers%t y p e )
RETURN BOOLEAN I S
rowA PERSONNE%rowtype ;
rowB PERSONNE%rowtype ;
BEGIN
SELECT ∗ INTO rowA FROM PERSONNE WHERE numpers = A ;
SELECT ∗ INTO rowB FROM PERSONNE WHERE numpers = B ;
RETURN rowA . p e r e = rowB . p e r e AND rowA . mere = rowB . mere ;
END;
/

CREATE OR REPLACE FUNCTION


c o u s i n s G e r m a i n s (A PERSONNE. numpers%type , B PERSONNE. numpers%t y p e )
RETURN BOOLEAN I S
rowA PERSONNE%rowtype ;
rowB PERSONNE%rowtype ;
BEGIN
SELECT ∗ INTO rowA FROM PERSONNE WHERE numpers = A ;
SELECT ∗ INTO rowB FROM PERSONNE WHERE numpers = B ;
RETURN
f r e r e s ( rowA . p e r e , rowB . p e r e )
OR
f r e r e s ( rowA . p e r e , rowB . mere )
OR
f r e r e s ( rowA . mere , rowB . p e r e )
OR
f r e r e s ( rowA . mere , rowB . mere ) ;
END;
/

−− E x e r c i c e 5

117
CREATE OR REPLACE PROCEDURE
a i e u l (P PERSONNE. numpers%t y p e ) I S
row PERSONNE%rowtype ;
nb NUMBER;
BEGIN
SELECT count ( ∗ ) INTO NB
FROM PERSONNE
WHERE numpers = P ;
IF (NB = 1 ) THEN
SELECT ∗ INTO row
FROM PERSONNE
WHERE numpers = P ;
DBMS OUTPUT. PUT LINE ( row . nom ) ;
a i e u l ( row . p e r e ) ;
END IF ;
END;
/

−− E x e r c i c e 6

CREATE OR REPLACE PROCEDURE


mecs (P PERSONNE. numpers%t y p e ) I S
row PERSONNE%rowtype ;
nb NUMBER;
BEGIN
SELECT count ( ∗ ) INTO NB
FROM PERSONNE
WHERE numpers = P ;
IF (NB = 1 ) THEN
SELECT ∗ INTO row
FROM PERSONNE
WHERE numpers = P ;
SELECT count ( ∗ ) INTO NB
FROM PERSONNE
WHERE p e r e = P ;
IF (NB > 0 ) THEN
DBMS OUTPUT. PUT LINE ( row . nom ) ;
END IF ;
mecs ( row . p e r e ) ;
mecs ( row . mere ) ;
END IF ;
END;
/

−− E x e r c i c e 7

CREATE OR REPLACE FUNCTION


a s c e n d a n t (A PERSONNE. numpers%type , B PERSONNE. numpers%t y p e )
RETURN BOOLEAN I S
row PERSONNE%rowtype ;
BEGIN
SELECT ∗ INTO row FROM PERSONNE WHERE numpers = B ;
IF ( row . p e r e = A OR row . mere = A) THEN
RETURN TRUE;
END IF ;
RETURN ( row . p e r e I S NOT NULL AND a s c e n d a n t (A, row . p e r e ) )
OR
( row . mere I S NOT NULL AND a s c e n d a n t (A, row . mere ) ) ;

END;
/

BEGIN
IF ( a s c e n d a n t ( 1 , 8 ) ) THEN
DBMS OUTPUT. PUT LINE ( ’OK ’ ) ;
ELSE
DBMS OUTPUT. PUT LINE ( ’ pas OK ’ ) ;
END IF ;
END;
/

−− E x e r c i c e 8

CREATE OR REPLACE FUNCTION


fmax (A NUMBER, B NUMBER)
RETURN NUMBER I S
BEGIN
IF (A > B) THEN
RETURN A ;
ELSE
RETURN B ;

118
END IF ;
END;
/

CREATE OR REPLACE FUNCTION


e c a r t A s c e n d a n t (A PERSONNE. numpers%type , B PERSONNE. numpers%t y p e )
RETURN NUMBER I S
row PERSONNE%rowtype ;
NB NUMBER;
BEGIN
SELECT ∗ INTO row FROM PERSONNE WHERE numpers = B ;
IF ( row . p e r e = A OR row . mere = A) THEN
RETURN 1 ;
END IF ;
IF ( row . p e r e I S NULL) THEN
NB := −1;
ELSE
NB := e c a r t A s c e n d a n t (A, row . p e r e ) ;
END IF ;
IF ( row . mere I S NULL) THEN
NB := fmax ( −1 , NB ) ;
ELSE
NB := fmax ( e c a r t A s c e n d a n t (A, row . p e r e ) , NB ) ;
END IF ;
IF (NB <> −1) THEN
NB := NB + 1 ;
END IF ;
RETURN NB;
END;
/

CREATE OR REPLACE FUNCTION


e c a r t (A PERSONNE. numpers%type , B PERSONNE. numpers%t y p e )
RETURN NUMBER I S
row PERSONNE%rowtype ;
NB NUMBER;
BEGIN
RETURN fmax ( e c a r t A s c e n d a n t (A, B) , e c a r t A s c e n d a n t (B , A ) ) ;
END;
/

−− E x e r c i c e 9

SELECT A. nom , A . prenom , B . nom , B . prenom


FROM PERSONNE A, PERSONNE B
WHERE e c a r t A s c e n d a n t (A . numpers , B . numpers ) =
(
SELECT MAX( e c )
FROM
(
SELECT e c a r t (A . numpers , B . numpers ) AS e c
FROM PERSONNE A, PERSONNE B
)
);

−− E x e r c i c e 10

119
3.14 Curseurs
CREATE OR REPLACE PROCEDURE copyFromPersonneToClient I S
CURSOR C I S
SELECT ∗
FROM PERSONNE;
ROW C%rowtype ;
BEGIN
FOR ROW IN C LOOP
INSERT INTO CLIENT
( numcli , n o m c l i , p r e n o m c l i )
VALUES
(ROW. numpers , ROW. nom , ROW. prenom ) ;
END LOOP;
COMMIT;
EXCEPTION
WHEN DUP VAL ON INDEX THEN
DBMS OUTPUT. PUT LINE ( ’ Copy can be done o n l y o n c e . ’ ) ;
END;
/

CALL copyFromPersonneToClient ( ) ;

CREATE OR REPLACE PROCEDURE t a k e C l i e n t T o P e r s o n n e l I S


Row c l i e n t%rowtype ;
BEGIN
SELECT ∗ INTO Row
FROM CLIENT
WHERE n u m c l i =
(
SELECT MAX( n u m c l i )
FROM CLIENT ) ;
INSERT INTO PERSONNEL
( numpers , nompers , prenompers )
VALUES
(Row . numcli , Row . n o m c l i , Row . p r e n o m c l i ) ;
COMMIT;
EXCEPTION
WHEN DUP VAL ON INDEX THEN
DBMS OUTPUT. PUT LINE ( ’ T h i s row has a l r e a d y been i m p o r t e d . ’ ) ;
ROLLBACK;
WHEN NO DATA FOUND THEN
DBMS OUTPUT. PUT LINE ( ’ Table CLIENT i s empty . ’ ) ;
ROLLBACK;
END;
/

CALL t a k e C l i e n t T o P e r s o n n e l ( ) ;

CREATE OR REPLACE PROCEDURE


c r e d i t A c c o u n t ( n u m c l i e n t CLIENT . n u m c l i%type , value NUMBER) I S
BEGIN
IF ( value > 1 0 0 ) THEN
creditAccount ( numclient , 1 0 0 ) ;
c r e d i t A c c o u n t ( n u m c l i e n t , value − 1 0 0 ) ;
ELSE
INSERT INTO OPERATION VALUES
( numclient ,
1,
(SELECT n v l (MAX( numoper ) , 0 ) + 1
FROM OPERATION
WHERE n u m c l i = n u m c l i e n t
AND numccl = 1
),
(SELECT numtypeoper
FROM TYPEOPERATION
WHERE nomtypeoper = ’ v i r e m e n t ’
),
sysdate ,
value ,
’ cadeau ! ’
);
END IF ;
EXCEPTION
WHEN OTHERS THEN
IF (SQLCODE = −22900) THEN
DBMS OUTPUT. PUT LINE ( ’ Too much money a t o n c e . ’ ) ;
END IF ;
END;
/

120
CREATE OR REPLACE PROCEDURE
c r e a t e V i r e m e n t ( n u m c l i e n t CLIENT . n u m c l i%type , value NUMBER) I S
BEGIN
INSERT INTO OPERATION VALUES
( numclient ,
1,
(SELECT n v l (MAX( numoper ) , 0 ) + 1
FROM OPERATION
WHERE n u m c l i = n u m c l i e n t
AND numccl = 1
),
(SELECT numtypeoper
FROM TYPEOPERATION
WHERE nomtypeoper = ’ v i r e m e n t ’
),
sysdate ,
−value ,
’ cadeau ! ’
);
INSERT INTO OPERATION VALUES
( numclient ,
2,
(SELECT n v l (MAX( numoper ) , 0 ) + 1
FROM OPERATION
WHERE n u m c l i = n u m c l i e n t
AND numccl = 1
),
(SELECT numtypeoper
FROM TYPEOPERATION
WHERE nomtypeoper = ’ v i r e m e n t ’
),
sysdate ,
value ,
’ cadeau ! ’
);
EXCEPTION
WHEN OTHERS THEN
IF (SQLCODE = −22900) THEN
DBMS OUTPUT. PUT LINE ( ’ Too much money a t o n c e . ’ ) ;
END IF ;
END;
/

CREATE OR REPLACE PROCEDURE


moveToLivret ( n u m c l i e n t CLIENT . n u m c l i%type , value NUMBER) I S
BEGIN
IF ( value >= 0 ) THEN
IF ( value > 1 0 0 ) THEN
moveToLivret ( n u m c l i e n t , 1 0 0 ) ;
moveToLivret ( n u m c l i e n t , value − 1 0 0 ) ;
ELSE
c r e a t e V i r e m e n t ( n u m c l i e n t , value ) ;
END IF ;
END IF ;
EXCEPTION
WHEN OTHERS THEN
IF (SQLCODE = −22900) THEN
DBMS OUTPUT. PUT LINE ( ’ Too much money a t o n c e . ’ ) ;
END IF ;
END;
/

CREATE OR REPLACE PROCEDURE


openAccount ( n u m c l i e n t CLIENT . n u m c l i%t y p e ) I S
BEGIN
INSERT INTO COMPTECLIENT VALUES
( numclient ,
1,
(SELECT n u m t y p e c c l
FROM TYPECCL
WHERE n o m t y p e c c l = ’ Compte c o u r a n t ’
),
sysdate ,
(SELECT numpers
FROM PERSONNEL
WHERE numpers =
(
SELECT MAX( n u m c l i )
FROM CLIENT
)
)

121
);
INSERT INTO COMPTECLIENT VALUES
( numclient ,
2,
(SELECT n u m t y p e c c l
FROM TYPECCL
WHERE n o m t y p e c c l = ’ v i r e m e n t ’
),
sysdate ,
(SELECT numpers
FROM PERSONNEL
WHERE numpers =
(
SELECT MAX( n u m c l i )
FROM CLIENT
)
)
);
creditAccount ( numclient , numclient ∗ 1 0 0 ) ;
moveToLivret ( n u m c l i e n t , n u m c l i e n t ∗ 100 − 5 0 0 ) ;
EXCEPTION
WHEN DUP VAL ON INDEX THEN
DBMS OUTPUT. PUT LINE ( ’ T h i s a c c o u n t h as a l r e a d y been opened . ’ ) ;
END;
/

CREATE OR REPLACE PROCEDURE openAccounts I S


CURSOR C I S
SELECT n u m c l i FROM CLIENT ;
ROW C%rowtype ;
BEGIN
FOR ROW IN C LOOP
openAccount (ROW. n u m c l i ) ;
END LOOP;
COMMIT;
EXCEPTION
WHEN OTHERS THEN
DBMS OUTPUT. PUT LINE ( ’An e r r o r has o c c u r r e d . ’ ) ;
ROLLBACK;
END;
/

CALL openAccounts ( ) ;

CREATE OR REPLACE PROCEDURE


a f f i c h e D e s c e n d a n c e ( numpersonne NUMBER) I S
CURSOR C I S
SELECT ∗
FROM PERSONNE
WHERE p e r e = numpersonne
OR mere = numpersonne ;
ROW C%rowType ;
BEGIN
FOR ROW IN C LOOP
DBMS OUTPUT. PUT LINE ( row . nom | | ’ ’ | | row . prenom ) ;
a f f i c h e D e s c e n d a n c e (ROW. numpers ) ;
END LOOP;
END;
/

122
3.15 Curseurs paramétrés
−− E x e r c i c e 1

CREATE OR REPLACE PROCEDURE a f f i c h e C l i e n t ( u n C l i e n t CLIENT%rowtype ) I S


BEGIN
DBMS OUTPUT. PUT LINE ( ’ C l i e n t ’ | | u n C l i e n t . p r e n o m c l i | | ’ ’ | | u n C l i e n t . nomCli ) ;
END;
/

CREATE OR REPLACE PROCEDURE a f f i c h e C o m p t e ( unCompte COMPTECLIENT%rowtype ) I S


BEGIN
DBMS OUTPUT. PUT LINE ( ’ ∗ Compte ’ | | unCompte . numCli | | ’− ’ | | unCompte . numccl ) ;
END;
/

CREATE OR REPLACE PROCEDURE a f f i c h e C o m p t e s C l i e n t s I S


CURSOR c l i e n t s I S
SELECT ∗
FROM CLIENT ;
u n C l i e n t c l i e n t s%rowtype ;
CURSOR comptes ( n u m c l i e n t CLIENT . n u m c l i%t y p e ) I S
SELECT ∗
FROM COMPTECLIENT
WHERE n u m c l i = n u m c l i e n t ;
unCompte c l i e n t s%rowtype ;
BEGIN
FOR u n C l i e n t IN c l i e n t s LOOP
a f f i c h e C l i e n t ( unClient ) ;
FOR unCompte IN comptes ( u n C l i e n t . n u m c l i ) LOOP
a f f i c h e C o m p t e ( unCompte ) ;
END LOOP;
END LOOP;
END;
/

SET SERVEROUTPUT ON SIZE 1 00 00 0 0

call afficheComptesClients ( ) ;

−− E x e r c i c e 2

CREATE OR REPLACE PROCEDURE a f f i c h e O p e r a t i o n ( u n e O p e r a t i o n OPERATION%rowtype ) I S


BEGIN
DBMS OUTPUT. PUT LINE ( ’ ∗ ∗ O p e r a t i o n ’ | | u n e O p e r a t i o n . numOper | | ’ , montant : ’ || u n e O p e r a t i o n . mon
END;
/

CREATE OR REPLACE PROCEDURE a f f i c h e O p e r C o m p t e s C l i e n t s I S


CURSOR c l i e n t s I S
SELECT ∗
FROM CLIENT ;
u n C l i e n t c l i e n t s%rowtype ;
CURSOR comptes ( n u m c l i e n t CLIENT . n u m c l i%t y p e ) I S
SELECT ∗
FROM COMPTECLIENT
WHERE n u m c l i = n u m c l i e n t ;
unCompte c l i e n t s%rowtype ;
CURSOR o p e r a t i o n s
( n u m c l i e n t CLIENT . n u m c l i%type ,
numcompte COMPTECLIENT. numccl%t y p e ) I S
SELECT ∗
FROM OPERATION
WHERE n u m c l i = n u m c l i e n t
AND numccl = numcompte ;
u n e O p e r a t i o n o p e r a t i o n s%rowtype ;
BEGIN
FOR u n C l i e n t IN c l i e n t s LOOP
a f f i c h e C l i e n t ( unClient ) ;
FOR unCompte IN comptes ( u n C l i e n t . n u m c l i ) LOOP
a f f i c h e C o m p t e ( unCompte ) ;
FOR u n e O p e r a t i o n IN o p e r a t i o n s ( u n C l i e n t . numcli , unCompte . numccl ) LOOP
a f f i c h e O p e r a t i o n ( uneOperation ) ;
END LOOP;
END LOOP;
END LOOP;
END;
/

call afficheOperComptesClients ( ) ;

123
3.16 Triggers
−− I l c o n v i e n t d ’ abord de m o d i f i e r q u e l q u e peu l ’ o r g a n i s a t i o n d e s
−− donnees , on a j o u t e par exemple dans l a t a b l e MODULE l e nombre
−− d ’ e t u d i a n t s i n s c r i t s

DROP TABLE RESULTAT;


DROP TABLE EXAMEN;
DROP TABLE PREREQUIS ;
DROP TABLE INSCRIPTION ;
DROP TABLE MODULE;
DROP TABLE ETUDIANT;

CREATE TABLE ETUDIANT


( numEtud number ,
nom varchar2 ( 4 0 ) ,
prenom varchar2 ( 4 0 ) ,
d a t e n a i s s date ,
c i v i l i t e varchar2 ( 4 ) ,
patronyme varchar2 ( 4 0 ) ,
numsecu varchar2 ( 1 5 ) NOT NULL,
moyenne NUMBER DEFAULT NULL) ;

CREATE TABLE MODULE


( codMod number ,
nomMod varchar2 ( 1 5 ) ,
e f f e c M a x number DEFAULT 3 0 ,
e f f e c number d e f a u l t 0 ) ;

CREATE TABLE EXAMEN


( codMod number ,
codExam number ,
dateExam date ) ;

CREATE TABLE INSCRIPTION


( numEtud number ,
codMod number ,
d a t e I n s c date d e f a u l t s y s d a t e ) ;

CREATE TABLE PREREQUIS


( codMod number ,
codModPrereq number ,
noteMin number ( 4 , 2 ) NOT NULL) ;

CREATE TABLE RESULTAT


( codMod number ,
codExam number ,
numEtud number ,
n o t e number ( 4 , 2 ) ) ;

ALTER TABLE ETUDIANT ADD


CONSTRAINT p k e t u d i a n t
PRIMARY KEY ( numEtud ) ;
ALTER TABLE MODULE ADD
CONSTRAINT pk module
PRIMARY KEY ( codMod ) ;
ALTER TABLE EXAMEN ADD
CONSTRAINT pk examen
PRIMARY KEY ( codMod , codExam ) ;
ALTER TABLE PREREQUIS ADD
CONSTRAINT p k p r e r e q u i s
PRIMARY KEY ( codMod , codModPrereq ) ;
ALTER TABLE INSCRIPTION ADD
CONSTRAINT p k i n s c r i p t i o n
PRIMARY KEY ( codMod , numEtud ) ;
ALTER TABLE RESULTAT ADD
CONSTRAINT p k r e s u l t a t
PRIMARY KEY ( codMod , numEtud , codExam ) ;

ALTER TABLE INSCRIPTION ADD


(CONSTRAINT f k i n s c r i p t i o n e t u d i a n t
FOREIGN KEY ( numEtud )
REFERENCES ETUDIANT( numEtud ) ,
CONSTRAINT f k i n s c r i p t i o n m o d u l e
FOREIGN KEY ( codMod )
REFERENCES MODULE( codMod ) ) ;
ALTER TABLE PREREQUIS ADD
(CONSTRAINT f k p r e r e q u i s c o d m o d
FOREIGN KEY ( codMod )
REFERENCES MODULE( codMod ) ,
CONSTRAINT f k p r e r e q u i s c o d m o d p r e r e q

124
FOREIGN KEY ( codModPrereq )
REFERENCES MODULE( codMod ) ) ;
ALTER TABLE EXAMEN ADD
CONSTRAINT f k e x a m e n
FOREIGN KEY ( codMod )
REFERENCES MODULE( codMod ) ;
ALTER TABLE RESULTAT ADD
(CONSTRAINT f k r e s u l t a t e x a m e n
FOREIGN KEY ( codMod , codExam )
REFERENCES EXAMEN( codMod , codExam ) ,
CONSTRAINT f k r e s u l t a t i n s c r i p t i o n
FOREIGN KEY ( codMod , numEtud )
REFERENCES INSCRIPTION ( codMod , numEtud ) ) ;

ALTER TABLE ETUDIANT ADD


(CONSTRAINT c k c i v i l i t e
CHECK
(
c i v i l i t e IN ( ’Mr ’ , ’Mme ’ , ’ M l l e ’ )
),
CONSTRAINT c k c i v i l i t e n u m s e c u
CHECK
(
SUBSTR( numsecu , 1 , 1 ) = ’ 2 ’ OR patronyme I S NULL
),
CONSTRAINT c k l e n g t h n u m s e c u
CHECK
(
l e n g t h ( numsecu ) = 15
),
CONSTRAINT c k a n n e e n u m s e c u CHECK
(
t o c h a r ( d a t e n a i s s , ’ yy ’ ) = substr ( numsecu , 2 , 2 )
)
);

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−− C o n t r a i n t e 1 −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

CREATE OR REPLACE TRIGGER b e f o r e U p d a t e F E R P r e r e q u i s


BEFORE UPDATE ON PREREQUIS
FOR EACH ROW
BEGIN
IF ( : new . noteMin < : o l d . noteMin ) THEN
: new . noteMin := : o l d . noteMin ;
END IF ;
END;
/

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−− C o n t r a i n t e 2 −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

CREATE OR REPLACE PROCEDURE i n c r E f f e c ( module NUMBER) I S


BEGIN
UPDATE MODULE SET e f f e c = e f f e c + 1 WHERE codmod = module ;
END;
/

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

CREATE OR REPLACE PROCEDURE d e c r E f f e c ( module NUMBER) I S


BEGIN
UPDATE MODULE SET e f f e c = e f f e c − 1 WHERE codmod = module ;
END;
/

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

CREATE OR REPLACE TRIGGER B e f o r e I n s e r t F E R M o d u l e


BEFORE INSERT ON MODULE
FOR EACH ROW
BEGIN
: new . e f f e c := 0 ;
END;

125
/

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

CREATE OR REPLACE TRIGGER a f t e r I n s e r t F E R I n s c


AFTER INSERT ON INSCRIPTION
FOR EACH ROW
BEGIN
i n c r E f f e c ( : new . codmod ) ;
END;
/

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

CREATE OR REPLACE TRIGGER a f t e r D e l e t e F E R I n s c


AFTER DELETE ON INSCRIPTION
FOR EACH ROW
BEGIN
d e c r E f f e c ( : o l d . codmod ) ;
END;
/

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

CREATE OR REPLACE TRIGGER a f t e r U p d a t e F E R I n s c


AFTER UPDATE ON INSCRIPTION
FOR EACH ROW
BEGIN
d e c r E f f e c ( : o l d . codmod ) ;
i n c r E f f e c ( : new . codmod ) ;
END;
/

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

DROP VIEW m o d u l e s D i s p o n i b l e s ;

CREATE VIEW m o d u l e s D i s p o n i b l e s AS
SELECT codmod
FROM MODULE
WHERE e f f e c < e f f e c M a x ;

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

CREATE OR REPLACE TRIGGER b e f o r e I n s e r t U p d a t e F E R I n s c


BEFORE INSERT OR UPDATE ON INSCRIPTION
FOR EACH ROW
DECLARE
n b L i g n e s NUMBER;
BEGIN
SELECT count ( ∗ ) INTO n b L i g n e s
FROM m o d u l e s D i s p o n i b l e s
WHERE codmod = : new . codmod ;
IF ( n b L i g n e s = 0 ) THEN
RAISE APPLICATION ERROR( −20001 , ’ P l u s de p l a c e s diponibles . ’ );
END IF ;
END;
/

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−− C o n t r a i n t e 3 −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

DROP VIEW e x a m e n s P o s s i b l e s ;

CREATE VIEW e x a m e n s P o s s i b l e s AS
SELECT codMod
FROM MODULE M
WHERE
(
SELECT COUNT( ∗ )

126
FROM INSCRIPTION I
WHERE I . codmod = M. codmod
) > 0 ;

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

CREATE OR REPLACE TRIGGER beforeInsertUpdateFERExam


BEFORE INSERT OR UPDATE ON EXAMEN
FOR EACH ROW
DECLARE
n b L i g n e s NUMBER;
BEGIN
SELECT count ( ∗ ) INTO n b L i g n e s
FROM e x a m e n s P o s s i b l e s
WHERE codMod = : new . codmod ;
IF ( n b L i g n e s = 0 ) THEN
RAISE APPLICATION ERROR( −20002 , ’ Pas d” é l è v e dans c e module . ’ ) ;
END IF ;
END;
/

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−− C o n t r a i n t e 4 −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

DROP VIEW e t u d i a n t s E x a m e n s ;

CREATE VIEW e t u d i a n t s E x a m e n s AS
SELECT I . numetud , E . codmod , E . codexam
FROM INSCRIPTION I , EXAMEN E
WHERE I . codmod = E . codmod
AND I . d a t e I n s c < E . dateExam ;

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

CREATE OR REPLACE TRIGGER b e f o r e I n s e r t U p d a t e F E R R e s u l t


BEFORE INSERT OR UPDATE ON RESULTAT
FOR EACH ROW
DECLARE
n b L i g n e s NUMBER;
BEGIN
SELECT count ( ∗ ) INTO n b L i g n e s
FROM e t u d i a n t s E x a m e n s
WHERE numetud = : new . numetud
AND codmod = : new . codmod
AND codexam = : new . codexam ;
IF ( n b L i g n e s = 0 ) THEN
RAISE APPLICATION ERROR( −20002 , ’ Examen a n t é r i e u r à l ” i n s c r i p t i o n dans l e module . ’ ) ;
END IF ;
END;
/

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−− C o n t r a i n t e 5 −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

−− On c ré e une t a b l e t e m p o r a i r e c o n t e n a n t l e s mêmes v a l e u r s que p r e r e q u i s ,


−− On l a met à j o u r AVANT l a t a b l e p r e r e q u i s pour v é r i f i e r que l ’ i n s e r t i o n
−− ne c o n s t r u i t pas de c i r c u i t .

DROP TABLE MIRRORPREREQ;

CREATE TABLE MIRRORPREREQ


( codmod NUMBER,
codmodprereq NUMBER,
noteMin NUMBER) ;

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

CREATE OR REPLACE FUNCTION


f i n d M o d u l e ( r o o t number , moduleToFind number)
RETURN BOOLEAN
IS
CURSOR C I S

127
SELECT codmod
FROM MIRRORPREREQ
WHERE codmodprereq = r o o t ;
SON C%rowtype ;
BEGIN
FOR SON IN C LOOP
IF
( son . codmod = moduleToFind OR
f i n d M o d u l e ( son . codmod , moduleToFind ) )
THEN
RETURN TRUE;
END IF ;
END LOOP;
RETURN FALSE;
END;
/

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

CREATE OR REPLACE PROCEDURE


i n s e r t M i r r o r P r e r e q ( codmodValue NUMBER, codmodprereqValue NUMBER, n o t e NUMBER) I S
BEGIN
INSERT INTO MIRRORPREREQ
( codmod , codmodprereq , noteMin )
VALUES
( codmodValue , codmodprereqValue , n o t e ) ;
END;
/

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

CREATE OR REPLACE PROCEDURE


d e l e t e M i r r o r P r e r e q ( codmodValue NUMBER, codmodprereqValue NUMBER) I S
BEGIN
DELETE FROM MIRRORPREREQ
WHERE codmod = codmodValue
AND codmodprereq = codmodprereqValue ;
END;
/

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

CREATE OR REPLACE PROCEDURE


updateMirrorPrereq
( codmodValue NUMBER,
codmodNewValue NUMBER,
codmodprereqValue NUMBER,
codmodprereqNewValue NUMBER,
newNote NUMBER) I S
BEGIN
UPDATE MIRRORPREREQ SET
codmod = codmodNewValue ,
codmodprereq = codmodprereqNewValue ,
noteMin = newNote
WHERE codmod = codmodValue
AND codmodprereq = codmodprereqValue ;
END;
/

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

CREATE OR REPLACE TRIGGER a f t e r D e l e t e F E R P r e r e q


AFTER DELETE ON PREREQUIS
FOR EACH ROW
BEGIN
d e l e t e M i r r o r P r e r e q ( : o l d . codmod , : o l d . codmodprereq ) ;
END;
/

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

128
CREATE OR REPLACE TRIGGER b e f o r e I n s e r t U p d a t e F E R P r e r e q
BEFORE INSERT OR UPDATE ON PREREQUIS
FOR EACH ROW
BEGIN
IF INSERTING THEN
i n s e r t M i r r o r P r e r e q ( : new . codmod , : new . codmodprereq , : new . noteMin ) ;
END IF ;
IF UPDATING THEN
u p d a t e M i r r o r P r e r e q ( : o l d . codmod , : new . codmod ,
: o l d . codmodprereq , : new . codmodprereq , : new . noteMin ) ;
END IF ;
IF ( f i n d M o d u l e ( : new . codmod , : new . codmod ) ) THEN
IF INSERTING THEN
d e l e t e M i r r o r P r e r e q ( : new . codmod , : new . codmodprereq ) ;
END IF ;
IF UPDATING THEN
u p d a t e M i r r o r P r e r e q ( : new . codmod , : o l d . codmod ,
: new . codmodprereq , : o l d . codmodprereq , : o l d . noteMin ) ;
END IF ;
RAISE APPLICATION ERROR( −20003 , ’ C i r c u i t dans p r e r e q u i s . ’ ) ;
END IF ;
END;
/

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−− C o n t r a i n t e 6 −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

CREATE OR REPLACE FUNCTION


c h e c k I n s c r i p t i o n ( e t u d NUMBER, mod NUMBER)
RETURN BOOLEAN
IS
CURSOR p r e r e q I S
SELECT noteMin , codmodprereq
FROM MIRRORPREREQ
WHERE codmod = mod ;
p p r e r e q%rowtype ;
n b L i g n e s NUMBER;
BEGIN
FOR p IN p r e r e q LOOP
SELECT count ( ∗ ) INTO n b L i g n e s
FROM RESULTAT
WHERE codmod = p . codmodprereq
AND numetud = e t u d
AND n o t e < p . noteMin ;
IF ( n b L i g n e s = 0 ) THEN
RETURN FALSE;
END IF ;
END LOOP;
RETURN TRUE;
END;
/

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

CREATE OR REPLACE TRIGGER b e f o r e I n s e r t U p d a t e F E R I n s c


BEFORE INSERT OR UPDATE ON INSCRIPTION
FOR EACH ROW
DECLARE
n b L i g n e s NUMBER;
BEGIN
SELECT count ( ∗ ) INTO n b L i g n e s
FROM m o d u l e s D i s p o n i b l e s
WHERE codmod = : new . codmod ;
IF ( n b L i g n e s = 0 ) THEN
RAISE APPLICATION ERROR( −20001 , ’ P l u s de p l a c e s d i p o n i b l e s . ’ ) ;
END IF ;
IF (NOT( c h e c k I n s c r i p t i o n ( : new . numetud , : new . codmod ) ) ) THEN
RAISE APPLICATION ERROR( −20004 , ’ P r é r e q u i s non s a t i s f a i t . ’ ) ;
END IF ;
END;
/

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−− C o n t r a i n t e 7 −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

−− La a u s s i un probleme s e pose , on ne p e u t pas f a i r e de r e q u e t e s u r


−− l a t a b l e r e s u l t a t , comme de p l u s , on t i e n t à p r e n d r e pour chaque e t u d i a n t

129
−− l e m e i l l e u r e n o t e dans chaque module , on c r e e une t a b l e t e m p o r a i r e c o n t e n a n t
−− l e s n o t e s o b e t n u e s par l e s e l e v e s .

DROP TABLE MIRRORRESULT;

CREATE TABLE MIRRORRESULT


( numetud NUMBER,
codmod NUMBER,
codexam NUMBER,
n o t e NUMBER,
PRIMARY KEY( numetud , codmod , codexam )
);

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

DROP VIEW MEILLEURENOTE;

CREATE VIEW MEILLEURENOTE AS


SELECT numetud , codmod , MAX( n o t e ) AS noteMax
FROM MIRRORRESULT
GROUP BY numetud , codmod ;

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

DROP VIEW NOMBREINSCRIPTIONs ;

CREATE VIEW NOMBREINSCRIPTIONS AS


SELECT numetud ,
(
SELECT COUNT( ∗ )
FROM INSCRIPTION I
WHERE I . numetud = E . numetud
) AS n b I n s c r i p t i o n s
FROM ETUDIANT E ;

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

DROP VIEW NOMBRENOTES;

CREATE VIEW NOMBRENOTES AS


SELECT numetud ,
(SELECT COUNT( ∗ ) AS nbNotes
FROM MEILLEURENOTE M
WHERE M. numetud = E . numetud
) AS nbNotes
FROM ETUDIANT E ;

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

CREATE OR REPLACE PROCEDURE


updateMoyenne ( e t u d NUMBER)
IS
nbNotes NUMBER;
n b I n s c r i p t i o n s NUMBER;
BEGIN
SELECT nbNotes INTO nbNotes
FROM NOMBRENOTES
WHERE numetud = e t u d ;
SELECT n b I n s c r i p t i o n s INTO n b I N s c r i p t i o n s
FROM NOMBREINSCRIPTIONS
WHERE numetud = e t u d ;
IF ( nbNotes = n b I n s c r i p t i o n s ) THEN
UPDATE ETUDIANT SET moyenne =
(SELECT AVG( noteMax )
FROM MEILLEURENOTE
WHERE numetud = e t u d
)
WHERE numetud = e t u d ;
ELSE
UPDATE ETUDIANT SET
moyenne = NULL
WHERE numetud = e t u d ;
END IF ;

130
END;
/

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

CREATE OR REPLACE TRIGGER a f t e r I n s e r t F E R R e s u l t


AFTER INSERT ON RESULTAT
FOR EACH ROW
BEGIN
INSERT INTO MIRRORRESULT VALUES
( : new . numetud , : new . codmod , : new . codexam , : new . n o t e ) ;
updateMoyenne ( : new . numetud ) ;
END;
/

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

CREATE OR REPLACE TRIGGER a f t e r U p d a t e F E R R e s u l t


AFTER UPDATE ON RESULTAT
FOR EACH ROW
BEGIN
UPDATE MIRRORRESULT SET
numetud = : new . numetud ,
codmod = : new . codmod ,
codexam = : new . codexam ,
n o t e = : new . n o t e
WHERE numetud = : o l d . numetud
AND codmod = : o l d . codmod
AND codexam = : o l d . codexam ;
updateMoyenne ( : new . numetud ) ;
END;
/

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

CREATE OR REPLACE TRIGGER a f t e r D e l e t e F E R R e s u l t


AFTER DELETE ON RESULTAT
FOR EACH ROW
BEGIN
DELETE FROM MIRRORRESULT
WHERE numetud = : new . numetud
AND codmod = : new . codmod
AND codexam = : new . codexam ;
updateMoyenne ( : new . numetud ) ;
END;
/

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−− C o n t r a i n t e 9 −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

CREATE OR REPLACE FUNCTION


checkAllStudents
RETURN BOOLEAN
IS
CURSOR C I S
SELECT numetud , codmod
FROM INSCRIPTION ;
e C%rowtype ;
BEGIN
FOR e IN C LOOP
IF (NOT( c h e c k I n s c r i p t i o n ( e . numetud , e . codmod ) ) ) THEN
RETURN FALSE;
END IF ;
END LOOP;
RETURN TRUE;
END;
/

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

CREATE OR REPLACE TRIGGER BeforeUpdateFERModule


BEFORE UPDATE ON MODULE

131
FOR EACH ROW
BEGIN
IF ( : new . e f f e c m a x < : new . e f f e c ) THEN
RAISE APPLICATION ERROR( −20005 ,
’ L e f f e c t i f ne p e u t ê t r e en d e s s o u s de ’ || : new . e f f e c ) ;
END IF ;
END;
/

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−− C o n t r a i n t e 8 −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

CREATE OR REPLACE TRIGGER b e f o r e I n s e r t U p d a t e F E R P r e r e q


BEFORE INSERT OR UPDATE ON PREREQUIS
FOR EACH ROW
BEGIN
IF INSERTING THEN
i n s e r t M i r r o r P r e r e q ( : new . codmod , : new . codmodprereq , : new . noteMin ) ;
END IF ;
IF UPDATING THEN
u p d a t e M i r r o r P r e r e q ( : o l d . codmod , : new . codmod ,
: o l d . codmodprereq , : new . codmodprereq , : new . noteMin ) ;
END IF ;
IF ( f i n d M o d u l e ( : new . codmod , : new . codmod ) ) THEN
IF INSERTING THEN
d e l e t e M i r r o r P r e r e q ( : new . codmod , : new . codmodprereq ) ;
END IF ;
IF UPDATING THEN
u p d a t e M i r r o r P r e r e q ( : new . codmod , : o l d . codmod ,
: new . codmodprereq , : o l d . codmodprereq , : o l d . noteMin ) ;
END IF ;
RAISE APPLICATION ERROR( −20003 , ’ C i r c u i t dans p r e r e q u i s . ’ ) ;
END IF ;
IF (NOT( c h e c k A l l S t u d e n t s ( ) ) ) THEN
IF INSERTING THEN
d e l e t e M i r r o r P r e r e q ( : new . codmod , : new . codmodprereq ) ;
END IF ;
IF UPDATING THEN
u p d a t e M i r r o r P r e r e q ( : new . codmod , : o l d . codmod ,
: new . codmodprereq , : o l d . codmodprereq , : o l d . noteMin ) ;
END IF ;
RAISE APPLICATION ERROR( −20006 , ’ I m p o s s i b l e de d i m i n u e r c e t t e n o t e . ’ ) ;
END IF ;
END;
/

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−− Quelques i n s e r t i o n s pour t e s t e r −−−−−−−−−−−−−−−−
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

INSERT INTO ETUDIANT VALUES


(
(SELECT n v l (MAX( numEtud ) , 0 ) + 1 FROM ETUDIANT) ,
’ Fourier ’ ,
’ Joseph ’ ,
t o d a t e ( ’ 2 1 0 3 1 7 6 8 ’ , ’ ddmmyyyy ’ ) ,
’Mr ’ ,
NULL,
’ 168031234567890 ’ ,
NULL
);

INSERT INTO MODULE


( codMod , nomMod)
VALUES
(
(SELECT n v l (MAX( codMod ) , 0 ) + 1 FROM MODULE) ,
’ Maths ’
);

INSERT INTO INSCRIPTION


( codMod , numEtud )
VALUES
(
(SELECT numEtud FROM ETUDIANT WHERE nom = ’ F o u r i e r ’ ) ,
(SELECT codMod FROM MODULE WHERE nomMod = ’ Maths ’ )
);

INSERT INTO EXAMEN VALUES

132
(
(SELECT codMod FROM MODULE WHERE nomMod = ’ Maths ’ ) ,
1,
t o d a t e ( ’ 0 2 0 1 2 0 0 8 ’ , ’ ddmmyyyy ’ )
);

INSERT INTO RESULTAT VALUES


(
(SELECT codMod FROM MODULE WHERE nomMod = ’ Maths ’ ) ,
1,
(SELECT numEtud FROM ETUDIANT WHERE nom = ’ F o u r i e r ’ ) ,
19 );

UPDATE RESULTAT SET


n o t e = 20
wHERE
numEtud = (SELECT numEtud FROM ETUDIANT WHERE nom = ’ F o u r i e r ’ )
AND codMod = (SELECT codMod FROM MODULE WHERE nomMod = ’ Maths ’ )
AND codExam = 1 ;

INSERT INTO MODULE VALUES


( 2 , ’ Algo ’ , 3 0 , 2 2 ) ;

INSERT INTO PREREQUIS VALUES


(1 , 2 , 10);

INSERT INTO PREREQUIS VALUES


(2 , 1 , 10);

UPDATE PREREQUIS SET noteMin = 2 ;

INSERT INTO EXAMEN VALUES ( 2 , 1 , s y s d a t e ) ;

133

S-ar putea să vă placă și