Vous êtes sur la page 1sur 133

Cours Oracle

Alexandre Meslé

13 octobre 2009
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 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.1.4 SQL+ et iSQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
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 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
1.3 Introduction aux requêtes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
1.3.1 Compléments sur SELECT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
1.3.2 Instruction WHERE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
1.3.3 Conditions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
1.3.4 Suppression . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
1.3.5 Mise à jour . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
1.4 Jointures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
1.4.1 Principe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
1.4.2 Produit cartésien . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
1.4.3 Jointure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
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 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
1.7.3 Sous requêtes non correlées renvoyant une table . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
1.7.4 Sous requêtes correlées . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
1.8 Compléments sur les types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
1.8.1 Types numériques . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
1.8.2 Types chaine de caractères . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
1.8.3 Types date . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
1.8.4 La fonction inclassable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
1.8.5 Contraintes CHECK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
1.9 Introduction au PL/SQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
1.9.1 PL/SQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
1.9.2 Blocs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
1.9.3 Affichage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
1.9.4 Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31

1
1.9.5 Traitements conditionnels . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
1.9.6 Traitements répétitifs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
1.10 Tableaux et structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
1.10.1 Tableaux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
1.10.2 Structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
1.11 Utilisation du PL/SQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
1.11.1 Affectation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
1.11.2 Tables et structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
1.11.3 Transactions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
1.12 Exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
1.12.1 Rattraper une exception . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
1.12.2 Exceptions prédéfinies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
1.12.3 Codes d’erreur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
1.12.4 Déclarer et lancer ses propres exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
1.13 Sous-programmes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
1.13.1 Procédures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
1.13.2 Fonctions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
1.14 Curseurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
1.14.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
1.14.2 Les curseurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
1.15 Curseurs parametrés . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
1.15.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
1.15.2 Définition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
1.15.3 Déclaration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
1.15.4 Ouverture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
1.15.5 Lecture d’une ligne, fermeture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
1.15.6 Boucle pour . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
1.15.7 Exemple récapitulatif . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
1.16 Triggers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
1.16.1 Principe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
1.16.2 Classification . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
1.16.3 Création . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
1.16.4 Accès aux lignes en cours de modification . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
1.16.5 Contourner le problème des tables en mutation . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
1.17 Packages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
1.17.1 Principe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
1.17.2 Spécification . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
1.17.3 Corps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53

2 Exercices 55
2.1 Contraintes déclaratives . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
2.2 Introduction aux requêtes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
2.3 Jointures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
2.4 Agrégation de données . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
2.5 Vues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
2.6 Requêtes imbriquées . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
2.7 Compléments sur les types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
2.8 Révisions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
2.9 Introduction au PL/SQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
2.10 Tableaux et Structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
2.11 Utilisation PL/SQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
2.12 Exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
2.13 Sous-programmes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
2.14 Curseurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
2.15 Curseurs parametrés . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
2.16 Triggers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
2.17 Packages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
2.18 Révisions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75

2
3 Corrigés 76
3.1 Contraintes déclaratives . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
3.2 Introduction aux requêtes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
3.3 Jointures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
3.4 Agrégation de données . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
3.5 Vues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
3.6 Requêtes imbriquées . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
3.7 Compléments sur les types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
3.8 Révisions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
3.9 Examen Type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
3.10 Introduction au PL/SQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
3.11 Tableaux et Structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
3.12 Application du PL/SQL et Exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
3.13 Sous-programmes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
3.14 Curseurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
3.15 Curseurs paramétrés . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106
3.16 Triggers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
3.17 Packages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116
3.18 Révisions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117

A Scripts de création de bases 121


A.1 Livraisons Sans contraintes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121
A.2 Modules et prerequis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
A.3 Géométrie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123
A.4 Livraisons . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
A.5 Arbre généalogique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125
A.6 Comptes bancaires . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126
A.7 Comptes bancaires avec exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128
A.8 Secrétariat pédagogique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130
A.9 Mariages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132

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.
– 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 :

4
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 sui-
vantes :
– 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
#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 :

5
– 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 ’ )

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 :

6
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.

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 >

8
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 Introduction aux requêtes
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

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)

10
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 ’ )

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 !

11
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 Jointures
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
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
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 :

13
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.

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

14
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
−−−−−−−−−− −−−−−−−−−−
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 ;

15
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 moche
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 belle
SQL> SELECT count ( ∗ ) FROM PRODUIT;

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

1 ligne selectionnee .
La réponse est le résultat de la requête.

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

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

17
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 .
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 :

18
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 comptabilisé
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 ).

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

19
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 confon-
dues),
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 fournisseurs 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
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− −−−−−−−−−−−−−−−
Cor n i c h o n s 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
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− −−−−−−−−−−−−−−−
Cor n i c h o n s 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 ).

21
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
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− −−−−−−−−−−−−−−−
Cor n i c h o n s 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 fournis-
seurs.
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
Cor n i c h o n s 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 :
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

23
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
f1
La requête SELECT MAX(NB PROD) FROM NB PROD PAR FOU est évaluée avant, et son résultat lui est substitué 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 .

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 :

24
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
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

25
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 proposant 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
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
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

26
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
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 ?

27
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
−−−−−−−−−−
10 ,2
10
,01
21 ,01

28
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 :
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

29
−−−−−−−−−− −−−−−−−−−− −−−−−−−−
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 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,
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).

30
1.9 Introduction au 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 obliga-
toirement 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 OUTPUT.PUT() et DBMS OUTPUT.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 IF ;
voire
IF /∗ c o n d i t i o n 1 ∗/ THEN
/∗ i n s t r u c t i o n s 1 ∗/
ELSIF /∗ c o n d i t i o n 2 ∗/
/∗ i n s t r u c t i o n s 2 ∗/

31
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 LOOP;
L’instruction EXIT WHEN permet de quitter une boucle.
LOOP
/∗ i n s t r u c t i o n s ∗/
EXIT WHEN /∗ c o n d i t i o n ∗/ ;
END LOOP;
La boucle FOR existe aussi en PL/SQL :
FOR /∗ v a r i a b l e ∗/ IN /∗ i n f ∗/ . . /∗ sup ∗/ LOOP
/∗ i n s t r u c t i o n s ∗/
END LOOP;
Ainsi que la boucle WHILE :
WHILE /∗ c o n d i t i o n ∗/ LOOP
/∗ i n s t r u c t i o n s ∗/
END LOOP;
Est-il possible, en bidouillant, d’implémenter une boucle DO ... WHILE ?

32
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
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;
/

33
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.
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 ),
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

34
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,
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.

35
1.11 Utilisation 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 , . . . , champ n INTO v 1 , . . . , v n
FROM . . .
affecte aux variables v 1, ..., v n les valeurs retournées par la requête. Par exemple
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,
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.
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
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;
/

36
1.11.3 Transactions
Un des mécanismes les plus puissants des SGBD récents réside dans le système des transactions. Une 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 assassiner.

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é.

37
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 identificateur, par
exemple GLUBARF. Lorsque dans les instructions, l’erreur GLUBARF se produit, le code du BEGIN s’interrompt et le
code de la section EXCEPTION est lancé. 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;
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;

38
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 :
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
/∗ 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,
DECLARE
GLUBARF EXCEPTION;

39
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;
/

40
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 ( n NUMBER) IS
BEGIN
IF n >= 0 THEN
DBMS OUTPUT. PUT LINE( n ) ;
compteARebours ( n − 1 ) ;
END IF ;
END;

Invocation
En PL/SQL, une procédure s’invoque tout simplement avec son nom. Mais sous SQL+, on doit utiliser 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,
CREATE OR REPLACE FUNCTION module ( a NUMBER, b NUMBER) RETURN NUMBER IS
BEGIN
IF a < b THEN
RETURN a ;
ELSE
RETURN module ( a − b , b ) ;

41
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.

42
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 en
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 ) ;
END LOOP;
/∗ . . . ∗/
END;

43
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 LOOP
DBMS OUTPUT. PUT LINE( l i g n e . ename ) ;
END LOOP;
END;
/

44
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 ) ;

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é.

45
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 s%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 . prenom | |
’ ’ | | p . nom | | ’ s o n t : ’ ) ;
FOR e IN e n f a n t s ( p . numpers ) LOOP
DBMS OUTPUT. PUT LINE( ’ ∗ ’ | | e . prenom
| | ’ ’ | | e . nom );
END LOOP;
END LOOP;
END;
/

46
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 | ]
DECLARE
/∗ d e c l a r a t i o n s ∗/
BEGIN
/∗ i n s t r u c t i o n s ∗/
END;
Par exemple,
SQL> CREATE OR REPLACE TRIGGER 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 ;

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

SQL> DELETE FROM CLIENT ;

47
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 remarquez 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 elle n’était pas respectée, il a lancé
une erreur.

Combinaisons d’événements
Il est possible, en séparant les types d’événement par le mot-clé OR, de définir un trigger déclenché par plusieurs
événements. Les variables booléennes INSERTING, UPDATING et DELETING permettent d’identifier l’événement qui a
déclenché le trigger.
CREATE OR REPLACE TRIGGER a f f i c h e E v e n e m e n t
BEFORE INSERT OR UPDATE OR DELETE ON CLIENT
FOR EACH ROW
BEGIN
IF INSERTING THEN
DBMS OUTPUT. PUT LINE( ’ I n s e r t i o n dans CLIENT ’ ) ;
ELSIF UPDATING THEN
DBMS OUTPUT. PUT LINE( ’ Mise a j o u r dans CLIENT ’ ) ;
ELSE
DBMS OUTPUT. PUT LINE( ’ S u p p r e s s i o n dans CLIENT ’ ) ;
END IF ;
END;

1.16.4 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. Par exemple le trigger suivant empêche
de diminuer un salaire :
CREATE OR REPLACE TRIGGER p a s D e B a i s s e D e S a l a i r e
BEFORE UPDATE ON EMP
FOR EACH ROW
BEGIN
IF ( : o l d . s a l > : new . s a l ) THEN
RAISE APPLICATION ERROR( −20567 ,
’ Pas de b a i s s e de s a l a i r e ! ’ ) ;
END IF ;
END;

Tables en mutation
Il est impossible, dans un trigger de type FOR EACH ROW de faire un SELECT sur la table en cours de modification.
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

48
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;
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>

49
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>
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’

1.16.5 Contourner le problème des tables en mutation


Il existe plusieurs façons de contourner ce problème :
– Utiliser un STATEMENT trigger. Comme on ne sait pas quelles lignes ont été modifiées, on est obligé de toutes
les traiter. Cette approche présente donc un inconvénient majeur : elle nous amène à effectuer de nombreux
traitements inutiles.
– En ayant des données redondantes. Il suffit que les données servant à la vérification se trouvent dans une autre
table que celle en mutation. Cette méthode a pour inconvénient la mémoire occupée et la quantité de code à écrire
pour maintenir la cohérence des données. Dans la plupart des cas, cette solution est malgré tout la meilleure.

Colonnes supplémentaires
Par exemple, si l’on souhaite empêcher un client d’avoir plus de 10 comptes en banque, une solution est de placer
dans la table client une colonne contenant le nombre de comptes.
ALTER TABLE CLIENT ADD nbComptes number ;
UPDATE CLIENT SET nbComptes = 0 ;
Une fois cette table crée, il convient de s’assurer que les données de la colonne nbComptes contient toujours les
bonnes valeurs. On le fait avec plusieurs sous-programmes :
CREATE OR REPLACE TRIGGER metAJourNbComptes
AFTER INSERT OR UPDATE OR DELETE ON COMPTECLIENT
BEGIN
UPDATE CLIENT SET nbComptes =
(
SELECT COUNT( ∗ )
FROM COMPTECLIENT CC
WHERE CC. numCli = numCli
);
END;
/

CREATE OR REPLACE TRIGGER v e r i f i e N b C o m p t e s


BEFORE INSERT ON COMPTECLIENT
FOR EACH ROW
DECLARE
nbComptes NUMBER;

50
BEGIN
SELECT nbComptes INTO nbComptes
FROM CLIENT
WHERE numCli = : new . numcli ;
IF ( nbComptes >= 1 0 ) THEN
RAISE APPLICATION ERROR( −20556 ,
’ Ce c l i e n t a d e j a t r o p de comptes ’ ) ;
END IF ;
END;
/
On peut affiner en remplaçant metAJourNbComptes par plusieurs sous-programmes :
CREATE OR REPLACE TRIGGER i n i t i a l i s e N b C o m p t e s
BEFORE INSERT ON CLIENT
FOR EACH ROW
BEGIN
: new . nbComptes := 0 ;
END;
/

CREATE OR REPLACE TRIGGER metAJourNbComptes


AFTER INSERT OR UPDATE OR DELETE ON COMPTECLIENT
FOR EACH ROW
BEGIN
IF DELETING OR UPDATING THEN
UPDATE CLIENT SET nbComptes = nbComptes − 1
WHERE numcli = : o l d . numcli ;
END IF ;
IF INSERTING OR UPDATING THEN
UPDATE CLIENT SET nbComptes = nbComptes + 1
WHERE numcli = : new . numcli ;
END IF ;
END;
/

Tables supplémentaires
Si l’on souhaite par exemple empêcher les circuits dans la table PERSONNE, il est nécessaire de faire un parcours
de graphe. Ce qui nécessite des SELECT dans la table en cours de mutation. La seule solution est dans ce cas d’avoir
une table miroir qui contient les colonnes clés primaire et étrangères de cette table, et de s’en servir pour détecter les
circuits.
CREATE TABLE MIRRORPERSONNE
(
numpers NUMBER PRIMARY KEY,
p e r e NUMBER,
mere NUMBER
);
Nous allons ensuite procéder de même, en répercutant chaque opération de PERSONNE sur MIRRORPERSONNE.
CREATE OR REPLACE TRIGGER miseAJourMirrorPersonne
BEFORE UPDATE OR INSERT OR DELETE ON PERSONNE
FOR EACH ROW
BEGIN
IF DELETING OR UPDATING THEN
DELETE FROM MIRRORPERSONNE
WHERE numpers = : o l d . numpers ;
END IF ;
IF INSERTING OR UPDATING THEN
INSERT INTO MIRRORPERSONNE VALUES

51
( : new . numpers , : new . pere , : new . mere ) ;
END IF ;
END;
/
Une fois cela fait, il suffit de rechercher si une personne insérée est une descendante d’elle même dans MIRRORPERSONNE.
CREATE OR REPLACE FUNCTION t r o u v e C i r c u i t ( c u r r e n t NUMBER, toFind NUMBER)
RETURN BOOLEAN IS
numPere NUMBER;
numMere NUMBER;
BEGIN
IF ( c u r r e n t IS NULL) THEN
RETURN FALSE;
END IF ;
SELECT pere , mere INTO numPere , numMere
FROM MIRRORPERSONNE
WHERE numPers = c u r r e n t ;
RETURN ( numPere = toFind OR numMere = toFind OR
t r o u v e C i r c u i t ( numPere , toFind ) OR
t r o u v e C i r c u i t ( numMere , toFind ) ) ;
END;
/

CREATE OR REPLACE TRIGGER v e r i f i e C i r c u i t


AFTER UPDATE OR INSERT ON PERSONNE
FOR EACH ROW
BEGIN
IF ( t r o u v e C i r c u i t ( : new . numPers , : new . numPers ) ) THEN
RAISE APPLICATION ERROR( −20557 ,
’ C i r c u i t dans l ’ ’ a r b r e g é n é a l o g i q u e . ’ ) ;
END IF ;
END;
/

52
1.17 Packages
1.17.1 Principe
Un package est un ensemble de sous-programmes et de variables formé par
– Une spécification : déclaration de variables et de sous-programmes
– Un corps : implémentation des sous-programmes
Tout ce qui se trouve dans la spécification doit se trouver dans le corps, mais la réciproque est fausse. Un package
satisfait les points suivants :
– encapsulation : certains traitements sont masqués, seule la spécification du package est visible. Cela a pour
avantage de simplifier la tâche de celui qui va utiliser le package.
– modularité : il est possible de développer séparément les diverses parties de l’application. le développement
devient ainsi un assemblage de package.
Ces deux aspects fournissent une souplesse certaine au niveau du développement : il est possible de modifier le
corps d’un package sans changer sa spécification, donc sans modifier le fonctionnement de l’application.

1.17.2 Spécification
La syntaxe permettant de créer l’entête est la suivante :
CREATE OR REPLACE PACKAGE nompackage IS
/∗
declarations
∗/
END nomPackage ;
/
Par exemple,
CREATE OR REPLACE PACKAGE compteur IS
procedure r e s e t ;
f u n c t i o n nextValue r e t u r n number ;
END compteur ;
/

1.17.3 Corps
La syntaxe permettant de créer le corps est la suivante :
CREATE OR REPLACE PACKAGE BODY nompackage IS
/∗
implementation
∗/
END nomPackage ;
/
Par exemple,
CREATE OR REPLACE PACKAGE BODY compteur IS
c p t NUMBER := 0 ;

PROCEDURE r e s e t IS
BEGIN
c p t := 0 ;
END;

FUNCTION nextValue RETURN NUMBER IS


BEGIN
c p t := c p t + 1 ;
RETURN c p t − 1 ;
END;
END compteur ;
/

53
On peut utiliser un package depuis n’importe quel script PL/SQL :
DECLARE
nb NUMBER;
BEGIN
FOR nb IN 4 . . 2 0 LOOP
DBMS OUTPUT. PUT LINE(COMPTEUR. nextValue ( ) ) ;
END LOOP;
COMPTEUR.RESET ( ) ;
FOR nb IN REVERSE 0 . . 1 0 LOOP
DBMS OUTPUT. PUT LINE(COMPTEUR. nextValue ( ) ) ;
END LOOP;
END;
/

54
Chapitre 2

Exercices

2.1 Contraintes déclaratives


Nous nous proposons de modifier le script de création de table de l’annexe A.1.

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.

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 Introduction aux requêtes
Nous souhaitons gérer un secrétatiat pédagogique avec la base de A.2.
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).

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 utilisera pour les questions suivantes les tables de A.3.

56
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).

57
2.3 Jointures
Reprenons pour ce tp la base de donées de A.4.

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.

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 de A.5. Dans les questions où il vous est demandé de
formuler des requêtes retournant plusieurs personnes, 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

58
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.

59
2.4 Agrégation de données
Nous utiliserons les données de A.4. Il est demandé dans chaque exercice de formuler une requête.

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.

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.

60
2.5 Vues
Nous utiliserons les données de A.4. N’hésitez pas, pour tester vos requêtes et à 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é.

61
2.6 Requêtes imbriquées
Nous utiliserons les données de A.4. Presque tous les stratagèmes sont autorisés, vous pouvez utiliser des fonctions
d’agrégation, des vues, et des requêtes imbriquées. 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 fournisseur 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. Normalement, 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).

62
2.7 Compléments sur les types
Vous modifierez pour faire ces exercices le script de création de tables de A.4.

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.

63
2.8 Révisions
Nous utiliserons les données de A.4.

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.

64
2.9 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.

65
2.10 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;
first := 1;
last := 19;
t(first).previous := -1;
t(last).next := -1;

66
-- 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.

67
2.11 Utilisation PL/SQL
Nous travaillerons sur les données A.6 et A.5.
Vous n’oublierez pas de placer des commit en des lieux bien choisis.

Exercice 1
Vous remarquerez que les valeurs des numpers de la table PERSONNE forment une sé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.

68
2.12 Exceptions
Nous utiliserons les données de A.7 et A.5
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.

69
2.13 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 les données de A.5.

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.

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.

70
2.14 Curseurs
Exercice 1
Refaites les exercices de 2.11 en utilisant les curseurs.

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

71
2.15 Curseurs parametrés
L’intérêt de ces exercices étant de vous familiariser avec les curseurs paramétrés, vous ferez en sorte de ne pas
contourner leur usage. Nous utiliserons les données de A.6

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.

72
2.16 Triggers
Implémentez les contraintes suivantes dans les données de les données de A.8. Vous ferez des sous-programmes
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.

73
2.17 Packages
Exercice 1
Lancez deux sessions simultanément sur le même serveur et invoquez les sous-programmes du package compteur
depuis chacune des sessions. Que remarquez-vous ?

Exercice 2
Implémenter le corps du package suivant (utilisez les données de A.5).
CREATE OR REPLACE PACKAGE g e s t i o n a r b r e I S
c i r c u i t exception ;

cursor feuilles r e t u r n p e r s o n n e%rowtype ;

p r o c e d u r e a j o u t e P e r s o n n e (nom p e r s o n n e . nom%type ,
prenom p e r s o n n e . prenom%type , p e r e p e r s o n n e . p e r e%type ,
mere p e r s o n n e . mere%t y p e ) ;

p r o c e d u r e m o d i f i e P a r e n t s ( p e r s p e r s o n n e . numpers%type ,
numPere p e r s o n n e . p e r e%type , numMere p e r s o n n e . mere%t y p e ) ;

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

74
2.18 Révisions
Implémentez les contraintes suivantes dans les données de A.9.
1. Les parents d’une même personne sont des personnes différentes.
2. L’arbre généalogique ne contient pas de circuit.
3. Les dates de divorce sont ultérieures aux dates de mariage.
4. Une même personne ne peut pas être mariée à plusieurs personnes simultanément.
5. Personne ne peut être père d’une personne et mère d’une autre.
6. Un mari ne peut pas être mère et une femme ne peut pas être père.
7. Deux personnes ayant du sang en commun ne peuvent se marier.

75
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);

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 , 1 0 ) ;


INSERT INTO DETAILLIVRAISON values ( 1 , 1 , 1 , 2 5 ) ;

76
INSERT INTO DETAILLIVRAISON values ( 1 , 1 , 2 , 2 0 ) ;
INSERT INTO DETAILLIVRAISON values ( 1 , 2 , 1 , 1 5 ) ;
INSERT INTO DETAILLIVRAISON values ( 1 , 2 , 2 , 1 7 ) ;

−− 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 termout 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 termout 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 )
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 ) ;

77
3.2 Introduction aux requêtes
−− 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
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 ∗

78
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 ) ;

79
3.3 Jointures
−− 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, livraison l
WHERE nomfou = ’ f 3 ’
AND f . numfou = l . numfou
AND l . numfou = d . numfou
AND l . numli = d . numli
AND d . numprod = p . numprod
AND d a t e l i < s y s d a t e ;

−− 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
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 ;

80
−− 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 )
)
);

81
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 ) ;

82
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 ;

83
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
)
)
)
FROM FOURNISSEUR F ;

−− E x e r c i c e 7

84
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
(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 ;

85
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 ) ) ;

86
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
)
);

87
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 ) ) ;
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 )

88
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
);

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

89
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 ’
)
) = 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
(

90
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( ∗ )
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 ’
)
);

91
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;
/

92
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
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;
/

93
−− 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 | | ’ ) ’ ) ;
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

94
−− 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;
/

95
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

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

96
FROM TYPEOPERATION
WHERE nomtypeoper = ’ dé p ô t e s p è c e s ’ ;
SELECT n um 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
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

97
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 um 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 ;
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 ,

98
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;
/

99
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

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

100
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 ;
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

101
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

102
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;
/

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

103
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
)
)
);
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

104
)
)
);
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;
/

105
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 . montantOper )
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 ( ) ;

106
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
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

107
(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;
/

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

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;
/

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

108
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

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( ∗ )
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;
/

109
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−− 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
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 ( so n . 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;
/

110
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

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;
/

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

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

111
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


−− la 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
−− le 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
−− les 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 ,

112
(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 ;
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 −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

113
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

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
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
);

114
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 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 ) ;

115
3.17 Packages
CREATE OR REPLACE PACKAGE BODY g e s t i o n a r b r e I S

cursor f e u i l l e s r e t u r n p e r s o n n e%rowtype I S
SELECT ∗ FROM PERSONNE;

PROCEDURE a j o u t e P e r s o n n e (nom p e r s o n n e . nom%type ,


prenom p e r s o n n e . prenom%type , p e r e p e r s o n n e . p e r e%type ,
mere p e r s o n n e . mere%t y p e ) I S
BEGIN
INSERT INTO PERSONNE VALUES (
(SELECT n v l (MAX( numpers ) , 0 ) + 1 FROM PERSONNE) ,
nom , prenom , p e r e , mere ) ;
END;

FUNCTION descendDe ( numpers p e r s o n n e . numpers%type ,


d e s c e n d a n t p e r s o n n e . numpers%t y p e ) RETURN BOOLEAN I S
BEGIN
IF ( d e s c e n d a n t I S NULL) THEN
RETURN FALSE;
ELSIF ( d e s c e n d a n t = numpers ) THEN
RETURN TRUE;
ELSE
DECLARE
p e r s PERSONNE%rowtype ;
BEGIN
SELECT ∗ INTO p e r s
FROM PERSONNE
WHERE numpers = d e s c e n d a n t ;
RETURN descendDe ( numpers , p e r s . p e r e )
OR descendDe ( numpers , p e r s . mere ) ;
END;
END IF ;
END;

p r o c e d u r e m o d i f i e P a r e n t s ( p e r s p e r s o n n e . numpers%type ,
numPere p e r s o n n e . p e r e%type , numMere p e r s o n n e . mere%t y p e ) I S
BEGIN
IF ( descendDe ( p e r s , numPere ) OR descendDe ( p e r s , numMere ) ) THEN
RAISE CIRCUIT ;
END IF ;
UPDATE PERSONNE SET p e r e = numPere , mere = numMere
WHERE numPers = p e r s ;
END;
END;
/

CALL g e s t i o n A r b r e . m o d i f i e P a r e n t s ( 2 0 , 1 4 , 1 5 ) ;

116
3.18 Révisions
−− P r e p a r a t i f s . . .

DROP TABLE MIRRORPERSONNE;

CREATE TABLE MIRRORPERSONNE


(
numpers NUMBER PRIMARY KEY,
p e r e NUMBER,
mere NUMBER
);

CREATE OR REPLACE TRIGGER m i s e A J o u r M i r r o r P e r s o n n e


BEFORE UPDATE OR INSERT OR DELETE ON PERSONNE
FOR EACH ROW
BEGIN
IF DELETING OR UPDATING THEN
DELETE FROM MIRRORPERSONNE
WHERE numpers = : o l d . numpers ;
END IF ;
IF INSERTING OR UPDATING THEN
INSERT INTO MIRRORPERSONNE VALUES
( : new . numpers , : new . p e r e , : new . mere ) ;
END IF ;
END;
/

DROP TABLE MIRRORMARIAGE;

CREATE TABLE MIRRORMARIAGE


(
nummari NUMBER,
numfemme NUMBER,
d a t e m a r i a g e DATE,
d a t e d i v o r c e DATE
);

CREATE OR REPLACE TRIGGER m i s e A J o u r M i r r o r M a r i a g e


BEFORE UPDATE OR INSERT OR DELETE ON MARIAGE
FOR EACH ROW
BEGIN
IF DELETING OR UPDATING THEN
DELETE FROM MIRRORMARIAGE
WHERE nummari = : o l d . nummari
AND numfemme = : o l d . numfemme
AND d a t e m a r i a g e = : o l d . d a t e m a r i a g e ;
END IF ;
IF INSERTING OR UPDATING THEN
INSERT INTO MIRRORMARIAGE VALUES
( : new . nummari , : new . numfemme , : new . d a t e m a r i a g e , : new . d a t e d i v o r c e ) ;
END IF ;
END;
/

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

ALTER TABLE PERSONNE ADD CONSTRAINT c k p a r e n t s d i f f e r e n t s CHECK( p e r e <> mere ) ;

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

CREATE OR REPLACE PACKAGE c o n t r a i n t e C i r c u i t I S


CIRCUIT EXCEPTION;
PROCEDURE v e r i f i e C i r c u i t ( p e r s p e r s o n n e . numpers%t y p e ) ;
FUNCTION descendDe ( numpers p e r s o n n e . numpers%type ,
d e s c e n d a n t p e r s o n n e . numpers%t y p e ) RETURN BOOLEAN;
END;
/

CREATE OR REPLACE TRIGGER v e r i f i e C o n t r a i n t e C i r c u i t


AFTER UPDATE OR INSERT ON PERSONNE
FOR EACH ROW
BEGIN
c o n t r a i n t e C i r c u i t . v e r i f i e C i r c u i t ( : new . numPers ) ;
END;
/

CREATE OR REPLACE PACKAGE BODY c o n t r a i n t e C i r c u i t I S

FUNCTION descendDe ( numpers p e r s o n n e . numpers%type ,


d e s c e n d a n t p e r s o n n e . numpers%t y p e ) RETURN BOOLEAN I S
BEGIN
IF ( d e s c e n d a n t I S NULL) THEN
RETURN FALSE;
ELSIF ( d e s c e n d a n t = numpers ) THEN
RETURN TRUE;
ELSE
DECLARE

117
p e r s MIRRORPERSONNE%rowtype ;
BEGIN
SELECT ∗ INTO p e r s
FROM MIRRORPERSONNE
WHERE numpers = d e s c e n d a n t ;
RETURN descendDe ( numpers , p e r s . p e r e )
OR descendDe ( numpers , p e r s . mere ) ;
END;
END IF ;
END;

PROCEDURE v e r i f i e C i r c u i t ( p e r s p e r s o n n e . numpers%t y p e ) I S
l i g n e m i r r o r p e r s o n n e%rowtype ;
BEGIN
SELECT ∗ INTO LIGNE
FROM m i r r o r p e r s o n n e
WHERE numpers = p e r s ;
IF ( descendDe ( p e r s , l i g n e . p e r e ) OR descendDe ( p e r s , l i g n e . mere ) ) THEN
RAISE CIRCUIT ;
END IF ;
END;

END;
/

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

ALTER TABLE MARIAGE ADD CONSTRAINT c k d a t e s m a r i a g e CHECK( d a t e D i v o r c e I S NULL OR d a t e M a r i a g e <= dateDivorce ) ;

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

CREATE OR REPLACE PACKAGE c o n t r a i n t e s M a r i a g e s I S


m a r i a g e s S u p e r p o s e s EXCEPTION;
PROCEDURE v e r i f i e M a r i a g e s S u p e r p o s e s ( nouveauMariage m a r i a g e%rowtype ) ;
END c o n t r a i n t e s M a r i a g e s ;
/

CREATE OR REPLACE TRIGGER v e r i f i e C o n t r a i n t e s M a r i a g e s


BEFORE UPDATE OR INSERT ON MARIAGE
FOR EACH ROW
DECLARE
nouveauMariage MARIAGE%rowtype ;
BEGIN

nouveauMariage . numMari := : new . numMari ;


nouveauMariage . numFemme := : new . numFemme ;
nouveauMariage . d a t e M a r i a g e := : new . d a t e M a r i a g e ;
nouveauMariage . d a t e D i v o r c e := : new . d a t e D i v o r c e ;
c o n t r a i n t e s M a r i a g e s . v e r i f i e M a r i a g e s S u p e r p o s e s ( nouveauMariage ) ;
END;
/

CREATE OR REPLACE PACKAGE BODY c o n t r a i n t e s M a r i a g e s I S

FUNCTION s e S u p e r p o s e n t (m1 m i r r o r M a r i a g e%rowtype , m2 m i r r o r M a r i a g e%rowtype ) RETURN BOOLEAN I S


BEGIN
IF (m1 . nummari <> m2 . nummari OR m1 . numfemme <> m2 . numfemme ) THEN
RETURN FALSE;
END IF ;
RETURN NOT(
(m2 . d a t e d i v o r c e I S NOT NULL AND m1 . d a t e M a r i a g e <= m2 . d a t e D i v o r c e )
OR (m1 . d a t e d i v o r c e I S NOT NULL AND m2 . d a t e M a r i a g e <= m1 . d a t e D i v o r c e )
);
END;

PROCEDURE v e r i f i e M a r i a g e s S u p e r p o s e s ( nouveauMariage m a r i a g e%rowtype ) I S


CURSOR a u t r e s M a r i a g e s I S
SELECT ∗ FROM MIRRORMARIAGE
WHERE numMari = nouveauMariage . numMari
OR numFemme = nouveauMariage . numFemme ;
a u t r e M a r i a g e a u t r e s M a r i a g e s%ROWTYPE;
BEGIN
FOR a u t r e M a r i a g e IN a u t r e s M a r i a g e s LOOP
IF ( s e S u p e r p o s e n t ( nouveauMariage , a u t r e M a r i a g e ) ) THEN
RAISE m a r i a g e s S u p e r p o s e s ;
END IF ;
END LOOP;
END;

END c o n t r a i n t e s M a r i a g e s ;
/

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

CREATE OR REPLACE p a c k a g e c o n t r a i n t e s T r a n s I S
t r a n s EXCEPTION;

PROCEDURE v e r i f i e P e r e M e r e ( n o u v e l l e P e r s o n n e MIRRORPERSONNE%rowtype ) ;
PROCEDURE v e r i f i e M a r i F e m m e ( nouveauMariage MARIAGE%rowtype ) ;

118
end c o n t r a i n t e s T r a n s ;
/

CREATE OR REPLACE TRIGGER pereMere


AFTER UPDATE OR INSERT ON PERSONNE
FOR EACH ROW
DECLARE
n o u v e l l e P e r s o n n e MIRRORPERSONNE%rowtype ;
BEGIN
n o u v e l l e P e r s o n n e . numpers := : new . numpers ;
n o u v e l l e P e r s o n n e . p e r e := : new . p e r e ;
n o u v e l l e P e r s o n n e . mere := : new . mere ;
contraintesTrans . verifiePereMere ( nouvellePersonne ) ;
END;
/

CREATE OR REPLACE TRIGGER mariFemme


AFTER UPDATE OR INSERT ON MARIAGE
FOR EACH ROW
DECLARE
nouveauMariage MARIAGE%rowtype ;
BEGIN
nouveauMariage . numMari := : new . numMari ;
nouveauMariage . numFemme := : new . numFemme ;
nouveauMariage . d a t e M a r i a g e := : new . d a t e M a r i a g e ;
nouveauMariage . d a t e D i v o r c e := : new . d a t e D i v o r c e ;
c o n t r a i n t e s T r a n s . v e r i f i e M a r i F e m m e ( nouveauMariage ) ;
END;
/

CREATE OR REPLACE p a c k a g e BODY c o n t r a i n t e s T r a n s I S

PROCEDURE v e r i f i e P e r e M e r e ( n o u v e l l e P e r s o n n e MIRRORPERSONNE%rowtype ) I S
nb INT;
BEGIN
SELECT COUNT( ∗ ) INTO nb
FROM MIRRORPERSONNE
WHERE p e r e = n o u v e l l e P e r s o n n e . mere
OR mere = n o u v e l l e P e r s o n n e . p e r e ;
IF ( nb <> 0 ) THEN
RAISE TRANS;
END IF ;
SELECT COUNT( ∗ ) INTO nb
FROM MIRRORMARIAGE
WHERE numMari = n o u v e l l e P e r s o n n e . mere
OR numFemme = n o u v e l l e P e r s o n n e . p e r e ;
IF ( nb <> 0 ) THEN
RAISE TRANS;
END IF ;
END;

PROCEDURE v e r i f i e M a r i F e m m e ( nouveauMariage MARIAGE%rowtype ) I S


nb INT;
BEGIN
SELECT COUNT( ∗ ) INTO nb
FROM MIRRORMARIAGE
WHERE numMari = nouveauMariage . numFemme
OR numFemme = nouveauMariage . numMari ;
IF ( nb <> 0 ) THEN
RAISE TRANS;
END IF ;
SELECT COUNT( ∗ ) INTO nb
FROM MIRRORPERSONNE
WHERE p e r e = nouveauMariage . numFemme
OR mere = nouveauMariage . numMari ;
IF ( nb <> 0 ) THEN
RAISE TRANS;
END IF ;
END;

END c o n t r a i n t e s T r a n s ;
/

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

CREATE OR REPLACE PACKAGE c o n t r a i n t e M a r i a g e C o n s a n g u i n I S


MariageConsanguin EXCEPTION;

PROCEDURE v e r i f i e M a r i a g e C o n s a n g u i n ( nouveauMariage MARIAGE%rowtype ) ;


END c o n t r a i n t e M a r i a g e C o n s a n g u i n ;
/

CREATE OR REPLACE TRIGGER m a r i a g e C o n s a n g u i n


AFTER UPDATE OR INSERT ON MARIAGE
FOR EACH ROW
DECLARE
nouveauMariage MARIAGE%rowtype ;
BEGIN

119
nouveauMariage . numMari := : new . numMari ;
nouveauMariage . numFemme := : new . numFemme ;
nouveauMariage . d a t e M a r i a g e := : new . d a t e M a r i a g e ;
nouveauMariage . d a t e D i v o r c e := : new . d a t e D i v o r c e ;
c o n t r a i n t e M a r i a g e C o n s a n g u i n . v e r i f i e M a r i a g e C o n s a n g u i n ( nouveauMariage ) ;
END;
/

CREATE OR REPLACE PACKAGE BODY c o n t r a i n t e M a r i a g e C o n s a n g u i n I S

FUNCTION p e r e ( p PERSONNE. numpers%t y p e ) RETURN PERSONNE. numpers%t y p e I S


numPere PERSONNE. numpers%t y p e ;
BEGIN
SELECT p e r e INTO numPere
FROM MIRRORPERSONNE
WHERE numpers = p ;
RETURN numPere ;
EXCEPTION
WHEN NO DATA FOUND THEN
RETURN NULL;
END;

FUNCTION mere ( p PERSONNE. numpers%t y p e ) RETURN PERSONNE. numpers%t y p e I S


numMere PERSONNE. numpers%t y p e ;
BEGIN
SELECT mere INTO numMere
FROM MIRRORPERSONNE
WHERE numpers = p ;
RETURN numMere ;
EXCEPTION
WHEN NO DATA FOUND THEN
RETURN NULL;
END;

FUNCTION rechercheAncetreCommun ( a PERSONNE. numpers%type ,


b PERSONNE. numpers%t y p e ) RETURN BOOLEAN I S
BEGIN
IF ( a I S NULL) THEN
RETURN FALSE;
ELSE
RETURN ( c o n t r a i n t e C i r c u i t . descendDe ( a , b ) ) OR rechercheAncetreCommun ( p e r e ( a ) , b ) OR rechercheAncetr
END IF ;
END;

PROCEDURE v e r i f i e M a r i a g e C o n s a n g u i n ( nouveauMariage MARIAGE%rowtype ) I S


BEGIN
IF ( rechercheAncetreCommun ( nouveauMariage . numMari , nouveauMariage . numFemme ) ) THEN
RAISE MariageConsanguin ;
END IF ;
END;
END c o n t r a i n t e M a r i a g e C o n s a n g u i n ;
/

120
Annexe A

Scripts de création de bases

A.1 Livraisons Sans contraintes


Attention : Le numéro de livraison est une clé secondaire, c’est-à-dire un numéro unique étant donné un fournisseur.
CREATE TABLE PRODUIT
( numprod number ,
nomprod varchar2 ( 3 0 ) ) ;

CREATE TABLE FOURNISSEUR


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

CREATE TABLE PROPOSER


( numfou number ,
numprod number ,
p r i x number ) ;

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
);

CREATE TABLE DETAILLIVRAISON


( numfou number ,
numli number ,
numprod number ,
q t e number ) ;

121
A.2 Modules et prerequis
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 ( 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 avancà e
c ’ );

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);

122
A.3 Géométrie
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.
CREATE TABLE INTERVALLE
( b o r n e I n f NUMBER,
borneSup NUMBER,
PRIMARY KEY ( b o r n e I n f , borneSup ) ) ;

CREATE TABLE RECTANGLE


( xHautGauche NUMBER,
yHautGauche NUMBER,
x B a s D r o i t NUMBER,
y B a s D r o i t NUMBER,
PRIMARY KEY ( xHautGauche , yHautGauche , xBasDroit , y B a s D r o i t ) ) ;

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);
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 , 1 3 ) ;
INSERT INTO RECTANGLE VALUES (10 , 13 , 1 , 1 1 ) ;
INSERT INTO RECTANGLE VALUES (10 , 13 , 10 , 1 1 ) ;
INSERT INTO RECTANGLE VALUES (2 , 7 , 5 , 13);
INSERT INTO RECTANGLE VALUES (21 , 73 , 15 , 2 2 ) ;
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);

123
A.4 Livraisons
CREATE TABLE PRODUIT
( numprod number ,
nomprod varchar2 ( 3 0 ) ) ;

CREATE TABLE FOURNISSEUR


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

CREATE TABLE PROPOSER


( numfou number ,
numprod number ,
p r i x number NOT NULL) ;

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
);

CREATE TABLE DETAILLIVRAISON


( numfou number ,
numli number ,
numprod number ,
q t e number NOT NULL) ;

a l t e r table p r o d u i t add c o n s t r a i n t p k p r o d u i t
PRIMARY KEY ( numprod ) ;
a l t e r table f o u r n i s s e u r add c o n s t r a i n t p k f o u r n i s s e u r
PRIMARY KEY ( numfou ) ;
a l t e r table p r o p o s e r add c o n s t r a i n t p k p r o p o s e r
PRIMARY KEY ( numfou , numprod ) ;
a l t e r table l i v r a i s o n add c o n s t r a i n t p k l i v r a i s o n
PRIMARY KEY ( numfou , numli ) ;
a l t e r table 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 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 table 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 f o u r n i s s e u r
FOREIGN KEY ( numfou ) REFERENCES f o u r n i s s e u r ( numfou ) ;
a l t e r table 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 table 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 table 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 table 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 ) ;

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


INSERT INTO PRODUIT values (2 , ’Poupà e
c 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);

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);

124
A.5 Arbre généalogique
La table PERSONNE, 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.
CREATE TABLE PERSONNE
( numpers number PRIMARY KEY,
nom varchar2 ( 3 0 ) NOT NULL,
prenom varchar2 ( 3 0 ) ,
p e r e REFERENCES PERSONNE( numpers ) ,
mere REFERENCES PERSONNE( numpers )
);

INSERT INTO PERSONNE VALUES (1 , ’ de M o n t m i r a i l , d i t l e H a r d i ’ , ’ G o d e f r o y ’ , NULL, NULL) ;


INSERT INTO PERSONNE VALUES (16 , ’ET ’ , NULL, NULL, NULL) ;
INSERT INTO PERSONNE VALUES (2 , ’ Le Croquant ’ , ’ Jacqou ’ , 1 , 1 6 ) ;
INSERT INTO PERSONNE VALUES (3 , ’ La F r i p o u i l l e ’ , ’ J a c q o u i l l e ’ , 1 , 1 6 ) ;
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 c ’ , ’MÃ dor
c ’ , 3 ,4 ) ;
INSERT INTO PERSONNE VALUES (12 , ’ Kobalevska ïa ’ , ’ S o f i a ’ , NULL, NULL) ;
INSERT INTO PERSONNE VALUES (6 , ’ Rieu ’ , ’Andrà c ’ , NULL, NULL) ;
INSERT INTO PERSONNE VALUES (7 , ’ Bontoutou ’ , ’ Rex ’ , 6 , 4 ) ;
INSERT INTO PERSONNE VALUES (8 , ’ D i j k s t r a ’ , ’ Edvard ’ , 2 , 1 3 ) ;
INSERT INTO PERSONNE VALUES (9 , ’ L e i b n i z ’ , ’ G o t t f r i e 1 d Wilhem ’ , 8 , 1 2 ) ;
INSERT INTO PERSONNE VALUES (10 , ’ Bach ’ , ’ Johann S e b a s t i e n ’ , 5 , 1 2 ) ;
INSERT INTO PERSONNE VALUES (17 , ’ Mathieu ’ , ’ M i r e i l l e ’ , NULL, NULL) ;
INSERT INTO PERSONNE VALUES (11 , ’ Lemarchal ’ , ’ Gregory ’ , 1 0 , 1 7 ) ;
INSERT INTO PERSONNE VALUES (15 , ’ S o c r a t e ’ , NULL, 3 , 1 3 ) ;
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 ’ , 1 0 , 1 7 ) ;
INSERT INTO PERSONNE VALUES (14 , ’ S t o n e ’ , ’ Sharon ’ , 1 5 , 2 0 ) ;
INSERT INTO PERSONNE VALUES (18 , ’ Frege ’ , ’ Elodie ’ , 7 , 1 3 ) ;

125
A.6 Comptes bancaires
DROP TABLE OPERATION;
DROP TABLE TYPEOPERATION;
DROP TABLE COMPTECLIENT;
DROP TABLE TYPECCL;
DROP TABLE PERSONNEL;
DROP TABLE CLIENT ;

CREATE TABLE CLIENT


( n u m c l i number ,
n o m c l i varchar2 ( 3 0 ) ,
p r e n o m c l i varchar2 ( 3 0 ) ,
a d r e s s e varchar2 ( 6 0 ) ,
t e l varchar ( 1 0 )
);

CREATE TABLE PERSONNEL


( numpers number ,
nompers varchar2 ( 3 0 ) ,
prenompers varchar2 ( 3 0 ) ,
manager number ,
s a l a i r e number
);

CREATE TABLE TYPECCL


( n u mt y p ec c l number ,
n o m t y p e c c l varchar2 ( 3 0 )
);

CREATE TABLE COMPTECLIENT


( n u m c l i number ,
numccl number ,
n u m t y pe c c l number ,
d a t e c c l date d e f a u l t s y s d a t e not null ,
numpers number
);

CREATE TABLE TYPEOPERATION


( numtypeoper number ,
nomtypeoper varchar2 ( 3 0 )
);

CREATE TABLE OPERATION


( n u m c l i number ,
numccl number ,
numoper number ,
numtypeoper number ,
d a t e o p e r date d e f a u l t s y s d a t e not null ,
montantoper number not null ,
l i b e l o p e r varchar2 ( 3 0 )
);

ALTER TABLE CLIENT ADD


(
CONSTRAINT p k c l i e n t PRIMARY KEY ( n u m c l i ) ,
CONSTRAINT c k t e l e p h o n e CHECK(LENGTH( t e l )=10)
);

ALTER TABLE PERSONNEL ADD


(
CONSTRAINT p k p e r s o n n e l PRIMARY KEY ( numpers ) ,
CONSTRAINT c k s a l a i r e CHECK(SALAIRE >= 1 2 5 4 . 2 8 )
);

ALTER TABLE TYPECCL ADD


CONSTRAINT p k t y p e c c l PRIMARY KEY ( n u m t y p e c c l ) ;

ALTER TABLE TYPEOPERATION ADD


CONSTRAINT p k t y p e o p e r a t i o n PRIMARY KEY ( numtypeoper ) ;

ALTER TABLE COMPTECLIENT ADD


(
CONSTRAINT p k c o m p t e c l i e n t
PRIMARY KEY ( numcli , numccl ) ,
CONSTRAINT f k c c l t y p e c c l
FOREIGN KEY ( n u m t y p e c c l )
REFERENCES TYPECCL ( n u m t y p e c c l ) ,
CONSTRAINT f k c c l c l i e n t
FOREIGN KEY ( n u m c l i )
REFERENCES CLIENT ( n u m c l i ) ,
CONSTRAINT f k c c l p e r s o n n e l
FOREIGN KEY ( numpers )
REFERENCES PERSONNEL ( numpers )
);

ALTER TABLE OPERATION ADD


(

126
CONSTRAINT p k o p e r a t i o n
PRIMARY KEY ( numcli , numccl , numoper ) ,
CONSTRAINT f k o p e r c c l
FOREIGN KEY ( numcli , numoper )
REFERENCES COMPTECLIENT ( numcli , numccl ) ,
CONSTRAINT f k o p e r c o d e o p e r
FOREIGN KEY ( numtypeoper )
REFERENCES t y p e o p e r a t i o n ( numtypeoper ) ,
CONSTRAINT m o n t a n t o p e r a t i o n
CHECK( montantoper <> 0 )
);

INSERT INTO TYPECCL VALUES (


(SELECT n v l (MAX( n u m t y p e c c l ) , 0 ) + 1
FROM TYPECCL
),
’ Compte c o u r a n t ’ ) ;

INSERT INTO TYPECCL VALUES (


(SELECT n v l (MAX( n u m t y p e c c l ) , 0 ) + 1
FROM TYPECCL
),
’ livret ’ );

INSERT INTO TYPECCL VALUES (


(SELECT n v l (MAX( n u m t y p e c c l ) , 0 ) + 1
FROM TYPECCL
),
’PEL ’ ) ;

INSERT INTO TYPEOPERATION VALUES (


(SELECT n v l (MAX( numtypeoper ) , 0 ) + 1
FROM TYPEOPERATION
),
’dà p
c ôt e s p à ¨ c e s ’ ) ;

INSERT INTO TYPEOPERATION VALUES (


(SELECT n v l (MAX( numtypeoper ) , 0 ) + 1
FROM TYPEOPERATION
),
’ pr à l
c èvement ’ ) ;

INSERT INTO TYPEOPERATION VALUES (


(SELECT n v l (MAX( numtypeoper ) , 0 ) + 1
FROM TYPEOPERATION
),
’ virement ’ ) ;

INSERT INTO TYPEOPERATION VALUES (


(SELECT n v l (MAX( numtypeoper ) , 0 ) + 1
FROM TYPEOPERATION
),
’ retrait ’ );

127
A.7 Comptes bancaires avec exceptions
DROP TABLE OPERATION;
DROP TABLE COMPTECLIENT;
DROP TABLE TYPECCL;
DROP TABLE TYPEOPERATION;
DROP TABLE PERSONNEL;
DROP TABLE CLIENT ;

CREATE TABLE CLIENT


( n u m c l i number ,
n o m c l i varchar2 ( 3 0 ) ,
p r e n o m c l i varchar2 ( 3 0 ) ,
a d r e s s e varchar2 ( 6 0 ) ,
t e l varchar ( 1 0 )
);

CREATE TABLE PERSONNEL


( numpers number ,
nompers varchar2 ( 3 0 ) ,
prenompers varchar2 ( 3 0 ) ,
manager number ,
s a l a i r e number
);

CREATE TABLE TYPECCL


( n u mt y p ec c l number ,
n o m t y p e c c l varchar2 ( 3 0 )
);

CREATE TABLE COMPTECLIENT


( n u m c l i number ,
numccl number ,
n u m t y pe c c l number ,
d a t e c c l date d e f a u l t s y s d a t e not null ,
numpers number
);

CREATE TABLE TYPEOPERATION


( numtypeoper number ,
nomtypeoper varchar2 ( 3 0 )
);

CREATE TABLE OPERATION


( n u m c l i number ,
numccl number ,
numoper number ,
numtypeoper number ,
d a t e o p e r date d e f a u l t s y s d a t e not null ,
montantoper number not null ,
l i b e l o p e r varchar2 ( 3 0 )
);

ALTER TABLE CLIENT ADD


(
CONSTRAINT p k c l i e n t PRIMARY KEY ( n u m c l i ) ,
CONSTRAINT c k t e l e p h o n e CHECK(LENGTH( t e l )=10)
);

ALTER TABLE PERSONNEL ADD


(
CONSTRAINT p k p e r s o n n e l PRIMARY KEY ( numpers ) ,
CONSTRAINT c k s a l a i r e CHECK(SALAIRE >= 1 2 5 4 . 2 8 )
);

ALTER TABLE TYPECCL ADD


CONSTRAINT p k t y p e c c l PRIMARY KEY ( n u m t y p e c c l ) ;

ALTER TABLE TYPEOPERATION ADD


CONSTRAINT p k t y p e o p e r a t i o n PRIMARY KEY ( numtypeoper ) ;

ALTER TABLE COMPTECLIENT ADD


(
CONSTRAINT p k c o m p t e c l i e n t
PRIMARY KEY ( numcli , numccl ) ,
CONSTRAINT f k c c l t y p e c c l
FOREIGN KEY ( n u m t y p e c c l )
REFERENCES TYPECCL ( n u m t y p e c c l ) ,
CONSTRAINT f k c c l c l i e n t
FOREIGN KEY ( n u m c l i )
REFERENCES CLIENT ( n u m c l i ) ,
CONSTRAINT f k c c l p e r s o n n e l
FOREIGN KEY ( numpers )
REFERENCES PERSONNEL ( numpers )
);

ALTER TABLE OPERATION ADD


(

128
CONSTRAINT p k o p e r a t i o n
PRIMARY KEY ( numcli , numccl , numoper ) ,
CONSTRAINT f k o p e r c c l
FOREIGN KEY ( numcli , numoper )
REFERENCES COMPTECLIENT ( numcli , numccl ) ,
CONSTRAINT f k o p e r c o d e o p e r
FOREIGN KEY ( numtypeoper )
REFERENCES t y p e o p e r a t i o n ( numtypeoper ) ,
CONSTRAINT m o n t a n t o p e r a t i o n
CHECK( montantoper <> 0 AND montantoper >= −1000 AND montantoper <= 1 0 0 0 )
);

INSERT INTO TYPECCL VALUES (


(SELECT n v l (MAX( n u m t y p e c c l ) , 0 ) + 1
FROM TYPECCL
),
’ Compte c o u r a n t ’ ) ;

INSERT INTO TYPECCL VALUES (


(SELECT n v l (MAX( n u m t y p e c c l ) , 0 ) + 1
FROM TYPECCL
),
’ livret ’ );

INSERT INTO TYPECCL VALUES (


(SELECT n v l (MAX( n u m t y p e c c l ) , 0 ) + 1
FROM TYPECCL
),
’PEL ’ ) ;

INSERT INTO TYPEOPERATION VALUES (


(SELECT n v l (MAX( numtypeoper ) , 0 ) + 1
FROM TYPEOPERATION
),
’dà p
c ôt e s p à ¨ c e s ’ ) ;

INSERT INTO TYPEOPERATION VALUES (


(SELECT n v l (MAX( numtypeoper ) , 0 ) + 1
FROM TYPEOPERATION
),
’ pr à l
c èvement ’ ) ;

INSERT INTO TYPEOPERATION VALUES (


(SELECT n v l (MAX( numtypeoper ) , 0 ) + 1
FROM TYPEOPERATION
),
’ virement ’ ) ;

INSERT INTO TYPEOPERATION VALUES (


(SELECT n v l (MAX( numtypeoper ) , 0 ) + 1
FROM TYPEOPERATION
),
’ retrait ’ );

129
A.8 Secrétariat pédagogique
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) ;

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 ) ) ;

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 ) ) ;
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 ) ) ;

130
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 )
)
);

131
A.9 Mariages
CREATE TABLE PERSONNE
( numpers number PRIMARY KEY,
nom varchar2 ( 3 0 ) NOT NULL,
prenom varchar2 ( 3 0 ) ,
p e r e REFERENCES PERSONNE( numpers ) ,
mere REFERENCES PERSONNE( numpers )
);

CREATE TABLE MARIAGE


(
nummari NUMBER REFERENCES PERSONNE( numpers ) ,
numfemme NUMBER REFERENCES PERSONNE( numpers ) ,
d a t e m a r i a g e DATE DEFAULT SYSDATE,
d a t e d i v o r c e DATE DEFAULT NULL,
PRIMARY KEY( nummari , numfemme , d a t e M a r i a g e )
);

132