Vous êtes sur la page 1sur 156

BTS Services informatiques aux organisations – 1re année

EXPLOITATION DES DONNÉES


COURS

BTS Services informatiques aux organisations – 1re année

José Gil

EXPLOITATION
DES DONNÉES
COURS
Retrouvez la liste de nos formations sur www.cned.fr
Pour plus d’informations, appelez le 05 49 49 94 94
Du lundi au vendredi, 8 h 30-18 h.
Coût d’une communication ordinaire.

*82943TGPA0013* www.cned.fr
Sommaire
Conseils généraux 3
Séquence 1 : Présentation de SQL 5
Séquence 2 : Le langage d’interrogation des données (LID) 23
Séquence 3 : Le langage de modification des données (LMD) 69
Séquence 4 : Le langage de description des données (LDD) 79
Séquence 5 : Le langage de contrôle de données (LCD) 97
Séquence 6 : Le langage de contrôle des transactions (LCT) 119
Corrigé des exercices 133

CONNECTÉ À VOTRE AVENIR

Les cours du CNED sont strictement réservés à l’usage privé de leurs destinataires et ne sont pas destinés à une utilisation collective.
Les personnes qui s’en serviraient pour d’autres usages, qui en feraient une reproduction intégrale ou partielle, une traduction sans
le consentement du CNED, s’exposeraient à des poursuites judiciaires et aux sanctions pénales prévues par le Code de la propriété
intellectuelle. Les reproductions par reprographie de livres et de périodiques protégés contenues dans cet ouvrage sont effectuées
par le CNED avec l’autorisation du Centre français d’exploitation du droit de copie (20, rue des Grands Augustins, 75006 Paris).

© CNED 2013
Conseils généraux
Présentation générale du module
Ce module intervient au premier semestre de la première année. Le référentiel lui
réserve 4 heures de cours / TP par semaine sur 15 semaines, ce qui représente un volume
total de 60 heures. Il faut cependant compter beaucoup plus d’heures de travail person-
nel pour les exercices.
Ce module concerne les deux options de la formation (SLAM et SISR).
Il porte sur un langage extrêmement important dans le monde des bases de données. Il
existe de nombreux logiciels de gestion de bases de données. Tous sont différents, soit
par leurs modes de fonctionnement, soit par leurs origines ou philosophies respectives.
Ils ont toutefois une chose en commun : ils utilisent le SQL au sein de leurs systèmes pour
interagir avec les bases de données.
Une fois que vous connaîtrez le SQL, vous pourrez manipuler des données de quasiment
n’importe quelle plateforme logicielle de gestion de bases de données.

Organisation du module
Le cours se décline en six séquences, ponctuées par des exercices applicatifs (dont la cor-
rection se trouve à la fin de ce fascicule) et des travaux pratiques.
Il est très important de suivre toutes les séquences, dans l’ordre, et de les réaliser dans
leur intégralité, quelles que soient vos connaissances préalables dans le domaine des
bases de données et du SQL. En effet, si vous avez déjà des connaissances, elles ne sont
peut-être pas totalement adaptées aux attentes de l’examen.
Conseils généraux
Ce cours est volontairement synthétique pour éviter de vous donner une surcharge de
travail. En contrepartie, tout ce qu’il contient est fondamental et c’est pour cette raison Page 3
qu’il faut le traiter en détail et dans son intégralité.
Deux devoirs d’évaluation sont à faire en respectant la chronologie suivante :
tDevoir 1 : à l’issue de la séquence 3 ;
tDevoir 2 : à l’issue de la séquence 4.

Outils
Dans ce cours, vous allez travailler avec les outils suivants :
PostgreSQL
SGBDR gratuit et téléchargeable sur le site officiel (http://www.postgresql.fr/accueil). Ce
cours a utilisé la version 8.4 mais vous pouvez a priori récupérer la version la plus récente.
Ce SGBDR est l’un des plus connus et des plus appréciés dans le monde gratuit : il est très
puissant et multiplateforme.
FlySpeed SQL Query
Logiciel gratuit permettant l’interrogation de bases de données. Il est téléchargeable sur le
site de l’éditeur Active Database Software : www.activedbsoft.com/overview-querytool.html.
Ce logiciel présente l’avantage de permettre la construction de requêtes graphiques tout
en générant du SQL compatible SQL-92.
Bon courage à tous !

8 2943 TG PA 00
Séquence 1
Présentation de SQL
Cette première séquence présente le langage SQL. Nous allons commen-
cer par un peu d’histoire et terminer par l’installation de PostgreSQL sous
Windows, l’utilisation de pgAdmin et l’installation de FlySpeed SQL Query
pour que vous puissiez programmer en SQL dès la fin de cette séquence.

X Prérequis
Aucun.

X Capacités attendues en fin de séquence


Avoir compris ce qu’est le SQL, un SGBDR et avoir installé les logiciels néces-
saires.

X Contenu
1. Qu’est-ce que le SQL ? ................................................................................. 6
2. Un peu d’histoire, normes et standards .................................................. 6 Séquence 1

3. Le SGBDR ........................................................................................................ 7 Présentation de SQL


4. Les différentes parties du SQL ................................................................... 8
Page 5
5. Installation de PostgreSQL et pgAdmin .................................................. 9
6. Prise en main de pgAdmin ........................................................................ 10
7. Installation et prise en main de FlySpeed SQL Query .......................... 20

8 2943 TG PA 00
1. Qu’est-ce que le SQL ?
C’est l’acronyme de Structured Query Language, soit en français : Langage structuré de
requêtes.
Ce langage, bientôt quarantenaire, permet d’assurer la gestion de bases de données
relationnelles. Sa syntaxe se présente sous la forme d’un pseudo-langage prenant appui
sur des mots de la langue anglaise.
La normalisation du SQL fait qu’il est utilisé par les principaux Systèmes de Gestion de
Bases de Données Relationnelles (SGBDR) : Oracle, DB2, SQL Server, MySQL, PostgreSQL …
Les développeurs de chacun de ces SGBDR ont adapté le SQL pour des besoins spéci-
fiques, on parle alors d’"extensions" (PL/pgSQL pour PostgreSQL, par exemple).
À la base, le SQL n’est pas un langage procédural. En effet, en SQL, lorsque vous voulez
obtenir quelque chose, il vous suffit d’indiquer au système ce que vous souhaitez obte-
nir. Alors qu’avec un langage procédural (VB6, par exemple), il vous faudrait dire au
système comment obtenir ce que vous souhaitez.
Mais ce n’est plus le cas. En 1999, lors d’une révision de la norme SQL (SQL-99), des fonc-
tionnalités procédurales ont été intégrées, satisfaisant ainsi des millions de développeurs
habitués à raisonner en procédural.

2. Un peu d’histoire, normes et standards


Séquence 1 Les bases de données "informatisées" sont nées de la demande croissante en stockage et
Présentation de SQL
en traitement d’informations. Auparavant, elles n’existaient que sous forme de fichiers
"papier", ce qui limitait grandement leur utilisation.
Page 6 Dès 1950, des applications développées en assembleur permettent d’extraire, de consul-
ter et de modifier un fichier informatique contenant des données.
À la fin des années 1950, le département de la
Défense des États-Unis souhaite créer un langage
indépendant des éditeurs de solutions logicielles pour
ses applications de gestion de l’administration améri-
caine. Ainsi naquit un langage de programmation
d’application de gestion, le COBOL (COmmon Business
Oriented Language) qui lui-même donnera naissance aux bases de données hiérar-
chiques.

Dix ans plus tard, les développeurs de COBOL publient


les spécifications d’un modèle de base de données
"réseau" permettant de simplifier la structure logique
du modèle de base de données "hiérarchisées".

En 1970, le Britannique Edgar Frank Codd, alors directeur de


recherche à IBM, rédige une thèse mathématique sur l’algèbre
relationnelle qui lui permet d’aboutir au concept révolutionnaire
de modèle de base de données "relationnel".

8 2943 TG PA 00
Ce modèle organise les données sous forme de tables en deux dimensions avec des index
de ligne permettant l’accès direct aux enregistrements.

Il faudra attendre 1974 pour qu’IBM crée SEQUEL (Structured English QUery Langage),
un langage d’interrogation des données respectant les concepts du modèle relationnel,
qui, deux ans plus tard, fut renommé en SQL. Dès lors, SQL devient le standard dans la
manipulation de bases de données.
En 1987, SQL est adopté comme norme par l’Organisation Internationale de Normalisation
(ISO) et, par la suite, subit un certain nombre de révisions :
t1989 : SQL-89
t1992 : SQL-92
t1999 : SQL-99
t2003 : SQL:2003
t2008 : SQL:2008

3. Le SGBDR
Le SGBDR est un ensemble logiciel permettant de définir, manipuler et administrer des Séquence 1
bases de données relationnelles.
Présentation de SQL
Il faut bien distinguer "La base de données" de son "SGBDR":
tLa base de données est un ensemble structuré et organisé de manière à pouvoir
Page 7
contenir des données.
tLe SGBDR est l’outil qui va vous permettre de créer la base de données et de mani-
puler les données qui se trouvent à l’intérieur.

SGBDR Base de données

8 2943 TG PA 00
4. Les différentes parties du SQL
Le langage SQL est divisé en cinq parties ayant chacune un périmètre bien défini :
tLangage d’Interrogation de Données (LID) : c’est la partie que nous utilisons le plus
fréquemment, celle qui nous permet d’extraire de l’information d’une base de don-
nées. Par exemple, on souhaite obtenir la liste de tous les articles (libellés et prix)
présents dans notre base dont le prix est strictement inférieur à 3 € :

SELECT libelle, prix


FROM article
WHERE prix < 3
tLangage de Manipulation de Données (LMD) : cette partie permet d’effectuer des
opérations de mise à jour en indiquant simplement le traitement que l’on veut
réaliser. Par exemple, on souhaite baisser de 7 % le prix des articles du rayon n° 9 :

UPDATE article
SET prix = prix * 0.93
WHERE idRayon = 9
tLangage de Définition de Données (LDD) : on utilise cette partie pour créer, modi-
fier ou détruire une base de données. Par exemple, on souhaite pouvoir identifier
un article "bio". Pour cela, on va modifier la structure de la table pour y ajouter une
nouvelle colonne "bio" de type booléen (oui/non) :

Séquence 1
ALTER TABLE article
ADD COLUMN bio BOOLEAN
Présentation de SQL
tLangage de Contrôle de Données (LCD) : c’est cette partie qui va nous permettre de
Page 8 sécuriser les accès à une base de données en indiquant des niveaux de privilèges.
Par exemple, on ne souhaite pas que n’importe quel utilisateur du SGBDR puisse
modifier les informations de la table articles :
REVOKE INSERT, UPDATE, DELETE
ON article
FROM PUBLIC
tLangage de Contrôle de Transactions (LCT) : cette partie va nous permettre de
sécuriser les transactions en nous donnant des mécanismes de sauvegarde et de
validation des transactions (pour éviter, par exemple, qu’une panne matérielle ou
logicielle ne vienne interrompre une transaction et ainsi risquer de corrompre des
informations). En cas d’erreur, le contrôle des transactions nous permet d’effectuer
des retours à des situations antérieures :

SAVEPOINT maSauvegarde
...
ROLLBACK TO SAVEPOINT MaSauvegarde

8 2943 TG PA 00
5. Installation de PostgreSQL et pgAdmin

Installation sous Windows


tTéléchargez l’exécutable à cette adresse :
http://www.postgresql.org/download/windows
tPendant l’installation, un mot de passe pour l’administrateur (postgres) vous est
demandé. Une fois saisi, veillez à ne pas l’oublier !

Séquence 1

tUne fois le serveur PostgreSQL installé, vous pourrez constater que l’outil d’admi- Présentation de SQL
nistration pgAdmin a également été installé.
tLancez-le. Par défaut, vous verrez apparaître votre serveur local (serveur barré Page 9
d’une croix rouge).
tDouble-cliquez sur votre serveur pour vous y connecter. Une demande d’authenti-
fication apparaît. Saisissez le mot de passe que vous avez donné pendant l’instal-
lation :

Installation sous Linux


tUtilisez votre gestionnaire de paquets (Synaptic sur Debian, YUM sur Fedora, YaST
sur OpenSuse …) et choisissez les paquets "postgresql" et "pgadmin".

8 2943 TG PA 00
6. Prise en main de pgAdmin

Fenêtre principale
Cette fenêtre affiche la structure des bases de données. À partir de cette fenêtre, on peut
créer de nouveaux objets, supprimer et modifier les objets déjà existants.

Rafraîchissement

Propriétés
Navigateur de l’objet
d’objets

Panneau
SQL

Séquence 1 Ligne de
statut
Présentation de SQL

Page 10 tRafraîchissement : pgAdmin minimise au maximum la bande passante utilisée. Le


statut des objets dans le navigateur n’est rafraîchi que par une demande de l’uti-
lisateur ou après que des modifications ont été réalisées par les outils intégrés.
Attention, toutefois, aux modifications réalisées par des requêtes SQL. Elles ne pro-
voquent pas de rafraîchissement automatique.
tNavigateur d’objets : contient une structure arborescente de tous les serveurs et des
objets (bases, utilisateurs …) qu’ils contiennent.
tPropriétés de l’objet : cet espace fournit les propriétés de l’objet sélectionné dans
le navigateur d’objet.
tLigne de statut : cette zone affiche l’état actuel, ainsi que la dernière action réalisée
avec succès par pgAdmin.
tPanneau SQL : affiche les instructions SQL qui ont permis de créer l’objet sélec-
tionné dans le navigateur d’objets.

8 2943 TG PA 00
Création d’un utilisateur pour le cours
tCliquez avec le bouton droit sur "Rôles de connexion" et choisissez "Ajouter un rôle
de connexion":

tDans l’onglet "Propriétés", saisissez le "Nom du rôle" ("myuser", par exemple) et


saisissez le mot de passe de ce compte :

Séquence 1

Présentation de SQL

Page 11

tDans l’onglet "Droits du rôle", décochez la case "Hérite des droits des rôles parents",
cochez les cases "Peut créer des bases de données" et "Peut créer des rôles".

tLe dernier onglet "SQL" vous donne l’instruction SQL qui va être exécutée pour
créer le rôle.

tDéconnectez-vous du serveur en cliquant dessus avec le bouton droit et en choisis-


sant "Se déconnecter".

tCliquez sur le serveur avec le bouton droit et choisissez "Propriétés".

tModifiez le "Nom d’utilisateur" en utilisant celui que nous venons de créer


(myuser).

8 2943 TG PA 00
tReconnectez-vous, le mot de passe qui vous est demandé est celui de l’utilisateur
"myuser":

Création d’une base de données pour le cours


tCliquez avec le bouton droit sur "Bases de données" et choisissez "Ajouter une base
de données".

tDans le "Nom", saisissez "magasin" et comme propriétaire, choisissez "myuser".


Séquence 1

Présentation de SQL

Page 12

Lorsque vous créez une base, une table ou même un champ dans PostgreSQL avec un outil
comme pgAdmin, veillez à toujours saisir les libellés en minuscules. C’est capital pour
que vos futures requêtes soient insensibles à la casse (indifférence majuscules / minuscules).

8 2943 TG PA 00
Contexte d’étude "magasin"
L’entreprise que nous allons étudier est un commerce de proximité de type "supérette"
organisé en rayons contenant des articles de diverses marques.
Lors du passage en caisse, on conserve la date, le détail des articles achetés ainsi que le
montant total qui a été réglé pour cet achat.
On conserve également les informations concernant les fournisseurs et les livraisons.
Pour chaque livraison, on mémorise le fournisseur ainsi que le ou les lots qui ont été
livrés.
Chaque lot concerne un seul article. Un lot est identifié par son numéro de lot et par le
code-barres de l’article qu’il concerne. Un article possède un identifiant unique, le code-
barres. C’est son appartenance à un lot qui permet de retrouver les informations qui le
concernent (dates de fabrication, de livraison et de péremption).
On peut d’ailleurs voir sur les photos suivantes quatre articles ayant le même code-
barres, mais des numéros de lot différents et donc des dates de péremption différentes.

Séquence 1

Présentation de SQL

Page 13

8 2943 TG PA 00
Schéma conceptuel de la base de données "magasin"
LOT ARTICLE RAYON
idLot
1,1 Placer 0,n
idArticle idRayon
(1,1) Appartenir 1,n
dateFabrication libelle libelle
dateLivraison prix
datePeremption packaging
MARQUE
uniteMesure
1,1 1,1 0,n idMarque
quantite Être
Livrer bio nom

0,n
0,n

FOURNISSEUR ListeCourses

idFournisseur quantite
raisonSociale
adresseRue 1,n
adresseCP ACHAT
adresseVille
email idAchat
numeroTelephone dateAchat
distanceKm montantTotal

Séquence 1

Présentation de SQL
Diagramme de classes de la base de données "magasin"
LOT ARTICLE RAYON
Page 14
idLot 1..* 1 idArticle * 1 idRayon
dateFabrication libelle libelle
dateLivraison prix
datePeremption packaging
uniteMesure
* quantite
* 1 MARQUE
bio
1 idMarque
1..* nom
FOURNISSEUR
idFournisseur
raisonSociale LISTECOURSES
adresseRue
quantite
adresseCP
adresseVille ACHAT
email idAchat
numeroTelephone * dateAchat
distanceKm montantTotal

8 2943 TG PA 00
Ces deux schémas sont issus de deux "mondes" différents :
s Le schéma conceptuel (également appelé "schéma entité/association") provient de la
méthodologie Merise qui a été, pendant des décennies, "la" méthode à utiliser pour
analyser et concevoir des projets informatiques.
s Le diagramme de classes est l’élément central du langage de modélisation UML.
Normalisé à la fin des années 1990, ce langage de modélisation orienté objet est de plus
en plus utilisé dans les projets informatiques.
Quelle que soit la modélisation, cela représente toujours des règles de gestion. Quelques
éléments pour comprendre les deux modélisations :
s Règle : Un article est placé dans un rayon.

Schéma conceptuel (Merise) Diagramme de classes (UML)

ARTICLE RAYON ARTICLE RAYON


1,1 Placer 0,n * 1

s Règle : Une liste de courses représente un achat d’articles. Chaque article y figure une
seule fois, dans une certaine quantité.

Schéma conceptuel (Merise) Diagramme de classes (UML)

ARTICLE 0,1 ACHAT ARTICLE 1..* ACHAT


ListeCourses 1,n *
Séquence 1
quantite

Présentation de SQL
LISTECOURSES
Page 15
quantite

s Règle : Chaque lot concerne un seul article. Un lot est identifié par son numéro de
lot et par le code-barres de l’article qu’il concerne 1.

Schéma conceptuel (Merise) Diagramme de classes (UML)

ARTICLE 1,n (1,1) LOT ARTICLE 1 1..* LOT


Appartenir

1. C’est d’ailleurs pour cela qu’au niveau relationnel (c’est-à-dire dans la description logique des
données), la relation "Lot" aura sa clé primaire, composée également de la clé primaire de la
relation "Article".

8 2943 TG PA 00
Schéma relationnel de la base de données "magasin"
FOURNISSEUR (idFournisseur, raisonSociale, adresseRue, adresseCP,
adresseVille, email, numeroTelephone, distanceKm)
idFournisseur : Clé primaire

LOT (idLot, idArticle, dateFabrication, dateLivraison,


datePeremption, idFournisseur)
idLot, idArticle : Clé primaire
idArticle : Clé étrangère en référence à idArticle de article
idFournisseur : Clé étrangère en référence à idFournisseur de
fournisseur

ARTICLE (idArticle, libelle, prix, packaging, uniteMesure,


quantite, bio, idMarque, idRayon)
idArticle : Clé primaire
idMarque : Clé étrangère en référence à idMarque de marque
idRayon : Clé étrangère en référence à idRayon de rayon

RAYON (idRayon, libelle)


idRayon : Clé primaire

MARQUE (idMarque, nom)


idMarque : Clé primaire

Séquence 1 LISTECOURSES (idArticle, idAchat, quantite)


idArticle, idAchat : Clé primaire
Présentation de SQL idArticle : Clé étrangère en référence à idArticle de article
idAchat : Clé étrangère en référence à idAchat de achat
Page 16
ACHAT (idAchat, dateAchat, montantTotal)
idAchat : Clé primaire

Dictionnaire des données de la base de données "magasin"


Nom Type de données Longueur Précision

FOURNISSEUR
idFournisseur numeric 2 4 0
raisonSociale character varying 3
adresseRue character varying
adresseCP character 4 5
adresseVille character varying
email character varying
numeroTelephone character varying

2."numeric": type permettant de stocker une valeur numérique.


3."character varying": type permettant de stocker une chaîne de caractères de longueur variable.
4."character": type permettant de stocker une chaîne de caractères de longueur fixe. Attention,
des espaces sont ajoutés pour obtenir la longueur fixe spécifiée.

8 2943 TG PA 00
Nom Type de données Longueur Précision

distanceKm numeric 4 1
LOT
idLot character 10
dateFabrication date 5

dateLivraison date
datePeremption date
ARTICLE
idArticle numeric 13 0
libelle character varying
prix numeric 6 2
packaging character varying
uniteMesure character varying
quantite numeric 8 3
bio boolean 6

ACHAT
idAchat numeric 8 0
dateAchat date
montantTotal numeric 6 2
LISTECOURSES Séquence 1
quantité numeric 3 0
Présentation de SQL
RAYON
idRayon numeric 2 0 Page 17
libelle character varying
MARQUE
idMarque numeric 3 0
nom character varying

Création de la table de données "rayon"56


tCliquez avec le bouton droit sur "Tables" et choisissez "Ajouter une table":

5."date": type permettant de stocker une date.


6."boolean": type qui ne permet d’avoir que deux valeurs : "true" (vrai) ou "false" (faux).

8 2943 TG PA 00
tSaisissez le "Nom" de la table (rayon) et son propriétaire (myuser).
tAllez dans l’onglet "Colonnes" et cliquez sur le bouton "Ajouter".
tSaisissez le "Nom" de la colonne (idrayon), le "Type de données" (numeric), la
"Longueur" (2), "Précision" (0), cochez la case "Non NULL" et validez par OK.
tCliquez de nouveau sur "Ajouter".
tSaisissez le "Nom" de la colonne (libelle), le "Type de données" (character varying)
et validez par "OK".
tAllez maintenant dans l’onglet "Contraintes", choisissez "Clé primaire" dans le
menu déroulant et cliquez sur le bouton "Ajouter".
tSaisissez le "Nom" de la clé primaire (pk_rayon) 7, dans l’onglet "Colonnes" choisis-
sez "idrayon" dans le menu déroulant et cliquez sur le bouton "Ajouter".
tValidez l’ajout de cette clé en cliquant sur OK.
tValidez l’ajout de cette table en cliquant à nouveau sur OK.
tDépliez l’arborescence de la table "rayon", de ses "Colonnes" et de ses "Contraintes",
vous devriez avoir l’affichage suivant :

Séquence 1

Présentation de SQL

Page 18

Création de la table de données "article"


tCliquez avec le bouton droit sur "Tables" et choisissez "Ajouter une table".
tSaisissez le "Nom" de la table (article) et son propriétaire (myuser).
tAllez dans l’onglet "Colonnes" et cliquez sur le bouton "Ajouter".
tSaisissez le "Nom" de la colonne (idarticle), le "Type de données" (numeric), la
"Longueur" (13), "Précision" (0), cochez la case "Non NULL" et validez par OK.
tCliquez de nouveau sur "Ajouter".
tSaisissez le "Nom" de la colonne (libelle), le "Type de données" (character varying),
la "Longueur" (50) et validez par OK.

7. PK pour Primary Key qui signifie "Clé primaire".

8 2943 TG PA 00
tCliquez de nouveau sur "Ajouter".
tSaisissez le "Nom" de la colonne (prix), le "Type de données" (numeric), la
"Longueur" (6), "Précision" (2) et validez par OK.
tCliquez de nouveau sur "Ajouter".
tSaisissez le "Nom" de la colonne (packaging), le "Type de données" (character
varying) et validez par OK.
tCliquez de nouveau sur "Ajouter".
tSaisissez le "Nom" de la colonne (unitemesure), le "Type de données" (character
varying), et validez par OK.
tCliquez de nouveau sur "Ajouter".
tSaisissez le "Nom" de la colonne (quantite), le "Type de données" (numeric), la
"Longueur" (8), "Précision" (3) et validez par OK.
tCliquez de nouveau sur "Ajouter".
tSaisissez le "Nom" de la colonne (bio), le "Type de données" (boolean) et validez
par OK.

Séquence 1

Présentation de SQL

Page 19

tCliquez de nouveau sur "Ajouter".


tSaisissez le "Nom" de la colonne (idrayon), le "Type de données" (numeric) la
"Longueur" (2), "Précision" (0), cochez la case "Non NULL"8 et validez par OK.
tAllez maintenant dans l’onglet "Contraintes", choisissez "Clé primaire" dans le
menu déroulant et cliquez sur le bouton "Ajouter".
tSaisissez le "Nom" de la clé primaire (pk_article), dans l’onglet "Colonnes" choisis-
sez "idarticle" dans le menu déroulant et cliquez sur le bouton "Ajouter".
tValidez l’ajout de cette clé en cliquant sur OK.
tChoisissez "Clé étrangère" dans le menu déroulant et cliquez sur le bouton
"Ajouter".

8. Respect de la cardinalité minimale "1" entre "Article" et "Rayon" de notre schéma conceptuel.

8 2943 TG PA 00
tSaisissez le "Nom" de la clé étrangère (fk_rayon) 9, sélectionnez "rayon" dans le
menu déroulant "Références".
tDans l’onglet "Colonnes" choisissez "idrayon" dans le menu déroulant "Colonne
locale" et "idrayon" dans le menu déroulant "Référence vers". Cliquez sur le bou-
ton "Ajouter".
tValidez l’ajout de cette clé en cliquant sur OK.
tValidez l’ajout de cette table en cliquant à nouveau sur OK.

Exercice 1
En vous appuyant sur les schémas de la page 14, le schéma relationnel de la page 16,
le dictionnaire des données et les manipulations des pages précédentes, terminez la
création de la base de données à l’aide de pgAdmin.

7. Installation et prise en main de FlySpeed SQL Query


Nous allons à présent installer FlySpeed SQL Query, qui est un logiciel permettant
d’effectuer des requêtes graphiquement, ce qui, dans un premier temps, vous facilitera
l’apprentissage des bases du SQL.

Séquence 1 Paramètres de connexion avec PostgreSQL :


tÀ l’ouverture de FlySpeed SQL Query, cliquez sur le menu "Connection" puis
Présentation de SQL
"New Connection":
Page 20

9. FK pour Foreign Key qui signifie "Clé étrangère".

8 2943 TG PA 00
tL’assistant se lance, validez le message de bienvenue en cliquant sur "Next".
Choisissez ensuite le type de connexion désirée. Ici, il faut, bien évidemment,
prendre "PostgreSQL". Cliquez ensuite sur "Next" pour passer à l’écran suivant :

Séquence 1

tSaisissez ensuite les informations de connexion comme ci-dessous et validez avec Présentation de SQL
"Next":
Page 21

8 2943 TG PA 00
tNommez la connexion "connmagasin" et cochez les cases comme ci-dessous :

Séquence 1 Fenêtre principale


À partir de cette fenêtre, on peut interroger la base de données en créant de nouvelles
Présentation de SQL
requêtes. Il suffit pour cela d’effectuer des "glisser/déposer" des tables de gauche, vers
Page 22
la "zone de requêtes graphiques" à droite.

Nouvelle requête Exécution d’une requête

Zone de
Tables de requêtes
la base de graphique
données

Détails et
précisions

Zone SQL

Ligne de
statut

8 2943 TG PA 00
Séquence 2
Le langage d’interrogation
des données : SELECT
Cette séquence aborde la partie la plus utilisée de SQL : l’interrogation.
C’est cette partie qui permet d’extraire les informations que nous recher-
chons. Contrairement aux idées reçues, c’est loin d’être la partie la plus
facile, au contraire ! La véritable difficulté ne réside pas dans l’utilisation
du langage à proprement dit, mais bien dans sa mise en œuvre.

X Prérequis
Avoir compris le sens des manipulations effectuées à la séquence 1.

X Capacités attendues en fin de séquence


Être capable d’extraire des informations d’une base de données en SQL.

Séquence 2
X Contenu
Le langage
1. Le choix des colonnes ......................................................................... 24 d'interrogation
des données (LID)
2. Les tables concernées ......................................................................... 28
3. Les conditions simples ........................................................................ 30 Page 23
4. Les calculs ............................................................................................ 36
5. Les jointures ........................................................................................ 41
6. Les tris ................................................................................................. 49
7. Les requêtes imbriquées .................................................................... 51
8. Les regroupements ............................................................................. 56
9. Les conditions sur regroupements .................................................... 58
10. La soustraction ................................................................................. 59
11. La division ......................................................................................... 62
12. Les opérations entre requêtes ......................................................... 63

...........................................................................................................
Synthèse 67

8 2943 TG PA 00
1. Le choix des colonnes
Le résultat d’une requête d’interrogation est une nouvelle table. Ce qui veut dire que
c’est à vous, concepteur de la requête, de prévoir quelle(s) colonne(s) vous voulez voir
affichée(s).
tPar exemple, on souhaite envoyer un email à tous nos fournisseurs. Pour cela, nous
allons avoir besoin de récupérer leurs noms et leurs emails respectifs.

Dans la zone SQL, vous pouvez voir que, lorsqu’il y a plusieurs champs à afficher, on
sépare leurs noms par une virgule :

SELECT fournisseur.raisonSociale, fournisseur.email


FROM fournisseur
Séquence 2
En SQL, un champ est identifié par son nom et par la table où il se situe. Ce qui veut dire
Le langage que, lorsqu’on utilise un champ, on doit normalement préciser la table à laquelle il appar-
d'interrogation
tient en préfixant le nom du champ par le nom de la table. Dans l’exemple précédent, le
des données (LID)
moteur d’exécution SQL n’a pas besoin de ces "précisions" car on utilise une seule table
(fournisseur) et que, dans cette table, il n’y a qu’un seul champ "raisonSociale" et qu’un
Page 24
seul champ "email". Il n’y a donc pas de confusion possible.
Dans la zone SQL, modifiez directement la requête pour lui retirer les préfixes de noms de
tables et réexécutez-la. Le résultat restera le même :

SELECT raisonSociale, email


FROM fournisseur

Prenons le cas où 2 attributs portent le même nom, dans des tables distinctes (ici on sou-
haite obtenir la liste des articles avec le rayon où ils sont placés) :

Sans préfixe
Avec préfixe
(attention, cette requête provoque une erreur 10)
SELECT article.libelle,
SELECT libelle, libelle rayon.libelle
FROM article, rayon FROM article, rayon
WHERE … WHERE …
Deux attributs portant le même nom doivent être préfixés par le nom de la table d’origine
pour éviter toute ambigüité quant à leurs tables d’appartenance.

10. Le moteur d'exéction SQL ne sait pas où aller chercher les champs "libelle" avec exactitude.

8 2943 TG PA 00
Le caractère * ("étoile")
L’étoile est un caractère qui désigne "tout".
tPar exemple, on souhaite afficher l’intégralité de la table "article". On pourrait
cocher toutes les cases de la table, mais, à la place, cochez uniquement la case "*":


Dans la zone SQL, on peut voir qu’utilisé avec l’instruction SELECT, cela correspond à
"toutes les colonnes de la table":

SELECT *
FROM article

Il faut toutefois utiliser ce "joker" avec prudence. En fonction de la structure de certaines


tables, le résultat produit peut s’avérer gigantesque et très consommateur de ressources
systèmes ralentissant ainsi le serveur. Séquence 2
Il faut également garder à l’esprit qu’utilisé avec une requête portant sur plusieurs tables, le
caractère "*" signifie "tous les champs, de toutes les tables". Soyez donc bien sûr que vous Le langage
d'interrogation
voulez bien tous les champs, avant de l’utiliser. des données (LID)

Le mot clé "DISTINCT" Page 25


tOn souhaite afficher le numéro des fournisseurs qui nous ont déjà fourni (idfournis-
seur présent dans la table "lot") :

Lorsque le moteur d’exécution SQL construit un résultat, par défaut, il prend toutes les
lignes qui satisfont à la requête demandée, y compris les lignes en double.
Ce qui nous donne en SQL, sans DISTINCT :

SELECT idFournisseur
FROM lot

tPour utiliser la suppression de doublons, il suffit de cliquer avec le bouton droit dans
la zone de requête (près d’une table), de choisir "DISTINCT" comme "SELECT Type"
(type d’interrogation) et de valider avec OK :

8 2943 TG PA 00
Séquence 2
Le mot clé DISTINCT, utilisé avec l’instruction SELECT, a pour effet de ne pas afficher de
Le langage doublons (lignes en double) :
d'interrogation
des données (LID) SELECT DISTINCT idFournisseur
FROM lot
Page 26

Le mot clé "AS"


Le SQL nous permet d’améliorer la lisibilité d’une requête en créant un "alias" de
colonne, c’est-à-dire un nom de substitution ou un pseudonyme.
tPar exemple, on souhaite afficher les coordonnées postales de tous les fournisseurs
présents dans notre base :

Dans la zone SQL, on peut voir que la requête est tout à fait semblable aux précédentes :

SELECT raisonSociale, adresseRue, adresseCP, adresseVille


FROM fournisseur

8 2943 TG PA 00
tNous allons à présent utiliser des alias. Pour cela, dans la zone "Détails et préci-
sions", saisissez dans la colonne "Alias" les correspondances suivantes (les alias
devront être entourés de guillemets). Exécutez-la, et regardez de plus près les inti-
tulés de colonnes :

Séquence 2

Le langage
d'interrogation
des données (LID)
Dans la zone SQL, on peut voir que la clause "AS" a été ajoutée après chaque champ
pour spécifier un alias :
Page 27
SELECT raisonSociale AS "Nom",
adresseRue AS "Adresse",
adresseCP AS "Code Postal",
adresseVille AS "Ville"
FROM fournisseur

Les guillemets qui entourent l’alias sont facultatifs mais fortement recommandés pour
plusieurs raisons :
s ils évitent tout risque de conflit si l’alias est un mot réservé (par le SQL ou le SGBDR) ;
s ils préviennent d’un éventuel conflit en cas d’ajout futur de mot-clé ;
s ils permettent de conserver la casse exacte de l’alias (majuscules/minuscules) ;
s ils permettent d’avoir plusieurs mots séparés par des espaces.

8 2943 TG PA 00
2. Les tables concernées
Comme vous avez pu le constater dans les précédents exemples, en plus de l’instruction
SELECT, il y a l’instruction "FROM". Celle-ci permet de définir les tables dont nous avons
besoin pour construire le résultat. Lorsqu’il y a plusieurs tables, on sépare leurs noms par
une virgule.
tPar exemple, si on a besoin de connaître la liste des fournisseurs de "kiwis", on aura
obligatoirement besoin des tables "fournisseur", "lot" et "article". Glissez-déposez
ces trois tables :

Séquence 2 Ce qui nous donne, en SQL :

Le langage ...
d'interrogation FROM fournisseur, lot, article
des données (LID)
...
Page 28
Le mot clé "AS"
Comme pour les alias de colonnes, on peut créer des alias de tables, c’est-à-dire un nom
de substitution ou un pseudonyme, pour nous permettre encore une fois d’améliorer la
lisibilité d’une requête.
tReprenons l’exemple d’utilisation du préfixage avec le nom de table :

SELECT article.libelle, rayon.libelle


FROM article, rayon
WHERE ...

Avec alias de tables Avec alias de tables et de champs


SELECT a.libelle, r.libelle SELECT a.libelle AS "Article",
FROM article AS a, rayon AS r r.libelle AS "Rayon"
WHERE ... FROM article AS a, rayon AS r
WHERE ...

Attention, dès lors que l’on a créé un alias, il devient le nouveau nom de la table et on ne
peut plus utiliser le nom d’origine pour s’y référer (contrairement aux alias de colonnes).

8 2943 TG PA 00
tPour créer un alias de table, le mot clé "AS" n’est en réalité pas obligatoire et,
comme pour les alias de champs, un espace suffit (cela rend toutefois la requête un
peu moins lisible) :
SELECT a.libelle "Article", r.libelle "Rayon"
FROM article a, rayon r
WHERE ...

Pour créer un alias de table dans FlySpeed SQL Query, il vous suffit de cliquer avec le bou-
ton droit sur la table où l’on souhaite insérer un alias et de choisir dans le menu qui appa-
raît "Properties…". Dans la fenêtre qui apparaît, il suffit ensuite de saisir l’alias désiré :

Séquence 2

Le langage
d'interrogation
des données (LID)

Exercice 1 Page 29

Réaliser les requêtes permettant d’obtenir les informations ci-dessous. Dans la


mesure du possible, essayez de réaliser ces requêtes directement en SQL.
Si vous n’y arrivez pas, essayez ensuite en graphique :
tla liste des fournisseurs ("n°F" doit apparaître à la place de "idFournisseur" et
"Nom" à la place de "raisonSociale") ;
tla liste des références d’articles qui ont déjà été sur des listes de courses ("Code
barre" doit apparaître à la place de "idArticle") ;
tla liste des marques ("m" doit être utilisé comme alias de la table "marque".
Utilisez également le préfixage des champs) ;
tla liste des achats :
– "N°" doit apparaître à la place de "idAchat", "Date" à la place de
"dateAchat" et "Prix à payer" à la place de "montantTotal";
– utilisez "a" comme alias de la table "achat";
– utilisez le préfixage des champs.

8 2943 TG PA 00
3. Les conditions simples
Nous allons maintenant voir comment restreindre une requête à un ensemble bien défini
en effectuant une sélection dite "conditionnelle" des enregistrements. Pour cela, nous
avons besoin de l’instruction "WHERE". Cette instruction va nous permettre de définir
une ou plusieurs conditions que les enregistrements devront vérifier pour pouvoir faire
partie des enregistrements concernés par notre requête.
Les opérateurs et les mots-clés utilisés dans les conditions sont également appelés "prédi-
cats"

tOn souhaite à présent obtenir la liste de tous les articles à "moins d’1 euro". Il nous
suffit donc de sélectionner la table "article" et les champs désirés. Ensuite, il ne nous
reste plus qu’à insérer notre condition "< 1" dans la colonne "Criteria" sur la ligne
correspondant au champ "prix" (puisque, ici, ce qui nous intéresse, c’est de retenir
les articles, dont le prix est inférieur à 1 euro) :

Séquence 2

Le langage
d'interrogation
des données (LID)

Page 30

En examinant la zone SQL, on peut voir que notre condition a été reportée après l’ins-
truction "WHERE":

SELECT idarticle, libelle, prix


FROM article
WHERE prix < 1

8 2943 TG PA 00
Les prédicats de comparaison

Opérateur Description Accepté sur papier

< inférieur à
> supérieur à
<= inférieur ou égal à ≤
>= supérieur ou égal à ≥
= égal à
<> ou != différent de ≠

tExemple : on souhaite obtenir la liste de tous les articles à "1 euro". En graphique,
il nous suffit de modifier le contenu de la colonne "Criteria".

En SQL, il nous suffit de modifier la condition qui se trouve dans le “WHERE":

SELECT idarticle, libelle, prix


Séquence 2
FROM article
WHERE prix = 1 Le langage
d'interrogation
des données (LID)
Les opérateurs logiques "AND", "OR" et "NOT"
Ces opérateurs vont nous permettre de combiner plusieurs conditions en construisant Page 31
des expressions logiques. Par exemple, si on souhaite obtenir la liste de tous les articles
dont le prix se situe entre 5 et 10 euros.
tEn graphique, il nous suffit de modifier le contenu de la colonne "Criteria" en insé-
rant ">= 5 and <= 10":

En SQL, il nous suffit de modifier la condition qui se trouve dans le "WHERE":

SELECT idarticle, libelle, prix


FROM article
WHERE prix >= 5
AND prix <= 10

8 2943 TG PA 00
Le prédicat d’intervalle "BETWEEN"
Le prédicat "BETWEEN" nous permet de définir des intervalles d’une manière plus effi-
cace et plus intuitive qu’avec les prédicats de comparaison.
tSi on reprend l’exemple précédent, on peut donc écrire la condition de cette
manière :

Ce qui nous donne, en SQL :

SELECT idarticle, libelle, prix


FROM article
WHERE prix BETWEEN 5 AND 10

Attention, jusqu’à la norme SQL:2003 il fallait obligatoirement que la première valeur


limite soit inférieure à la deuxième. Mais, depuis SQL:2003, la clause "SYMMETRIC" a
été ajoutée. Il suffit de l’insérer après BETWEEN pour que la condition fonctionne même
si la première valeur est supérieure à la deuxième.

SELECT idarticle, libelle, prix


Séquence 2
FROM article
Le langage WHERE prix BETWEEN SYMMETRIC 10 AND 5
d'interrogation
des données (LID) La requête précédente peut retourner une erreur dans FlySpeed SQL Query mais elle fonc-
tionne tout de même car PostgreSQL connaît la clause "SYMMETRIC" et sait l’utiliser.
Page 32 On ne pourra toutefois pas utiliser cette clause graphiquement, FlySpeed SQL Query ne la
reconnaissant pas.

Le prédicat "BETWEEN" présente plusieurs avantages : il comprend les valeurs limites


données dans la requête et peut être utilisé avec les types "chaîne de caractères", "date"
ainsi qu’avec les valeurs numériques.
tPar exemple, on veut obtenir les adresses électroniques des fournisseurs dont le
nom (la raison sociale) commence par une lettre entre "A" et "L" (il faudra donc
mettre la lettre suivante comme borne) :

Il faut toujours bien lire ce qui est demandé. Ici, par exemple, on souhaite obtenir unique-
ment les adresses électroniques et rien d’autre. C’est pour cette raison que seul le champ
"email" est coché. Le champ "raisonsociale" est bien entendu présent car on en a besoin
pour y appliquer une condition, mais ce dernier n’ayant pas à apparaître dans le résultat,
il ne devra pas être coché.

8 2943 TG PA 00
Ce qui nous donne en SQL :
SELECT email
FROM fournisseur
WHERE raisonSociale BETWEEN 'A' AND 'M'

tAutre exemple : on veut obtenir la liste des livraisons effectuées entre le 15 et le


31 mars :

Comme pour la requête précédente, ici, seul le champ "idLot" est demandé. Cela doit donc
être le seul champ coché.

Ce qui nous donne, en SQL :

SELECT idLot
FROM lot
WHERE dateLivraison BETWEEN '2010/03/15'
AND '2010/03/31'

Séquence 2
Par défaut, le format de date des SGBDR est "année/mois/jour". C’est pourquoi il est
souvent nécessaire, pour que la requête fonctionne, de renseigner la date en respectant ce Le langage
d'interrogation
format.
des données (LID)

Le prédicat de liste "IN" Page 33


Le prédicat "IN" permet de vérifier si des valeurs spécifiques se trouvent dans une liste
de valeurs plus simplement qu’avec les prédicats de comparaison.
tPar exemple, on veut obtenir le nom des fournisseurs de "Toulon", "Ollioules", "La
Seyne sur Mer" et "Sanary sur Mer":
– Avec les prédicats de comparaison :

Ce qui nous donne, en SQL :

SELECT raisonSociale
FROM fournisseur
WHERE adresseVille = 'Toulon'
OR adresseVille = 'Ollioules'
OR adresseVille = 'La Seyne sur Mer'
OR adresseVille = 'Sanary sur Mer'

8 2943 TG PA 00
– Avec le prédicat de liste "IN":

Ce qui nous donne, en SQL :

SELECT raisonSociale
FROM fournisseur
WHERE adresseVille IN ('Toulon','Ollioules',
'La Seyne sur Mer','Sanary sur Mer')

Le prédicat "IN" permet de sélectionner les enregistrements qui contiennent l’une des valeurs
de la liste. En associant l’opérateur logique "NOT", on peut faire l’inverse en sélectionnant
les enregistrements qui ne contiennent aucune des valeurs présentes dans la liste.

tPar exemple, on veut obtenir le nom des fournisseurs qui ne sont ni sur "Toulon",
ni sur "Ollioules", ni sur "La Seyne sur Mer":

Séquence 2

Le langage Ce qui nous donne, en SQL :


d'interrogation
des données (LID)
SELECT raisonSociale
FROM fournisseur
Page 34
WHERE adresseVille NOT IN ( 'Toulon','Ollioules',
'La Seyne sur Mer' )

Le prédicat de comparaison partielle "LIKE"


Le prédicat "LIKE" permet d’obtenir les enregistrements où la valeur de la colonne sélec-
tionnée est similaire à la chaîne comparée. Pour utiliser correctement ce prédicat, il faut
utiliser l’un des deux caractères de substitution du langage SQL :
tLe caractère pourcentage "%" remplace n’importe quelle chaîne de caractères (0
ou plusieurs) :
– on souhaite obtenir la liste des fournisseurs présents dans le Var (département
83) :

Ce qui nous donne, en SQL :

SELECT raisonSociale
FROM fournisseur
WHERE adresseCP LIKE '83%'

8 2943 TG PA 00
tLe blanc souligné "_" (également appelé "tiret du bas" ou "underscore") remplace
n’importe quel caractère (1 seul par "_") :
– même requête que précédemment. On souhaite obtenir la liste des fournis-
seurs présents dans le Var (département 83) :

Ce qui nous donne, en SQL :

SELECT raisonSociale
FROM fournisseur
WHERE adresseCP LIKE '83_ _ _'

L’inconvénient du blanc souligné est qu’il faut connaître avec exactitude le nombre de
caractères sur lesquels on veut un "joker".

Le prédicat de nullité "NULL"


Le prédicat "NULL" permet d’obtenir les enregistrements où la valeur de la colonne
sélectionnée est nulle, c’est-à-dire sans aucune valeur. Séquence 2

tPar exemple, on veut obtenir la liste des fournisseurs (raisons sociales et numéros de Le langage
téléphone) pour qui on ne dispose pas de leurs emails : d'interrogation
des données (LID)

Page 35

Ce qui nous donne, en SQL :

SELECT raisonSociale, numeroTelephone


FROM fournisseur
WHERE email IS NULL

On ne peut pas écrire "= NULL" parce que NULL n’est pas "égal à" NULL (la valeur NULL
représente une valeur inconnue et il est impossible de dire si deux valeurs inconnues sont
égales).
En utilisant l’opérateur "NOT", on peut faire l’inverse, c’est-à-dire ne récupérer que les
enregistrements où la valeur de la colonne n’est pas nulle.

8 2943 TG PA 00
tPar exemple, on veut obtenir la liste des fournisseurs (raisons sociales et numéros de
téléphone) qui nous ont fourni leurs emails :

Ce qui nous donne, en SQL :

SELECT raisonSociale, numeroTelephone


FROM fournisseur
WHERE email IS NOT NULL

Exercice 2
Réaliser les requêtes permettant d’obtenir les informations ci-dessous. Comme
pour les exercices précédents, essayez, dans la mesure du possible, de réaliser ces
requêtes directement en SQL. Si vous n’y arrivez pas, essayez ensuite en graphique :
tla liste des fournisseurs dont la distance est de moins de 100 km ;
tla liste des fournisseurs qui se situent à plus de 10 km mais à moins de 100 km ;
tla liste des fournisseurs ayant une adresse email chez "orange.fr";
Séquence 2
tla liste des lots fabriqués avant le 23 mars 2010 et qui ont été livrés entre le
Le langage 24 et le 26 mars ;
d'interrogation
tla liste des articles du rayon n° 12 dont le packaging ou l’unité de mesure n’a
des données (LID)
pas été renseigné ;
Page 36 tla liste des articles dont le packaging est "Par 3", "Par 6" ou "Par 12".

4. Les calculs

Les calculs simples


Le SQL nous permet d’appliquer les opérateurs d’addition, de soustraction, de multipli-
cation et de division à des données de type numérique.
tPar exemple, on veut faire une livraison et, pour cela, on a besoin de la liste des
articles mais on souhaite que le prix soit affiché avec un supplément de 1 € par
article :

8 2943 TG PA 00
Ce qui nous donne, en SQL :
SELECT idArticle, libelle, prix + 1
FROM article

Depuis quelques pages, nous savons utiliser les "alias" de colonnes. Prenons l’habitude
de les utiliser dès que l’occasion se présente. Ici, par exemple, c’est une bonne occasion
en effet, dès lors que l’on utilise une opération, il faudra utiliser un alias de colonnes :

Ce qui nous donne, en SQL :


SELECT idArticle, libelle,
prix + 1 AS "Prix livré"
FROM article
tAutre exemple : finalement, on souhaite que le prix livré représente le prix des
articles augmenté de 20 % :

Séquence 2

Le langage
d'interrogation
Ce qui nous donne, en SQL : des données (LID)
SELECT idArticle, libelle, prix * 1.20 AS "Prix livré"
FROM article Page 37
Les priorités opératoires sont respectées dans les instructions SQL permettant ainsi de
limiter l’usage des parenthèses. Bien sûr, comme en mathématiques, on peut tout de
même combiner les opérations à l’aide des parenthèses :

Ce qui nous donne, en SQL :


SELECT idArticle, libelle,
prix * (1 + 1 / 20) AS "Prix livré"
FROM article

Avec uniquement les calculs simples, les capacités de SQL sont vite limitées. C’est pour-
quoi des fonctions permettant à SQL d’effectuer des opérations complexes ont été
créées.

8 2943 TG PA 00
La fonction "COUNT"
La fonction "COUNT" vous permet d’obtenir le nombre de lignes que comporte la table
résultante de votre requête.
tPar exemple, on veut obtenir le nombre d’articles présents dans notre base.
Graphiquement nous allons à présent utiliser la colonne "Aggregate" qui va nous
permettre d’utiliser les fonctions SQL :

Ce qui nous donne, en SQL :


SELECT COUNT(*) AS "Nombre d’articles"
FROM article
tUn autre exemple : on veut obtenir le nombre d’articles dont le prix est inférieur
à 1€ :

Ce qui nous donne, en SQL :


Séquence 2
SELECT COUNT(*) AS "Nombre d’articles à – d’1 euro"
Le langage FROM article
d'interrogation
des données (LID) WHERE prix < 1

Page 38
tOn souhaite obtenir le nombre de nos fournisseurs qui possèdent un email :

Ce qui nous donne, en SQL :


SELECT COUNT(*) AS "Nombre de fournisseurs avec email"
FROM fournisseur
WHERE email IS NOT NULL
En précisant un nom de colonne à la fonction COUNT, cela permet de ne prendre en
compte que les lignes où cette colonne contient une valeur (non nulle). La requête sui-
vante produit donc exactement le même résultat que la précédente :

Ce qui nous donne, en SQL :

SELECT COUNT(email)
AS "Nb de fournisseurs avec email"
FROM fournisseur

8 2943 TG PA 00
tOn souhaite obtenir le nombre de fournisseurs qui nous ont déjà livrés. Il faut, pour
cela, choisir la fonction "COUNT DISTINCT":

Ce qui nous donne, en SQL :

SELECT COUNT(DISTINCT idFournisseur)AS "Nb fourn."


FROM lot

Attention, si on oublie le DISTINCT, on obtiendra le nombre de lots que l’on nous a


livrés, ce qui est complètement différent…

Les fonctions "MAX" et "MIN"


Les fonctions "MAX" et "MIN" retournent respectivement la valeur maximale et la
valeur minimale qui se trouvent dans la colonne passée à la fonction.
tPar exemple, on veut obtenir la distance du fournisseur qui est le plus loin :

Séquence 2

Le langage
Ce qui nous donne, en SQL : d'interrogation
des données (LID)
SELECT MAX(distanceKm) AS "Distance max fourn."
FROM fournisseur Page 39
tMaintenant, on veut obtenir le prix de l’article le moins cher du rayon n° 1 :

Ce qui nous donne, en SQL :


SELECT MIN(prix) AS "Prix mini des art. du rayon n°1"
FROM article
WHERE idRayon = 1

8 2943 TG PA 00
Les fonctions "SUM" et "AVG"
Les fonctions "SUM" et "AVG" retournent respectivement la somme et la moyenne de
la colonne passée à la fonction.
tPar exemple, on veut obtenir le chiffre d’affaires réalisé le 1er avril 2010 :

Ce qui nous donne, en SQL :


SELECT SUM(montantTotal) AS "CA le 01/04/2010"
FROM achat
WHERE dateAchat = '2010/04/01'
tMaintenant, on veut obtenir le prix moyen d'un article du rayon n° 2 :

t Maintenant on veut obtenir le prix moyen d'un article du rayon n°2 :

Ce qui nous donne, en SQL :


SELECT AVG(prix) AS "Moyenne des art. du rayon n°2"
Séquence 2
FROM article
Le langage WHERE idRayon = 2
d'interrogation
des données (LID)
Chaque SGBDR dispose d’un large panel de fonctions qui n’est pas forcément com-
patible avec les autres SGBDR. Par exemple, dans PostgreSQL, pour extraire l’année
Page 40
d’une date, on utilise la fonction issue de la norme SQL:2003 EXTRACT(year from
champDate). Cette fonction est supportée par MySQL qui a également sa propre fonc-
tion YEAR(champDate) qui, elle, n’est pas supportée par PostgreSQL. Mais la fonction
NOW() (non présente dans les différentes révisions de SQL), permet d’afficher la date
et l’heure courante, existe sur quasiment tous les SGBDR.

Exercice 3
Réaliser les requêtes permettant d’obtenir les informations ci-dessous. Comme
pour les exercices précédents, essayez, dans la mesure du possible, de réaliser ces
requêtes directement en SQL. Si vous n’y arrivez pas, essayez ensuite en graphique :
tla liste des articles ("idArticle", "libelle", "prix" que l’on renomme en "prix
en €") avec en plus les prix en livres sterling (on prend comme taux de change :
1 £ = 1,21 €) ;
tle nombre de marques référencées dans notre base de données ;
tle chiffre d’affaires pour le mois d’avril 2010 ;
tla date de la dernière livraison reçue ;
tla distance moyenne des fournisseurs du Var (département 83) ;
tle prix HT (taux de TVA de 19,6 %) de l’article le plus cher ;
tle prix moyen au kilo des articles dont l’unité de mesure est le gramme.

8 2943 TG PA 00
5. Les jointures
La jointure est le mécanisme le plus puissant du langage SQL. Elle permet de combiner
les données de plusieurs tables en les liant logiquement suivant les relations qui existent
entre elles (clés primaires et / ou étrangères).
Comme nous l’avons vu dans la séquence 1, le SQL repose sur le concept mathématique
d’algèbre relationnelle reposant lui-même sur la théorie des ensembles.
Il faut savoir que la base de la jointure est le "produit cartésien". Pour faire simple, le
résultat d’un produit cartésien entre 2 tables est l’ensemble formé par tous les couples
possibles entre ces 2 tables. Ce qui veut dire que si, dans la première table, il y a 5 enre-
gistrements et, dans la seconde 2, on obtiendra une table résultante de 10 enregistre-
ments :

Séquence 2

Le langage
d'interrogation
des données (LID)

Page 41
Cette jointure, également appelée "jointure croisée", est effectuée à chaque fois que
l’on indique plusieurs tables dans l’instruction "FROM" sans indiquer de condition dans
le "WHERE".
tPar exemple, on veut obtenir la liste des articles et des rayons :

Ce qui nous donne, en SQL :


SELECT a.libelle AS "Article", r.libelle AS "Rayon"
FROM article AS a, rayon AS r

Résultat :
Article Rayon
Camembert Apéritifs
Merguez Apéritifs
… …
Camembert Boissons
Merguez Boissons
… …

8 2943 TG PA 00
Dans notre cas, le résultat comporte de nombreuses incohérences car le modèle qui nous
a permis de créer la base de données possède la règle de gestion suivante : "Un article
est placé dans un et un seul rayon" (cardinalité 1,1 dans notre schéma conceptuel des
données ou multiplicité 1 dans notre diagramme de classes UML ).
Dans la majeure partie des cas, pour obtenir un résultat cohérent, il faudra spécifier
une condition de jointure. Dans une base de données créée à l’aide d’un modèle rela-
tionnel la condition de jointure sera tout simplement la représentation du respect des
règles de gestion : "La clé étrangère k de la table t fait référence à la clé primaire p de
la table x".

La jointure "classique"
La jointure "classique" est une jointure basée sur l’équivalence entre 2 champs. Elle
opère en associant l’enregistrement d’une première table à l’enregistrement d’une
seconde table, uniquement si la valeur d’un champ de la première table est égale à la
valeur du champ correspondant de la seconde table.

Séquence 2

Le langage
d'interrogation
des données (LID)

Page 42

Reprenons l’exemple précédent : on souhaite obtenir la liste des articles et des rayons. Ce
qui veut dire que si on veut obtenir la liste des articles avec le rayon où ils sont placés, il
faut que l’on associe un article à un rayon.

8 2943 TG PA 00
D’après notre schéma relationnel, on dispose de la clé étrangère "idRayon" de la table
article qui fait référence à la clé primaire "idRayon" de la table "rayon", ce qui signifie
rappelons-le, qu’un article est placé dans un et un seul rayon (conséquence de la cardi-
nalité 1,1 de notre schéma conceptuel des données).
Tout ce qui nous reste à faire, c’est donc de préciser au moteur d’interprétation SQL
qu’au lieu de faire un produit cartésien, on ne veut associer que les enregistrements de
la table article et de la table rayon où la valeur de la clé étrangère "idrayon" de "article"
correspond à la valeur de la clé primaire de la table "rayon".
tVous allez donc rajouter "WHERE a.idRayon = r.idRayon" à la requête précédente
pour donner la requête suivante :
SELECT a.libelle AS "Article", r.libelle AS "Rayon"
FROM article AS a, rayon AS r
WHERE a.idRayon = r.idRayon
Résultat :
Article Rayon
Galettes au millet et champignons Apéritifs
Galettes au riz complet Apéritifs
Pochon de légumes bio préparés Apéritifs
Rillettes de truite bio Apéritifs
Chips salées Boissons
Pur jus de citron bio Boissons Séquence 2

Eau minérale aromatisée à la fraise Boissons


Le langage
… … d'interrogation
des données (LID)

Attention, dans notre exemple, la clé primaire et la clé étrangère portent le même nom Page 43
mais ce n’est absolument pas obligatoire !
Si la clé étrangère idRayon de la table article se nommait en réalité "placementRayon",
on aurait la requête suivante, qui fonctionnerait exactement de la même façon et qui
fournirait exactement le même résultat :

SELECT a.libelle AS "Article", r.libelle AS "Rayon"


FROM article AS a, rayon AS r
WHERE placementRayon = idRayon

La jointure avec "JOIN"


Depuis la norme SQL-92, la jointure "classique" est devenue obsolète par la mise à dis-
position de l’opérateur relationnel "JOIN".
La jointure "classique" comportait de trop nombreux inconvénients avec, en particulier,
une consommation extrême de ressources systèmes à chaque "produit cartésien". Et
d’un point de vue strictement logique, le fait de rassembler toutes les données pour
ensuite n’en prendre en compte qu’une infime partie, laissait un peu à désirer…

8 2943 TG PA 00
Nous allons également voir que la relecture d’une requête avec JOIN apparaît beaucoup
plus simple à nos yeux d’humains.
Pour cela, vous allez cliquer sur le champ "idrayon" de la table "article" et, tout en res-
tant "appuyé", vous allez venir sur le champ "idrayon" de la table "rayon". Cela va avoir
pour effet d’associer les deux champs et de faire apparaître un lien entre les deux tables :

Séquence 2

Le langage
d'interrogation
des données (LID)

Page 44
tAvec l’opérateur “JOIN”, la requête va donc pouvoir s’écrire ainsi :
SELECT a.libelle AS "Article", r.libelle AS "Rayon"
FROM article AS a INNER JOIN rayon AS r
ON a.idRayon = r.idRayon

La clause "INNER" est facultative et est utilisée par défaut dès lors que l’on utilise l’opé-
rateur "JOIN". L’explication est que cette clause permet d’indiquer au moteur d’interpré-
tation SQL que la jointure est de type "interne", qui est le comportement par défaut de
l’opérateur "JOIN".
Pour plus de facilité, nous continuerons d’écrire "JOIN" sans "INNER" même si FlySpeed
SQL Query vous la propose à chaque fois.
Pour bien vous en convaincre, supprimez la clause "INNER" dans la zone SQL et réexé-
cutez-la.

Dans notre base de données, la clé étrangère idrayon de la table "article" fait référence
à la clé primaire idrayon. Ce cas, très fréquent, où l’on souhaite faire une jointure à
l’aide de champs portant le même nom, rend la manœuvre encore plus simple. Il suffit
de donner le nom du champ "commun":
SELECT a.libelle AS "Article", r.libelle AS "Rayon"
FROM article AS a JOIN rayon AS r USING (idRayon)

8 2943 TG PA 00
Dans FlySpeed SQL Query, cette requête va provoquer une erreur car le logiciel ne connaît
pas la clause "USING". La requête va toutefois bien fonctionner car PostgreSQL connaît
la clause "USING" et sait l’utiliser. Il y aura d’ailleurs le même type d’erreur pour la
requête ci-après…

On peut même faire encore plus simple en utilisant une jointure "naturelle", c’est-à-dire
que l’on va laisser le moteur d’exécution SQL joindre les champs ayant les mêmes noms.
tOn souhaite, par exemple, afficher le libellé d’article avec la marque associée :
SELECT libelle AS "Article", nom AS "Marque"
FROM article NATURAL JOIN marque

Attention, la jointure "naturelle" est un cas particulier de jointure. Lors d’une jointure
"naturelle", le moteur d’exécution SQL effectue automatiquement la comparaison des
champs ayant le même nom.
C’est pourquoi elle ne fonctionnerait pas dans le cas "article/rayon" car les tables portent
un champ de même nom (libelle), et ça ne fonctionnerait pas non plus dans le cas
"article/listeCourses" (à cause de "quantite"). Cet homonyme va contraindre le moteur
d’exécution à joindre les deux champs :
s soit les contenus sont différents, et aucun résultat n’est retourné ;
s soit il y a des contenus identiques, et le résultat retourné ne correspond pas à ce
que l’on voulait.
L’analyse à réaliser avant de pouvoir utiliser la jointure naturelle fait que ce type de
Séquence 2
jointure est très peu utilisé. Certains vont même, à juste titre, jusqu’à déconseiller son
usage car si l’analyse avant utilisation est mal faite, le risque d’erreur est important. Le langage
Je vous la donne tout de même, car le but, ici, et de vous faire connaître tout le SQL, ce d'interrogation
qui inclut également, selon moi, les instructions dites "dangereuses". des données (LID)

L’utilisation de "JOIN" telle qu’on vient de le voir, supprime toutes les lignes qui ne sont Page 45
pas équivalentes dans les deux tables utilisées. Nous allons maintenant voir comment
faire pour conserver ou non les lignes sans lignes équivalentes en distinguant les tables
qui se situent à gauche de "JOIN" des tables qui se situent à droite.

La jointure "GAUCHE" avec "LEFT JOIN"


La jointure "gauche" s’effectue avec "LEFT" et conserve les lignes sans lignes équiva-
lentes dans la table de gauche, mais supprime les lignes sans lignes équivalentes dans la
table de droite.

tOn souhaite, par exemple, afficher la liste des fournisseurs ainsi que la liste de leurs
livraisons. On va donc conserver toutes les lignes de la table de gauche. Pour cela,
cliquez avec le bouton droit sur le lien entre fournisseur et lot (que vous aurez créé
au préalable) et choisissez "Select all rows from fournisseur":

8 2943 TG PA 00
Visuellement, cela va modifier le lien :

Séquence 2

Le langage
d'interrogation Et, dans la zone SQL, on peut constater que la clause “LEFT” est venue se position-
des données (LID) ner avant le “JOIN":
SELECT raisonSociale, idLot, idArticle
Page 46
FROM fournisseur LEFT JOIN lot ON
(fournisseur.idFournisseur = lot.idFournisseur)

Contrairement à une jointure "équivalente", cette jointure "gauche" nous permet


d’avoir également la liste des fournisseurs qui n’ont pas effectué de livraisons (valeurs
nulles dans idLot et idArticle) :

8 2943 TG PA 00
La jointure "DROITE" avec "RIGHT JOIN"
La jointure "droite" s’effectue avec "RIGHT" et conserve les lignes sans lignes équiva-
lentes dans la table de droite, mais supprime les lignes sans lignes équivalentes dans la
table de gauche.

tOn souhaite à présent afficher la liste des marques ainsi que les articles correspon-
dants en magasin. On va donc procéder de la même manière que pour la jointure
gauche sauf que l’on va sélectionner tous les champs de la table de droite (ici,
"marque") en choisissant l’option "Select all rows from marque":

Séquence 2

Le langage
d'interrogation
des données (LID)

Page 47

Visuellement, cela va modifier le lien :

Dans la zone SQL, on peut voir que la clause "RIGHT" est venue se placer avant
l’opérateur “JOIN” afin de réaliser une jointure "droite" :
SELECT nom, libelle
FROM article RIGHT JOIN marque ON
(article.idMarque = marque.idMarque)

8 2943 TG PA 00
Cette jointure "droite" nous permet d’avoir la liste des marques qui n’ont aucune corres-
pondance dans la table "article" en conservant lors de la jointure, les lignes de marque
(table de droite) qui n’ont pas de lignes équivalentes dans la table "article".
tEn utilisant l’instruction "NATURAL", on peut également écrire notre requête de
cette manière :
SELECT nom, libelle
FROM article NATURAL RIGHT JOIN marque

Une jointure "naturelle" peut également être droite ("NATURAL RIGHT JOIN") ou
gauche ("NATURAL LEFT JOIN").

Exercice 4
Réaliser les requêtes permettant d’obtenir les informations ci-dessous. Comme pour
les exercices précédents, essayez dans la mesure du possible, de réaliser ces requêtes
directement en SQL. Si vous n’y arrivez pas, essayez ensuite en graphique :
tla liste des articles (références et libellés) qui ont été achetés ;
tla liste des articles (références et libellés) qui ont été achetés avec la date à
laquelle ils ont été achetés ;
Séquence 2 tla liste des articles (références, libellés et prix) avec le nom de la marque de l’ar-
ticle (renommé en "Marque") et le libellé du rayon d’appartenance (renommé
Le langage en "Rayon") ;
d'interrogation
des données (LID) tla liste des articles (Références, libellés et prix), qui ont été achetés, avec le nom
de la marque de l’article et le libellé du rayon d’appartenance ainsi que la date
Page 48 à laquelle ils ont été achetés ;
treprenez la requête précédente et utilisez des alias de champs pour chaque
champ utilisé :
– idArticle Î "Référence"; – nom Î "Marque";
– libelle Î "Produit"; – libelle Î "Rayon";
– prix Î "P.U"; – dateAchat Î "Date".
tla liste des fournisseurs qui n’ont pas encore effectué de livraison ;
tla liste des rayons qui n’ont aucun article attribué.

8 2943 TG PA 00
6. Les tris
SQL nous offre la possibilité de trier les résultats d’une requête grâce à l’instruction
"ORDER BY". Par défaut, l’instruction SELECT nous retourne les enregistrements dans
l’ordre dans lequel ils apparaîssent dans la table.
" ORDER BY " nous permet d’organiser les enregistrements en s’appuyant sur n’importe
quel type de champ :
s Ordre alphabétique : si le champ est basé sur des chaînes de caractères ;
s Ordre chronologique : si le champ est basé sur des dates ;
s Ordre incrémental : si le champ est basé sur des nombres ;
s Ordre de vérité : si le champ est basé sur des valeurs booléennes.

Par exemple, on souhaite obtenir la liste des fournisseurs triés par ordre alphabétique.
tCela signifie que l’on souhaite tous les champs et tous les enregistrements de la
table "fournisseur", mais cela veut également dire que l’on souhaite effectuer un
tri "croissant" sur le champ raisonSociale. On va donc se servir des colonnes "Sort
Type" (Type de tri) et "Sort Order" (Priorité de tri). Dans la colonne "Sort Type",
choisissez "Ascending" (croissant) :

Séquence 2
La priorité de tri se positionne automatiquement à 1. Nous verrons plus loin à quoi
cela correspond. Le langage
d'interrogation
Dans la zone SQL, on peut voir que l’instruction “ORDER BY” est venue s’ajouter, des données (LID)
accompagnée du champ sur lequel porte le tri “raisonSociale":
SELECT * Page 49
FROM fournisseur
ORDER BY raisonSociale

Le tri par ordre croissant se fait grâce à la clause "ASC" qui est normalement positionnée
après le champ à trier. Le type de tri par défaut, activé par l’instruction "ORDER BY", est
"ASC", ce qui fait que cette clause est facultative. C’est pourquoi FlySpeed SQL Query ne
vous le propose pas. Modifiez la requête précédente en ajoutant "ASC" et réexécutez-la :
SELECT *
FROM fournisseur
ORDER BY raisonSociale ASC

" ASC " permet de préciser que l’on souhaite effectuer un tri "croissant":
s si c’est un champ de type "chaînes de caractères", l’affichage se fera de "A" à "Z";
s si c’est un champ de type "date", l’affichage commencera par les dates les plus
anciennes pour se terminer avec les plus récentes ;
s si c’est un champ de type "numérique", l’affichage commencera par les nombres
les plus "petits" (−'), pour se terminer avec les plus grands (+') ;
s si c’est un champ de type "booléen", l’affichage commencera par les valeurs
"fausses" (false en anglais) pour se terminer par les valeurs "vraies" (true).

On souhaite à présent obtenir la liste des lots, mais on souhaite également que l’affi-
chage commence par les livraisons les plus récentes.

8 2943 TG PA 00
tCela signifie que l’on souhaite effectuer un tri "décroissant" (date les plus récentes
en premier) :

Dans la zone SQL, on peut voir que la clause "DESC" a été ajoutée après le champ
à trier :
SELECT *
FROM lot
ORDER BY dateLivraison DESC

" DESC " nous permet de préciser que l’on souhaite effectuer un tri "décroissant", ce qui
revient à faire l’inverse de "ASC".

Il est possible d’effectuer plusieurs tris consécutifs.


tPar exemple, on souhaite afficher les articles triés par rayon par ordre croissant
(idRayon), mais également triés par prix, les moins chers en premier :
Séquence 2

Le langage
d'interrogation
des données (LID)

Page 50 Dans la zone SQL, on peut voir que le tri porte d’abord sur "idRayon" (Sort Order = 1)
et ensuite sur "prix" (Sort Order = 2) :
SELECT *
FROM article
ORDER BY idRayon, prix

L’ordre de tri sera bien entendu croissant ("ASC"), rappelons-le puisque c’est l’action
par défaut de l’instruction "ORDER BY". La requête précédente peut donc s’écrire de la
manière suivante :
SELECT *
FROM article
ORDER BY idRayon ASC, prix ASC

Enfin, il est possible de combiner les deux ordres de tri.


tPar exemple, on souhaite obtenir la liste des fournisseurs en commençant par les
plus éloignés (distancekm) et en triant les noms par ordre alphabétique (sans ce tri,
"Surgel’2000" est placé avant "Livre boite") :

8 2943 TG PA 00
Dans la zone SQL, on peut voir que le tri porte d’abord sur "distanceKm" et que
ce champ sera trié dans l’ordre décroissant ("DESC") et ensuite que le tri porte sur
"prix" et que ce champ sera trié par ordre croissant (par défaut) :
SELECT *
FROM fournisseur
ORDER BY distanceKm DESC, raisonSociale

Exercice 5
Réaliser les requêtes permettant d’obtenir les informations ci-dessous. Comme pour
les exercices précédents, essayez dans la mesure du possible de réaliser ces requêtes
directement en SQL. Si vous n’y arrivez pas, essayez ensuite en graphique :
tla liste des marques par ordre alphabétique ;
tla liste des articles en affichant les articles "bio" en premier ;
tla liste des marques avec les articles correspondants. Les noms de marques
doivent être triés par ordre alphabétique inverse et les libellés d’articles par
ordre alphabétique ;
Séquence 2
tla liste des lots avec le nom des fournisseurs et le libellé des articles en com-
mençant par la livraison la plus ancienne. Les articles seront triés par ordre Le langage
alphabétique. d'interrogation
des données (LID)

Page 51

7. Les requêtes imbriquées


Il arrive parfois que l’on souhaite obtenir des informations pour lesquelles nous avons
besoin au préalable d’autres informations.

Sous-requête renvoyant une seule valeur


tPar exemple, nous sommes capables d’afficher le prix moyen d’un article "bio":
SELECT AVG(prix) AS "Prix moyen d’un article bio"
FROM article
WHERE bio = TRUE
tNous sommes également capables d’afficher les articles "bio" inférieurs ou égaux
à un certain prix ( x ) :
SELECT *
FROM article
WHERE bio = TRUE
AND prix <= x
tMais si on souhaite obtenir la liste des articles "bio" dont le prix est inférieur ou
égal au prix moyen d’un article "bio", on va avoir besoin de mettre en œuvre une
imbrication de requêtes :

8 2943 TG PA 00
– Pour cela, il faut commencer par faire la requête qui va nous permettre d’affi-
cher tous les articles "bio" sans restriction de prix :

– Nous allons ensuite appliquer une restriction sur le prix, mais, au lieu de
rajouter une condition, nous allons cliquer avec le bouton droit dans la cellule
"Criteria", choisir "Insert Sub-Query" (Insérer une sous-requête) et valider
avec la touche "Entrée":

Séquence 2

Le langage
d'interrogation
des données (LID)
– Par défaut, c’est le prédicat "IN" suivi de la sous-requête qui est proposé. Nous
allons donc remplacer "IN" par "<=" et ensuite appuyer sur le bouton aux
Page 52
3 points pour modifier la sous-requête. Après avoir appuyé, on peut remar-
quer que l’on est passé sur un nouvel onglet :

– La sous-requête est avant tout une requête, il faut donc agir comme pour une
requête "standard". Ici, on souhaite que cette requête retourne le prix moyen
des articles "bio":

– Dans la zone SQL, on peut voir que l’on a bien une première requête qui
retourne toutes les informations ("SELECT *") concernant les articles ("FROM
article") "bio" ("WHERE bio = TRUE") dont le prix est inférieur ou égal ("AND
prix <= ") au prix moyen ("SELECT AVG(prix)") d’un article ("FROM article")
"bio" ("WHERE bio = TRUE") :

8 2943 TG PA 00
SELECT *
FROM article
WHERE bio = TRUE
AND prix <= ( SELECT AVG(prix)11
FROM article
WHERE bio = TRUE )
11

Sous-requête renvoyant une liste de valeurs


Nous avons pu utiliser un opérateur de comparaison car notre sous-requête ne renvoyait
qu’une seule valeur. Dans le cas où nous avons à utiliser une sous-requête renvoyant
plusieurs lignes, il faut utiliser des prédicats de listes.
tNous souhaitons maintenant obtenir la liste des articles qui sont dans les mêmes
rayons que "Maïs tendre" et "Café moulu":
– Nous allons donc commencer par afficher toutes les informations des articles :

– Ensuite, comme pour la requête précédente, nous allons ajouter une restric-
tion (champ "Criteria") sous la forme d’une sous-requête portant ici sur le
champ "idRayon":
Séquence 2

Le langage
d'interrogation
des données (LID)

Page 53

– Nous allons garder le prédicat "IN" et cliquer directement sur le bouton aux
3 points pour modifier la sous-requête :

– Nous souhaitons que cette nouvelle requête (la sous-requête de la principale)


retourne les identificateurs de rayons ("idRayon") des articles "Maïs tendre"
et "Café moulu":

Attention, ici, c’est bien un "OR" qu’il faut utiliser car si on utilisait un "AND", cela
signifierait que l’on veut l’article dont le libellé est à la fois "Maïs tendre" et "Café
moulu", ce qui n’est pas possible puisqu’un article ne possède qu’un libellé.

11. Bien que nous ayons pris l'habitude de renommer tous les calculs, ici, ce n'est pas nécessaire :
l'intitulé n'est pas utile à la réquête principale et n'apparaît pas dans le résultat final.

8 2943 TG PA 00
– Pour éviter une erreur liée à la difficulté "AND"/"OR", nous allons plutôt
effectuer la restriction avec le prédicat "IN":

– Si notre requête s’arrête là, nous aurons également dans le résultat les don-
nées qui nous ont servi dans notre sous-requête :

– Il faut donc les éliminer en ajoutant à notre requête principale une restriction
sur le champ "libelle" (d’article ici) qui indique que l’on ne veut ni l’article
"Maïs tendre", ni l’article "Café moulu" ("NOT IN ('Maïs tendre', 'Café
Séquence 2
moulu')") :

Le langage
d'interrogation
des données (LID)

Page 54
– Dans la zone SQL, on peut voir que l’on a bien une première requête qui
retourne toutes les informations ("SELECT *") concernant les articles ("FROM
article") dont l’identificateur de rayon (c’est-à-dire le rayon où se trouve
l’article) se trouve dans la liste ("WHERE idRayon IN") des identificateurs de
rayons ("SELECT idRayon") des articles ("FROM article") dont le libellé est
lui-même dans la liste ("WHERE libelle IN") suivante : "Maïs tendre" ; "Café
moulu". On souhaite toutefois ne conserver que les articles dont le libellé
n’est pas ("AND libelle NOT IN") dans la liste suivante : "Maïs tendre" ; "Café
moulu".
SELECT *
FROM article
WHERE idRayon IN ( SELECT idRayon
FROM article
WHERE libelle IN ('Maïs tendre',
'Café moulu')
)
AND libelle NOT IN ('Maïs tendre', 'Café moulu')

8 2943 TG PA 00
Expressions de sous-requêtes
On a vu "IN" qui, de par son rôle de prédicat de liste, est lui aussi une expression de sous-
requêtes. Mais il faut savoir qu’il y a également : "ANY 12" (que l’on retrouve également
sous le nom de "SOME 13"), "ALL 14" et "EXISTS" que l’on peut combiner à un prédicat de
comparaison pour évaluer le contenu d’une sous-requête.
"ANY/SOME": est vrai si au moins une des lignes retournées par la sous-requête vérifie
la condition exprimée par le prédicat de comparaison.
tPar exemple, si on cherche les marques qui ont au moins un article en magasin :
SELECT *
FROM marque
WHERE idMarque = ANY ( SELECT idMarque FROM article )

"ALL": Est vrai si toutes les lignes retournées par la sous-requête vérifient la condition
exprimée par le prédicat de comparaison.
tPar exemple, si on cherche les articles qui sont moins chers ou au même prix que
tous les articles déjà vendus :
SELECT *
FROM article
WHERE prix <= ALL ( SELECT prix
FROM article JOIN listeCourses
USING (idArticle)
) Séquence 2

"EXISTS": est vrai s’il existe au moins une ligne retournée par la sous-requête qui vérifie Le langage
d'interrogation
la condition exprimée dans la sous-requête. L’utilisation de "EXISTS" n’a de sens que si la des données (LID)
requête principale et la sous-requête sont liées par un champ.
tPar exemple, si on veut obtenir la liste des rayons qui n’ont aucun article : Page 55

SELECT *
FROM rayon AS r
WHERE NOT EXISTS ( SELECT *
FROM article AS a
WHERE r.idRayon = a.idArticle
)

On retrouve ici la structure de la jointure "classique" que l’on n’utilise plus, et, dans les
exemples précédents, vous avez dû vous rendre compte que vous étiez capable de proposer
une requête sans utiliser "ANY", "ALL" ou "EXISTS" avec une sous-requête munie d’une
fonction de calcul. Bien que peu utilisés, ils le restent toujours, c’est pourquoi il fallait
que vous l’ayez vu au moins une fois pour être capable de comprendre leur utilisation si
un jour vous y étiez confronté.

12. ANY signifie "n’importe lequel" en anglais.


13. SOME signifie "quelques-uns" en anglais.
14. ALL signifie "tous" en anglais.

8 2943 TG PA 00
Exercice 6
Réaliser les requêtes permettant d’obtenir les informations ci-dessous. Comme
pour les exercices précédents, essayez, dans la mesure du possible, de réaliser ces
requêtes directement en SQL. Si vous n’y arrivez pas, essayez ensuite en graphique :
tle ou les articles les moins chers ;
tla liste des lots qui ont été livrés le même jour que le lot "L593078838";
tla liste des rayons qui ont été approvisionnés à la dernière livraison ;
tla liste des rayons qui ont été approvisionnés à l’avant-dernière livraison.

8. Les regroupements
Le regroupement est une opération qui nous permet de spécifier un ou plusieurs champs
qui déterminent l’appartenance à un groupe. En SQL, c’est l’instruction "GROUP BY" qui
effectue des regroupements de toutes les lignes dont la valeur du champ de groupe est
identique.
tPar exemple, nous souhaitons obtenir le nombre d’articles par rayon d’apparte-
nance (pour l’instant, il faut décocher la case "Grouping") :
Séquence 2

Le langage
d'interrogation 15
des données (LID)

En SQL, sans regroupement Résultat


Page 56
(attention, cette requête provoque une erreur 15) : (théorique) :

SELECT idRayon, COUNT(*) AS "Nb art." idRayon Nb art.


FROM article
5 1
5 1
5 1
4 1
14 1
14 1
… …

tNous allons maintenant cocher la case "Grouping" pour effectuer un regroupement


"par idRayon":

15. La présence d'une fonction ne permet pas au moteur d'exécution SQL de réaliser la requête
sans GROUP BY

8 2943 TG PA 00
Avec regroupement : Résultat :

SELECT idRayon, COUNT(*) AS "Nb art." idRayon Nb art.


FROM article 5 3
GROUP BY idRayon 4 1
14 2
… …

Dès lors que l’on souhaite afficher plusieurs champs dont un est composé d’une fonction
de calcul, il faut obligatoirement effectuer un regroupement en nommant clairement le
ou les champs sur lesquels on souhaite opérer ce regroupement.

tNous souhaitons maintenant obtenir le nombre d’articles par rayon d’appartenance


avec la référence et le libellé du rayon :

Ce qui nous donne, en SQL :


SELECT article.idRayon, rayon.libelle, Séquence 2
COUNT(*) AS "Nb art."
FROM article JOIN rayon ON Le langage
d'interrogation
(article.idRayon = rayon.idRayon) des données (LID)
GROUP BY article.idRayon, rayon.libelle
Page 57
Profitons de cette requête pour faire quelques révisions :
s Les champs sont préfixés car il existe un champ "idRayon" dans les 2 tables
présentes dans le "FROM". Le moteur d’exécution a donc besoin de savoir avec
précision quels sont les champs à utiliser. Même chose pour le champ "libelle"
dont le nom existe dans les 2 tables.
s On aurait pu écrire la jointure de cette façon : "article JOIN rayon USING
(idRayon)".
s Nous n’aurions pas pu utiliser la jointure naturelle (à cause du champ "libelle",
sur lequel la jointure aurait également porté…).
s La présence d’une fonction dans le "SELECT" contraint à faire un regroupement
sur tous les autres champs à l’aide d’un "GROUP BY" (regroupement qui ne serait
pas obligatoire s’il n’y avait que le résultat de la fonction à retourner).

8 2943 TG PA 00
Exercice 7
Réaliser les requêtes permettant d’obtenir les informations ci-dessous. Comme
pour les exercices précédents, essayez, dans la mesure du possible, de réaliser ces
requêtes directement en SQL. Si vous n’y arrivez pas, essayez ensuite en graphique :
tLe nombre d’articles par achat ;
tLe nombre d’articles par rayon ;
tLe nombre de lots livrés par fournisseur ;
tLa liste des articles avec le nombre de fois où ils ont été achetés en affichant les
plus "populaires" en premier ;
tLe prix moyen au kilo des articles par rayon.

9. Les conditions sur regroupements


Nous allons maintenant voir que, grâce à l’instruction "HAVING", nous pouvons appli-
quer une restriction sur les groupes que nous venons de créer avec l’instruction "GROUP
BY".

Tout comme l’instruction "WHERE" restreint le résultat d’une requête en incluant ou


Séquence 2 en excluant des lignes, l’instruction "HAVING" inclut ou exclut des groupes. "HAVING"
ne peut donc pas être utilisé sans "GROUP BY".
Le langage
d'interrogation tNous souhaitons restreindre notre précédente requête en ne gardant que les rayons
des données (LID) où il y a moins de 4 articles. Il nous suffit d’appliquer une restriction (colonne
"Criteria") sur le champ "COUNT(*)":
Page 58

En SQL, on retrouve la restriction après l’instruction “HAVING":


SELECT article.idRayon, rayon.libelle,
COUNT(*) AS "Nb art."
FROM article JOIN rayon ON
(article.idRayon = rayon.idRayon)
GROUP BY idRayon, rayon.libelle
HAVING COUNT(*) < 4

Attention, il faut veiller à bien distinguer une restriction sur un champ existant dans la
base de données et une restriction sur un champ "créé" localement par la requête (ce qui
est le cas pour les fonctions, comme ici avec "COUNT(*)").

8 2943 TG PA 00
Exercice 8
Réaliser les requêtes permettant d’obtenir les informations suivantes :
tle nombre d’articles par achat avec uniquement les achats concernant moins de
5 articles ;
tle nombre d’articles par rayon avec uniquement les rayons avec 4 articles ;
tle nombre de lots livrés par fournisseur en ne gardant que les fournisseurs qui
ont livré au moins 10 lots ;
tla liste des articles avec le nombre de fois où ils ont été achetés en affichant
les plus "populaires" en premier et en ne conservant que les articles achetés
entre 2 et 5 fois.

10. La soustraction
Cette opération nous permet de comparer 2 tables et de ne retourner que les lignes qui
apparaîssent dans la première table mais pas dans la seconde.

Séquence 2

Le langage
d'interrogation
des données (LID)

Page 59
tOn souhaite obtenir la liste des articles qui n’ont jamais figuré sur une liste de
courses, on peut utiliser "NOT IN" de cette manière :

Ce qui nous donne, en SQL :16

SELECT idArticle
FROM article
WHERE idArticle NOT IN ( SELECT DISTINCT 16 idArticle
FROM listeCourses
)
tOn peut également utiliser, depuis la norme SQL-92, l’opérateur relationnel
"EXCEPT" qui nous permet très simplement d’effectuer une soustraction :
– Pour cela, nous allons commencer par créer la table de gauche, c’est-à-dire
celle qui contient les données auxquelles on souhaite retirer les données pré-
sentes dans la table de droite (voir l’illustration ci-dessus) :

16. Conformément à nos règles de gestion, un article peut être sur plusieurs listes de courses, il
faut donc utiliser DISTINCT pour supprimer les doublons et ainsi "économiser" des ressources.

8 2943 TG PA 00
– Nous allons à présent créer une deuxième requête liée à la première. Pour
cela, il faut cliquer avec le bouton droit sur l’icône "Q" (présent en haut à
droite de la zone de requête graphique) et choisir "New Union Sub-Query":

– Par défaut, le type d’opération choisi est “Union”. Cliquez sur l’icone d’en-
semble présent entre les deux “Q” et choisissez “Except” pour effectuer une
opération de soustraction :

Séquence 2

Le langage
d'interrogation – Il nous suffit à présent de créer la requête de droite, c’est-à-dire celle dont les
des données (LID)
données vont être retirées à celle de gauche :

Page 60

Dans la zone SQL, on retrouve les instructions suivantes :17

SELECT idArticle FROM article


EXCEPT
SELECT 17 idArticle FROM listeCourses

Interprété littéralement, on retrouve bien le concept de soustraction : afficher les "idAr-


ticle" ("SELECT idArticle") des "articles" (FROM "article") excepté ceux qui sont présents
("EXCEPT") parmi les "idArticle" ("SELECT idArticle") des listes de courses ("FROM
listeCourses").
tPostgreSQL limite l’utilisation de l’opérateur relationnel "EXCEPT" au même
nombre de champs (c’est-à-dire que les 2 requêtes qui font office d’opérandes
doivent retourner exactement les mêmes champs).
– Pour obtenir tous les champs de la table article, il faudra utiliser une sous-
requête :

17. Le "DISTINCT" dans la deuxième table n'est plus nécessaire car "EXCEPT" supprime automati-
quement les doublons.

8 2943 TG PA 00
En SQL, on retrouve bien notre soustraction dans la sous-requête :
SELECT *
FROM article
WHERE idArticle IN ( SELECT idArticle FROM article
EXCEPT
SELECT idArticle FROM listeCourses
) ;
tOu plus simplement, en utilisant une jointure "gauche":

Séquence 2

Le langage
d'interrogation
des données (LID)
Ce qui nous donne, en SQL :
SELECT * Page 61
FROM article LEFT JOIN listeCourses ON
(article.idArticle = listeCourses.idArticle)
WHERE listeCourses.idArticle IS NULL

Sur d’autres SGBDR, la soustraction est possible entre 2 opérandes n’ayant pas le même
nombre de champs. Il suffit pour cela d’indiquer le ou les champs "de correspondance".
Par exemple, sous Oracle, on peut utiliser la requête suivante :
SELECT * FROM article
EXCEPT CORRESPONDING BY (idArticle)
SELECT idArticle FROM listeCourses
L’instruction "CORRESPONDING BY" n’est pas supportée par PostgreSQL. Bien que
présente dans la norme SQL-92, cette instruction a été créée par Oracle qui en est donc
propriétaire. C’est donc apparemment pour des raisons politiques que PostgreSQL ne
la supporte pas.

Avec PostgreSQL, il faut donc obligatoirement que les 2 tables soient strictement iden-
tiques.

8 2943 TG PA 00
Exercice 9
Réaliser les requêtes permettant d’obtenir les informations ci-dessous. Comme
pour les exercices précédents, essayez, dans la mesure du possible, de réaliser ces
requêtes directement en SQL. Si vous n’y arrivez pas, essayez ensuite en graphique :
tla liste des marques qui n’ont aucun article en magasin ;
tla liste des fournisseurs qui n’ont pas effectué de livraisons.

11. La division
Cette opération consiste à trouver une table "résultat" telle que son produit cartésien
avec une table "diviseur" soit un sous-ensemble de la table "dividende".
Table "dividende"

Séquence 2

Le langage
d'interrogation
des données (LID)

Page 62 Table "diviseur"

Table "résultat"

Vous remarquez que seul le dernier enregistrement de la table de gauche (table "divi-
dende") est en relation avec tous les enregistrements de la table de droite (table "divi-
seur"). C’est pourquoi cette ligne est le seul résultat.

tOn souhaite avoir la liste des articles qui sont sur toutes les listes de courses. Pour
cela, on pose la table "listeCourses" en tant que table "dividende" et la table
"achat" en tant que table "diviseur":

8 2943 TG PA 00
Ce qui nous donne, en SQL :
SELECT idArticle
FROM listeCourses
GROUP BY idArticle
HAVING COUNT(*) = ( SELECT COUNT(*)
FROM achat )
tEt si on veut avoir plus d’informations concernant ces articles, il suffit de compléter
notre précédente requête :

Séquence 2

Le langage
d'interrogation
des données (LID)
Ce qui nous donne, en SQL :
Page 63
SELECT article.idArticle, libelle, prix
FROM listeCourses JOIN article ON
(listeCourse.idArticle = article.idArticle)
GROUP BY article.idArticle, libelle, prix
HAVING COUNT(*) = ( SELECT COUNT(*)
FROM achat
)

12. Les opérations entre requêtes


Au point n° 7, nous avons pu mettre en œuvre des requêtes imbriquées, que l’on peut
également appeler "sous-requêtes". Dans les différents exemples et exercices mis en
œuvre, les requêtes étaient indépendantes (sauf l’exemple avec "EXISTS"). Voyons main-
tenant comment faire pour qu’elles puissent interagir entre elles.
Nous souhaitons, par exemple, obtenir le nombre de "livraisons" effectuées par fournis-
seur. C’est-à-dire le nombre de fois où un fournisseur est venu nous livrer un ou plusieurs
lots.
tOn est capable d’afficher le nombre de lots livrés par fournisseur et par date de
livraison :

8 2943 TG PA 00
Ce qui nous donne, en SQL :
SELECT raisonSociale AS "Fournisseur",
dateLivraison AS "Date de livraison",
COUNT(*) AS "Nb lots livrés"
FROM fournisseur NATURAL JOIN lot
GROUP BY "Fournisseur","Date de livraison"

Résultat : Sous-requête
Fournisseur Date de livraison Nb lots livrés
Lavandes et parfums 2010-03-26 1
Séquence 2 Au bon blé 2010-03-23 2
Pains et gâteaux 2010-04-05 1
Le langage
d'interrogation Super boissons 2010-04-10 1
des données (LID)
Surgel'2000 2010-04-30 1
Lavandes et parfums 2010-04-05 1
Page 64
Super boissons 2010-04-06 1
Super boissons 2010-03-28 1
Super boissons 2010-03-24 3
… … …

Enregistrer cette requête et la nommer "sousReq":

tOn sait également que le résultat d’une requête est une nouvelle table. On va donc
se servir de cette nouvelle table dans le FROM :

8 2943 TG PA 00
Ce qui aurait pu nous donner en SQL :
SELECT "Fournisseur",
COUNT(*) AS "Nb livraison"
FROM "sousReq"
GROUP BY "Fournisseur"

Bien entendu, la requête précédente ne fonctionne pas car nous n’avons pas défini
la table "sousReq". C’est pourquoi l’intégralité de la requête "sousReq" doit être
recopiée dans le "FROM" comme si c’était une table :
SELECT "Fournisseur",
COUNT(*) AS "Nb livraisons"
FROM ( SELECT raisonSociale AS "Fournisseur",
dateLivraison AS "Date de livraison",
COUNT(*) AS "Nb lots livrés"
FROM fournisseur NATURAL JOIN lot
GROUP BY "Fournisseur","Date de livraison"
) AS "sousReq"
GROUP BY "Fournisseur"

Résultat : Fournisseur Nb livraisons


Lavandes et parfums 6
Pains et gâteaux 6
Séquence 2
Surgel'2000 4
Le laitier 6 Le langage
d'interrogation
Au bon blé 4 des données (LID)
Super boissons 10
Le boucher 4 Page 65

tMaintenant que l’on sait utiliser des tables issues de sous-requêtes dans le "FROM",
on peut encore améliorer notre précédente requête pour afficher d’autres informa-
tions comme le nombre de lots livrés au total par fournisseur :

8 2943 TG PA 00
Ce qui nous donne en SQL :
SELECT "Fournisseur",
COUNT(*) AS "Nb livraisons",
SUM("Nb lots livrés") AS "Nb total lots"
FROM ( SELECT raisonSociale AS "Fournisseur",
dateLivraison AS "Date de livraison",
COUNT(*) AS "Nb lots livrés"
FROM fournisseur NATURAL JOIN lot
GROUP BY "Fournisseur","Date de livraison"
) AS "sousReq"
GROUP BY "Fournisseur"

Résultat : Fournisseur Nb livraisons Nb total lots


Lavandes et parfums 6 6
Pains et gâteaux 6 6
Surgel'2000 4 4
Le laitier 6 8
Au bon blé 4 11
Super boissons 10 12
Le boucher 4 4

Séquence 2
Faire des opérations entre requêtes n’est pas très difficile en soi. Mais, pour réussir, il
Le langage faut absolument traiter les problèmes séparément et ne pas se lancer directement dans
d'interrogation
des données (LID) la construction de la requête finale.

Page 66
Exercice 10
Réaliser les requêtes permettant d’obtenir les informations ci-dessous. Comme pour
les exercices précédents, essayez dans la mesure du possible de réaliser ces requêtes
directement en SQL. Si vous n’y arrivez pas, essayez ensuite en graphique :
tla liste des fournisseurs qui ont déjà livré plusieurs lots lors d’une livraison ;
tle numéro du ou des fournisseurs qui ont effectué le plus de livraisons ;
tle nom du ou des fournisseurs qui ont effectué le plus de livraisons.

TP 1
tTOUR DE FRANCE

8 2943 TG PA 00
Synthèse

SELECT : Que veut-on afficher ?

t Le caractère * ("étoile") : désigne toutes les colonnes de la ou des tables


désignées dans le FROM.
t DISTINCT : supprime les doublons.
t AS : facultatif, il permet de renommer un champ.
t Préfixage des champs : technique qui consiste à préciser à quelle table
appartient un champ, en précédant le nom d’un champ de son nom de table.
C’est obligatoire dès lors qu’il existe un risque d’ambiguïté ou de confusion.
syntaxe : nomTable . nomChamp
t Calculs : Il suffit d’utiliser des opérateurs mathématiques courants tels que
+, -, /, *, ou % (modulo) pour que le résultat soit calculé.
t Fonctions : syntaxe : fonction ( nomChamp ).
– COUNT() : compte le nombre de lignes dont la valeur du champ entre
parenthèses n’est pas nulle ;
– MAX() : retourne la valeur maximale trouvée dans la colonne passée
entre parenthèses ; Séquence 2
– MIN() : retourne la valeur minimale trouvée dans la colonne passée entre
Le langage
parenthèses ; d'interrogation
– SUM() : retourne la somme des valeurs de la colonne passée entre paren- des données (LID)
thèses ;
Page 67
– AVG() : retourne la moyenne ("average" en anglais) des valeurs de la
colonne passée entre parenthèses ;
– et bien d’autres en fonction du SGBDR utilisé.

Rappel : toutes ces fonctions ne prennent en compte que les lignes qui res-
pectent les conditions du "WHERE".

8 2943 TG PA 00
FROM : de quelle(s) table(s) a-t-on besoin ?
t AS : Facultatif, il permet de renommer une table ;
t Jointures :
– table1 JOIN table2 : effectue une jointure équivalente ;
– tableGauche LEFT JOIN tableDroite : effectue une jointure en conservant
également les lignes de la table de gauche sans lignes équivalentes dans
la table de droite ;
– tableGauche RIGHT JOIN tableDroite : effectue une jointure en conservant
également les lignes de la table de droite sans lignes équivalentes dans la
table de gauche ;
– NATURAL : effectue la jointure définie après "NATURAL" ("JOIN", "LEFT
JOIN" ou "RIGHT JOIN") en prenant comme champ de jointure les champs
portant le même nom dans les 2 tables ;
– Îà utiliser uniquement lorsque l’on est sûr qu’il n’y a que le couple clé
primaire / clé étrangère qui porte le même nom ;
– USING (champClé) : effectue une jointure en prenant comme champ de
jointure le champ défini entre parenthèses ;
– Î à utiliser uniquement lorsque l’on est sûr que le couple clé primaire / clé
étrangère porte le même nom ;
Séquence 2
– ON champClé1 = champClé2 : effectue une jointure en prenant comme
Le langage condition de jointure ce qui est placé après "ON".
d'interrogation
des données (LID) WHERE : quelles sont les conditions de sélection d’un enregistrement ?
t <, >, <=, >=, =, <> : opérateurs de comparaisons qui peuvent être utilisés avec
Page 68 des champs ou des valeurs.
t AND, OR, NOT : opérateurs logiques qui permettent de combiner plusieurs
conditions.
t BETWEEN : définit un intervalle.
syntaxe : nomChamp BETWEEN borne1 AND borne2
t IN : efectue une comparaison sur une liste de valeurs.
t LIKE : Effectue une comparaison partielle. Doit être utilisé obligatoirement
avec des caractères "jokers" (% ou _).
syntaxe : nomChamp LIKE 'chaîne%'
t IS NULL : permet de vérifier si une valeur est "nulle" ou pas (IS NOT NULL).

GROUP BY : que veut-on regrouper ?


syntaxe : GROUP BY nomChamp1 , nomChamp2 , …

HAVING : quelles sont les conditions pour rejoindre un regroupement ?


syntaxe : HAVING conditions

ORDER BY : dans quel ordre veut-on afficher le résultat ?


t ASC : ordre croissant/alphabétique/chronologique/de vérité ;
t DESC : ordre inverse.

8 2943 TG PA 00
Séquence 3
Le langage de modification
des données : INSERT / UPDATE /
DELETE
Cette séquence présente la partie de SQL qui permet de mettre à jour une
base de données en insérant, en modifiant ou en supprimant des données.
Pour cette séquence, nous allons abandonner FlySpeed SQL Query, qui ne
nous est plus utile ici. Nous allons utiliser uniquement le code SQL, et, pour
cela, nous allons reprendre pgAdmin.

X Prérequis
Avoir compris le cours et les exercices de la séquence 2.

X Capacités attendues en fin de séquence


Séquence 3
Être capable de créer de nouveaux enregistrements et de les modifier en SQL.
Le langage
de modification
X Contenu des données (LMD)

Le LDD en graphique, comment faire ? ................................................. 70 Page 69


1. L’ajout d’un tuple avec "INSERT" ..................................................... 71
2. La modification d’un tuple avec "UPDATE" .................................... 74
3. La suppression d’un tuple avec "DELETE" ....................................... 75

Synthèse ................................................................... 77

8 2943 TG PA 00
Le LDD en graphique, comment faire ?
Sous pgAdmin, l’ajout, la modification et la suppression d’enregistrement peuvent se
faire très simplement à l’aide de l’éditeur de données :

Éditeur de données

L’ajout
Pour ajouter des données, il suffit de remplir directement une nouvelle ligne :

La modification
Séquence 3
Pour modifier des données, il suffit de les modifier directement dans l’éditeur :

Le langage
de modification
des données (LMD)
Î
Page 70

La suppression
Pour supprimer des enregistrements, il suffit de cliquer avec le bouton droit sur la ligne
à supprimer et de choisir "Supprimer":

Même lorsque l’on a la possibilité d’utiliser un logiciel graphique pour effectuer des opé-
rations sur un SGBDR, il faut garder à l’esprit que tout ce que l’on fait "graphiquement"
est en réalité réalisé en "langage SQL". C’est pourquoi il est nécessaire de connaître le
langage, sans compter que l’on ne peut pas forcément "tout" faire graphiquement, alors
qu’en SQL, c'est le cas !

8 2943 TG PA 00
1. L’ajout d’un tuple avec "INSERT"

L’ajout simple
En SQL, l’ajout d’un nouvel enregistrement se fait avec l’instruction "INSERT".
tPar exemple, on veut ajouter une nouvelle marque :
INSERT INTO marque (idMarque,nom)
VALUES (31,'Kelona')

Les valeurs contenues après "VALUES" seront insérées dans l’ordre dans lequel les
champs sont déclarés après le nom de table. La déclaration des champs est facultative
et, lorsqu’ils ne sont pas présents, c’est l’ordre dans lequel ils ont été déclarés lors de la
création de la table qui est pris en compte. L’ordre des champs n’a pas d’importance à
partir du moment où il y a bien une cohérence entre l’ordre des champs et les valeurs
qui vont y être insérées.
tPour ajouter cette nouvelle marque, on peut également faire :
INSERT INTO marque
VALUES (31,'Kelona')
tOu encore :
INSERT INTO marque (nom,idMarque)
VALUES ('Kelona',31) Séquence 3

Le langage
Lors d’une insertion, il peut arriver qu’on ne souhaite pas remplir tous les champs18. de modification
tIl suffit pour cela de ne pas déclarer dans le "INSERT" le ou les champs à laisser sans des données (LMD)
contenu :
Page 71
INSERT INTO marque (idMarque)
VALUES (31)
tOu alors de stipuler clairement que l’on veut une valeur "nulle":
INSERT INTO marque (idMarque,nom)
VALUES (31,NULL)

Attention, la valeur NULL est différente d’une chaîne vide" (2 apostrophes simples). Ce
qui veut dire que :
"INSERT INTO marque VALUES (31,NULL)" n’aura pas du tout la même incidence
que
"INSERT INTO marque VALUES (31,").

L’ajout simple à partir d’une table


Pour l’instant, nous avons disposé de toutes les nouvelles valeurs à insérer. Que fait-on si
on a besoin de récupérer une valeur avant de procéder à une insertion ?

18. Pour cela, il faut au préalable que la saisie n’ait pas été rendue obligatoire à la création de la
table (case "Non NULL" non cochée lors de l’ajout du champ).

8 2943 TG PA 00
On veut, par exemple, ajouter une nouvelle marque, mais on souhaite que son identi-
fiant soit automatique et non plus saisi 19.
tOn sait récupérer le dernier identifiant de marque. Il suffit donc de l’incrémenter
de 1 pour obtenir le nouveau :
SELECT MAX(idMarque)+1 AS "Prochain n° de marque"
FROM marque

En ajoutant une valeur dans le SELECT, cela a pour effet de l’afficher.

tIl nous suffit donc d’ajouter le nom de la marque dans le "SELECT" pour obtenir une
table avec le nouvel identifiant de marque et son nom :
SELECT MAX(idMarque)+1 AS "Prochain n° de marque",
'Kelona' AS "Nouvelle marque"
FROM marque

Résultat : Prochain numéro de marque Nouvelle marque


31 Kelona
Séquence 3
tEt, depuis la page précédente, on sait ajouter un nouvel enregistrement. Il nous
Le langage
de modification suffit donc de combiner les 2 requêtes :
des données (LMD)
INSERT INTO marque
Page 72
SELECT MAX(idMarque)+1,'Kelona'
FROM marque

"VALUES" a été remplacé par "SELECT" car, ici, nous n’ajoutons pas des "valeurs" mais
bien des "enregistrements" retournés par le "SELECT".

L’ajout multiple
Si l’on a plusieurs nouveaux enregistrements à ajouter, on peut bien évidemment multi-
plier les "INSERT" autant de fois que nécessaire. Toutefois, on peut également procéder
à l’ajout de plusieurs enregistrements avec un seul "INSERT":
tOn a, par exemple, 3 nouveaux rayons à ajouter :
INSERT INTO rayon
VALUES (16,'Confiserie'),
(17,'Informatique'),
(18,'Musique')

19. La plupart des SGBDR proposent un système d’incrémentation automatique qui est bien sûr
à privilégier, le but ici est de mettre en œuvre des sous-requêtes d’interrogation dans une
requête d’insertion.

8 2943 TG PA 00
tAdmettons maintenant que ces nouveaux rayons soient dans une table "nouveau-
xRayons":

Résultat : nouveauxRayons
idRayon libelle
16 Confiserie
17 Informatique
18 Musique

tNous allons donc indiquer à "INSERT" où aller récupérer les rayons à ajouter :
INSERT INTO rayon
SELECT *
FROM nouveauxRayons
tSi on ne veut ajouter que le n° 17, il nous suffit de modifier notre "SELECT" comme
on sait déjà le faire :
INSERT INTO rayon
SELECT *
FROM nouveauxRayons
WHERE idRayon = 17

Exercice 1 Séquence 3

Réaliser les requêtes permettant d’insérer les informations suivantes : Le langage


de modification
tLe nouveau fournisseur n° 12 "Zap 83", se situant au "916 rue Pourquoi pas" à des données (LMD)
Toulon (83000) soit à 4,2 km ;
tInsertion 20 dans la table "article" des articles présents dans la table temporaire Page 73
"nouveauxArticles":
nouveauxArticles
Code-barres libelle Prix bio Rayon Marque
3760061541214 DVD concert 5 18 31
2001011013278 Jeu vidéo foot 6.99 17 30
5390102480783 Jeu vidéo shoot 9.99 17 30

20

20. La table "nouveauxArticles" n'existant pas dans notre base, la requête ne pourra pas être
testée avec pgAdmin.

8 2943 TG PA 00
2. La modification d’un tuple avec "UPDATE"
Les données présentes dans une base ne sont bien évidemment pas figées. Le SQL nous
permet de modifier les données d’une table grâce à l’instruction "UPDATE". On peut
également parler de mise à jour des données.
tOn souhaite, par exemple, dans le cadre d’une promotion, baisser de 5 % le prix de
tous les articles :
UPDATE article
SET prix = prix * 0.95

Cette requête modifie tous les enregistrements de la table "article" sans condition.
L’instruction "UPDATE" comme l’instruction "SELECT" peuvent recevoir en complément
l’instruction "WHERE" qui permet de définir une condition de mise à jour.

tOn souhaite, par exemple, dans le cadre d’une promotion, baisser de 15 % le prix
de tous les articles "bio":
UPDATE article
SET prix = prix * 0.85
WHERE bio = TRUE

Séquence 3
"UPDATE" n’est pas limité à la mise à jour d’un seul champ : lors d’une mise à jour, on
peut modifier le contenu de tous les champs désirés.
Le langage
de modification
des données (LMD)
tPrenons, par exemple, le cas du fournisseur n° 6 qui déménage "chemin du
Page 74 Rossignol" à "Châteauvallon" (83190). Sa raison sociale ne change pas, son numéro
de téléphone et son email non plus. Par contre, sa nouvelle distance est de 5,2 km :
UPDATE fournisseur
SET adresseRue = 'chemin du Rossignol',
adresseCP = '83190',
adresseVille = 'Châteauvallon',
distanceKm = 5.2
WHERE idFournisseur = 6

"UPDATE", dans sa définition d’origine, est limité à l’utilisation d’une seule table.
Mais, depuis SQL-92, on peut utiliser des sous-requêtes de la même manière qu’avec les
requêtes d’interrogations.

tOn souhaite, par exemple, déplacer tous les articles "bio" du rayon "Apéritifs" (on
ne connaît pas le numéro) dans le rayon n° 2. Au passage, on souhaite baisser le
prix de ces articles de 5% :

8 2943 TG PA 00
UPDATE article
SET idRayon = 2, prix = prix * 0.95
WHERE idRayon IN ( SELECT idRayon
FROM rayon
WHERE libelle = 'Apéritifs'
)
AND bio = TRUE
tOn peut même s’appuyer sur une sous-requête pour définir la nouvelle valeur d’un
champ. On veut, par exemple, déplacer tous les articles "bio" du rayon "Apéritifs"
dans le rayon "Boissons". Au passage, on souhaite baisser le prix des articles de 5 % :
UPDATE article
SET idRayon = ( SELECT idRayon
FROM rayon
WHERE libelle = 'Boissons'
),
prix = prix * 0.95
WHERE idRayon IN ( SELECT idRayon
FROM rayon
WHERE libelle = 'Apéritifs'
)
AND bio = TRUE
Séquence 3

Le langage
Exercice 2 de modification
des données (LMD)
Réaliser les requêtes permettant d’effectuer les mises à jour suivantes :
til y a une promotion, tous les articles du rayon "Surgelés" baissent de 10 % ; Page 75
tune autre promotion réduit le prix de tous les articles de la marque "Bonduil"
de 1 € ;
tune personne rapporte un paquet de "glaces chocolat en cornets" et désire
qu’on lui reprenne contre remboursement (ticket de caisse n° 1).

3. La suppression d’un tuple avec "DELETE"


Les données d’une base peuvent avoir une durée de vie au-delà de laquelle elles
deviennent inutiles. Dès lors, leur présence peut devenir problématique (gaspillage de
ressources mémoire inutiles, traitement plus long …). C’est pourquoi le langage SQL
met à notre disposition l’instruction "DELETE" qui permet de supprimer un ou plusieurs
enregistrements.
tOn souhaite, par exemple, supprimer la marque "Flagada" (n° 30) étant donné que
l’on n’a jamais eu d’articles de cette marque :
DELETE FROM marque
WHERE idMarque = 30

8 2943 TG PA 00
Comme avec "INSERT" et "UPDATE", on peut également utiliser une sous-requête pour
mieux cibler les enregistrements à supprimer.

tPar exemple, si l’on veut supprimer les fournisseurs que l’on a dans la base mais qui
n’ont jamais fait de livraison :
DELETE FROM fournisseur
WHERE idFournisseur NOT IN ( SELECT idFournisseur
FROM lot
)

Attention, lorsque vous concevez une requête de suppression, veillez à ce que votre requête
respecte bien les règles de gestion de votre base, sans quoi elle ne fonctionnera pas.

tPar exemple, on souhaite supprimer le rayon "Apéritifs":


DELETE FROM rayon
WHERE libelle = 'Apéritifs'

Cette requête seule ne pourra pas fonctionner car elle ne respecte pas la contrainte d’inté-
Séquence 3 grité référentielle suivante : la clé étrangère idRayon de la table "article" fait référence à
la clé primaire idRayon de la table "rayon". En effet, si on supprime ce rayon, les articles
Le langage qui y sont, feront référence à un rayon qui n’existe plus. C’est pourquoi, pour pouvoir
de modification supprimer ce rayon, il faut d’abord supprimer les références à ce rayon.
des données (LMD)
tOn commence par supprimer la référence au rayon "Apéritifs" dans article 21 :
Page 76
UPDATE article
SET idRayon = NULL
WHERE idRayon = ( SELECT idRayon
FROM rayon
WHERE libelle = 'Apéritifs'
)
tEt enfin, on peut supprimer le rayon :
DELETE FROM rayon
WHERE libelle = 'Apéritifs'

TP 2
tTOUR DE France - suite

21. Si on respecte strictement notre MCD, ça n’est pas non plus possible car les cardinalités entre
"article" et "rayon" nous informent qu’un article est placé dans un et un seul rayon.

8 2943 TG PA 00
Synthèse

INSERT INTO table : ajouter des nouveaux enregistrements dans "table"

t VALUES : permet d'insérer de nouveaux enregistrements à partir de valeurs


saisies par le concepteur de la requête.
syntaxe : INSERT INTO table ( champ1 , champ2 , … , champN )
VALUES ( valeur1 , valeur2 , … , valeurN ) ,
( valeurA , valeurB , … , valeurX )
t SELECT : permet d’insérer de nouveaux enregistrements à partir de données
existantes et accessibles depuis une requête d’interrogation.
syntaxe : INSERT INTO table ( champ1 , champ2 , … , champN )
SELECT champ1 , champ2 , … , champN ,
FROM tableX
WHERE champX = valeurX

UPDATE table : ajouter de nouveaux enregistrements dans "table"

t SET : permet de désigner les champs où opérer la mise à jour ainsi que les
Séquence 3
nouvelles valeurs à affecter.
syntaxe : UPDATE table Le langage
de modification
SET champ1 = valeur1 , champ2 = valeur2 , … , champN = valeurN des données (LMD)

t WHERE : permet de cibler les enregistrements à modifier en appliquant des


Page 77
conditions de mise à jour (que l’on peut combiner avec les opérateurs habi-
tuels "AND", "OR" et "NOT").
syntaxe : UPDATE table
SET champ1 = valeur1 = champ2 = valeur2 , … , champN = valeurN
WHERE champX = valeurX

DELETE FROM table : supprimer des enregistrements de "table"

t WHERE : permet de cibler les enregistrements à supprimer en appliquant


des conditions de suppression (que l’on peut combiner avec les opérateurs
habituels "AND", "OR" et "NOT").

8 2943 TG PA 00
Séquence 4
Le langage de description
des données : CREATE / ALTER /
DROP
Cette séquence présente la partie de SQL qui permet de créer, de modifier
et de supprimer des tables.

X Prérequis
Avoir compris le cours et les exercices des séquences précédentes.

X Capacités attendues en fin de séquence


Être capable de créer et de modifier la structure d’une base de données en SQL.

X Contenu Séquence 4

1. La création d’une table ................................................................... 80 Le langage


de description
2. Les clés primaires ............................................................................. 82 des données (LDD)
3. Les clés étrangères ........................................................................... 83
Page 79
4. La modification d’une table ............................................................ 85
5. La suppression d’une table ............................................................. 89
6. Les index ........................................................................................... 90
7. Les vues ............................................................................................ 92

...........................................................................................................
Synthèse 95

8 2943 TG PA 00
1. La création d’une table
Pour créer une table, on procède de la même manière qu’avec pgAdmin, c’est-à-dire que
l’on a besoin du dictionnaire des données pour avoir les informations sur chaque champ.
Ensuite, il nous suffit d’utiliser l’instruction de création "CREATE TABLE" que nous four-
nit le langage SQL.
Par exemple, on souhaite proposer à nos clients un système de points en fonction du
montant des achats. Ce système permettra à ceux qui le désirent de cumuler des points
qui, après un certain nombre donnent droit à un cadeau.
Pour pouvoir comptabiliser ce nombre de point, on va devoir créer une table qui contien-
dra les clients qui souhaitent participer à ce système. On profite d’effectuer ce référen-
cement pour proposer aux clients de s’abonner à une newsletter (lettre d’information
par email).

Rappel : dans un cadre professionnel, préalablement à tout envoi de newsletter


(et par conséquent à toute collecte de données personnelles dont fait partie
l’email) vous avez l’obligation d’effectuer une déclaration à la CNIL (Commission
Nationale Informatique et Libertés).
La CNIL est l’organisme national chargé de faire respecter le droit des personnes
au contrôle de leurs informations nominatives.
Toute application informatique (site Internet, base de données …) comportant
ou traitant des données directement ou indirectement nominatives doit être
Séquence 4
enregistrée auprès de la CNIL qui envoie alors un récépissé contenant un numéro
Le langage de déclaration à faire figurer dans les mentions légales. C’est la loi relative à
de description l’informatique, aux fichiers et aux libertés qui vous y oblige (consultable sur le
des données (LDD) site de la CNIL www.cnil.fr).

Page 80 tOn commence par modifier nos schémas :


– Schéma conceptuel des données :

ACHAT CLIENT
idAchat
0,1 Effectuer 1,n idClient
dateAchat nom
montantTotal prenom
dateDeNaissance
email
newsletter

– Diagramme de classes :

ACHAT CLIENT
idAchat 1..* 0..1 idClient
dateAchat nom
montantTotal prenom
dateDeNaissance
email
newsletter

8 2943 TG PA 00
tOn va également devoir mettre à jour notre schéma relationnel des données :
ACHAT (idAchat, dateAchat, montantTotal, idClient)
idAchat : Clé primaire
idClient : Clé étrangère en référence à idClient de
client
CLIENT (idClient, nom, prenom, dateDeNaissance, email,
newsletter)
idClient : Clé primaire
tAinsi que notre dictionnaire des données :
Nom Type de données Longueur Précision
CLIENT
idClient numeric 4 0
nom character varying
prenom character varying
dateDeNaissance date
email character varying
newsletter boolean

tCréons cette table en SQL :


CREATE TABLE client Séquence 4
(
idClient numeric(4), Le langage
de description
nom character varying,
des données (LDD)
prenom character varying,
dateDeNaissance date, Page 81
email character varying,
newsletter boolean
)

Avec cette requête, on se rend encore une fois bien compte qu’en SQL il suffit d’indiquer
au système ce que l’on veut obtenir, pour l’obtenir.

tSous pgAdmin, si on voulait créer cette table graphiquement, il nous suffirait de


faire comme on l’a vu au point 6 de la séquence 1 (page 17) :

8 2943 TG PA 00
2. Les clés primaires
La clé primaire d’une relation est l’attribut ou l’ensemble d’attributs qui permet de dis-
tinguer entre eux tous les tuples de la relation. Cette clé primaire (simple ou composée)
doit donc être unique et définie (non nulle).
tOn peut indiquer directement la clé primaire lors de la déclaration de la table en
ajoutant "PRIMARY KEY" à la définition du champ :
CREATE TABLE client
(
idClient numeric(4) PRIMARY KEY,
...
)

"PRIMARY KEY" permet d’indiquer que la valeur du champ doit être unique et qu’elle
ne peut pas être nulle. L’utilisation de "PRIMARY KEY" de cette manière ne fonctionne
qu’avec une clé primaire simple. Lorsqu’elle est composée, il faut déclarer explicitement
une contrainte sur la table.

tPar exemple, pour créer la table "listeCourses" qui contient une clé primaire com-
posée des champs "idAchat" et "idArticle", voici ce qu’on doit faire :
CREATE TABLE listecourses
Séquence 4
(
idAchat numeric(8) NOT NULL,
Le langage idArticle numeric(13) NOT NULL,
de description quantite numeric(3)
des données (LDD)
CONSTRAINT pk_listeC PRIMARY KEY (idAchat, idArticle)
)
Page 82

"PRIMARY KEY" est limité à une seule utilisation par table, ce qui revient à dire qu’une
table ne possède qu’une seule clé primaire (qui peut être composée de plusieurs champs).
Cela confirme qu’il faut bien parler d’une "clé primaire composée" et non pas de "clés
primaires". Cette syntaxe est plus claire fonctionne quelle que soit la composition de la
clé primaire et est, de toute façon, ce qui sera fait en réalité par le SGBDR.
tLorsque le SGBDR exécute cette requête :
CREATE TABLE client
(
idClient numeric(4) PRIMARY KEY,
...
)
tEn réalité, voici exactement ce que le SGBDR fait :
CREATE TABLE client
(
idClient numeric(4) NOT NULL,
...
CONSTRAINT pk_client PRIMARY KEY (idClient)
)

8 2943 TG PA 00
tOn le voit d’ailleurs également lorsqu’on le fait graphiquement avec pgAdmin.
Il faut en effet "ajouter" une "contrainte" de "clé primaire":

3. Les clés étrangères


Séquence 4
Une clé étrangère est un attribut d’une relation qui a un rôle de clé primaire unique dans
Le langage
une autre relation. Cette clé permet donc de formaliser physiquement les contraintes de description
que l’on a dans le schéma relationnel. des données (LDD)
Comme pour la définition d’une clé primaire, la clé étrangère est une contrainte d’inté-
grité sur la relation. On va donc la déclarer directement à la création de la table. Page 83
tPrenons, par exemple, la création de la table "achat":
CREATE TABLE achat
(
idAchat numeric(8) NOT NULL,
dateAchat date,
montantTotal numeric(6,2),
idClient numeric(4),
CONSTRAINT pk_achat PRIMARY KEY (idAchat),
CONSTRAINT fk_client FOREIGN KEY (idClient)
REFERENCES client (idClient)
)

"FOREIGN KEY" indique que la clé étrangère idClient fait "REFERENCE" à la table
"client" et en particulier au champ idClient. On n’est pas obligé de créer les contraintes
en même temps que les tables. Dans la partie suivante, nous verrons comment faire.
On a vu comment déclarer une clé étrangère simple, mais on peut également être amené
à devoir créer une clé étrangère composée, comme ici, par exemple, si une contrainte
d’intégrité fonctionnelle pointe sur la table "lot" qui possède une clé primaire composée.

8 2943 TG PA 00
...
CONSTRAINT fk_lot FOREIGN KEY (idLot,idArticle)
REFERENCES lot (idLot,idArticle)
...
tSous pgAdmin, cela revient à créer une clé étrangère composée, qui pointe vers
une clé primaire composée :

Séquence 4

Le langage
de description
des données (LDD)

Page 84
Exercice 1
Réaliser les requêtes permettant de créer 22 les tables suivantes :
t"rayon", "article" et "marque".

22. Attention, les tables étant déjà créées, vous ne pourrez pas tester ces requêtes via pgAdmin.

8 2943 TG PA 00
4. La modification d’une table
Comme on vient de le voir, la structure d’une base de données peut être amenée à évo-
luer. Encore une fois, le langage SQL a tout prévu avec l’instruction "ALTER" qui permet
de modifier la structure d’une table existante.
tPar exemple, la table "achat" étant déjà créée, on veut juste lui adjoindre un
champ :
ALTER TABLE achat
ADD COLUMN idClient numeric(4)

Sous pgAdmin, il suffit de cliquer sur


la table ciblée avec le bouton droit
et de choisir "Ajouter un objet", puis
"Ajouter une colonne":

tOn a ajouté un champ à la struc-


Séquence 4
ture, on peut également le supprimer :
Le langage
ALTER TABLE achat de description
DROP COLUMN idClient des données (LDD)

Sous pgAdmin, il y a plusieurs façons de faire. Soit Page 85


en modifiant la structure de la table dans ses pro-
priétés (clic droit sur la table, puis "Propriétés"), soit
en cliquant avec le bouton droit directement sur la
colonne ciblée dans l’organisation graphique de la
table puis en choisissant "Supprimer":

tLe champ que l’on veut adjoindre est une clé


étrangère. Il va donc falloir ajouter le champ et la contrainte indiquant que c’est
une clé étrangère :
ALTER TABLE achat
ADD COLUMN idClient numeric(4),
ADD CONSTRAINT fk_client FOREIGN KEY (idClient)
REFERENCES client (idClient)
tPour supprimer la contrainte, comme pour la suppression d’un champ, on utilise
"DROP":
ALTER TABLE achat
DROP CONSTRAINT fk_client

8 2943 TG PA 00
Lorsque l’on veut supprimer un champ qui possède une contrainte, on peut supprimer le
champ directement avec un "DROP COLUMN" sans avoir besoin au préalable d’effectuer
un "DROP CONSTRAINT".

t"ALTER" nous permet également de renommer les champs. Par exemple, si on veut
"franciser" l’appellation de l’adresse électronique (mél) des clients :
ALTER TABLE client
RENAME COLUMN email TO mel

Graphiquement, sous pgAdmin, on peut aller soit dans


les propriétés de la table puis dans l’onglet "Colonnes"
pour modifier un champ, soit directement dans les
propriétés de la colonne ciblée dans l’organisation gra-
phique de la table puis en choisissant "Propriétés" :

Séquence 4

Le langage
de description tDe la même façon, on peut renommer également le nom de la table :
des données (LDD)
ALTER TABLE client
Page 86 RENAME TO consommateur

Sous pgAdmin, il suffit encore une fois de


passer par les "Propriétés" de la table :

Lorsque l’on renomme une table ou une clé primaire, on peut se poser la question des
références existantes à ces noms. Pas d’inquiétude, le SGBDR se charge de renommer les
cibles des références. Ainsi, dans la table "achat" :

8 2943 TG PA 00
...
CONSTRAINT fk_client FOREIGN KEY (idClient)
REFERENCES client (idClient)
...

Deviendra automatiquement :

...
CONSTRAINT fk_client FOREIGN KEY (idClient)
REFERENCES consommateur (idClient)
...

Attention, toutefois, lorsque l’on utilise "RENAME", aucune autre modification n’est combi-
nable. Il faudra obligatoirement passer par un autre "ALTER TABLE".

tOn peut également être amené à changer le type d’un champ. Par exemple, on veut
passer le champ "dateAchat" de la table "achat" en "chaîne de caractères" (character
varying) :
ALTER TABLE achat
ALTER COLUMN dateAchat TYPE character varying

Attention, lorsque vous changez le type d’un champ, ce


sont toutes les valeurs qui y sont contenues qui seront Séquence 4
affectées. Autant la conversion d’un champ numérique
en chaîne de caractères aura peu d’incidence sur son Le langage
de description
contenu, autant la conversion d’une chaîne de carac-
des données (LDD)
tères vers un type numérique pourra se solder par une
perte intégrale des valeurs d’origine.
Page 87
Il faut donc utiliser ce "transtypage" avec prudence.

Attention, cette manipulation n’est pas possible sous


pgAdmin qui restreint les "transtypages" aux seuls
types dits "connexes". Par exemple, ici, le type date ne
peut être modifié qu'en type "timestamp" (horodatage)
qui reste un type connexe du type "date".

C’est encore une preuve que la connaissance du langage SQL reste essentielle, au-delà
même d’un bon savoir-faire sur un logiciel graphique !
tOn peut également modifier les contraintes sur un champ. Admettons que l’on souhaite
supprimer le rôle de clé primaire 23 du champ "idClient" de la table "client" et que l’on
souhaite aussi supprimer la contrainte d’existence "NOT NULL":
ALTER TABLE client
DROP CONSTRAINT pk_client

Si on se contente de cette modification, le champ "idClient" ne sera plus considéré


comme une clé primaire mais on sera encore contraint d’y saisir une valeur (à cause de
"NOT NULL" qui elle n’a pas été supprimée).

23. Attention, cette opération ne sera possible que si aucune clé étrangère n’y fait référence.

8 2943 TG PA 00
Graphiquement, sous pgAdmin, il suffit de cliquer avec le
bouton droit sur la "Contrainte" ciblée dans l’organisation
graphique de la table puis de choisir "Supprimer":

tOn supprime donc la contrainte d’existence qu’il y a sur "idClient":


ALTER TABLE client
ALTER COLUMN idClient DROP NOT NULL

Attention, supprimer le rôle de clé primaire n’est possible que si aucune référence au
champ visé n’existe dans la base.
Et si, au contraire, on veut contraindre un champ à être saisi, on utilisera "SET".

Sous pgAdmin, il faut décocher la case "non NULL" dans les propriétés du champ :

On remet l’obligation de saisie sur "idClient" :


ALTER TABLE client
Séquence 4
ALTER COLUMN idClient SET NOT NULL
Le langage
de description Sous pgAdmin, il suffit de cocher la case "non NULL" dans les propriétés du champ :
des données (LDD)

Page 88

Exercice 2
Réaliser les requêtes permettant d’effectuer les modifications suivantes :
tle champ "libelle" de la table "rayon" est renommé en "nomRayon";
tle champ "packaging" de la table "article" est supprimé ;
tle champ "raisonSociale" de la table "fournisseur" devient obligatoire.

8 2943 TG PA 00
5. La suppression d’une table
La suppression d’une table se fait grâce à l’instruction "DROP TABLE".
tPar exemple, on veut supprimer la table temporaire "nouveauxRayons":
DROP TABLE nouveauxRayons

Attention, lorsque l’on supprime une table, il faut obligatoirement qu’il n’y ait plus
aucune référence à cette table dans la base de données. Encore une fois, le respect de
l’intégrité référentielle est capital dans la gestion de bases de données.

Sous pgAdmin, il suffit de cliquer avec le bouton droit sur la table ciblée et de choisir
"Supprimer":

Séquence 4

Le langage
de description
des données (LDD)
tSi on veut, par exemple, supprimer la table "client", il faut d’abord supprimer la
contrainte de clé étrangère dans "achat": Page 89
ALTER TABLE achat
DROP CONSTRAINT fk_client
DROP TABLE client

Graphiquement, si on cherche à supprimer direc-


tement une table sur laquelle il existe des réfé-
rences, l’erreur suivante apparaît :

Supprimer une contrainte ne supprime pas le champ contraint. Donc, si l’objectif est
de supprimer le champ, il faudra aussi effectuer un "DROP COLUMN" dans le "ALTER
TABLE". Ou alors, comme on l’a vu précédemment, on peut se contenter de supprimer le
champ, ce qui aura pour effet de supprimer le champ et sa contrainte.

Exercice 3
Réaliser les requêtes permettant de supprimer la table suivante :
t"nouveauxArticles" de l’exercice 1 de la séquence 3.

8 2943 TG PA 00
6. Les index
Le sommaire au début de ce cours vous permet d’accéder à une séquence directement,
sans avoir à parcourir toutes les pages pour la trouver. De la même manière, un index
dans une base de données sert à optimiser l’accès aux données afin qu’il soit le plus
"facile" possible en indexant certaines colonnes et ainsi optimiser les temps de traite-
ment.
Un index est une table "système" qui accompagne une table de données suivant la règle
selon laquelle, pour chaque enregistrement de la table de données, il existe une ligne
correspondante dans la table "index" (l’ordre des lignes étant différent dans la table
"index").

La gestion des index est utilisée par tous les SGBDR mais ne fait pas partie de la norme
SQL et, même dans sa dernière révision (SQL:2008) : on ne trouve pas la moindre trace
d’index. L’explication est simple, le SQL a été créé pour répondre à des problématiques
"logiques" de gestion des données, pas pour répondre aux problématiques "systèmes" des
administrateurs de SGBDR.
PostgreSQL crée automatiquement un index pour chaque clé primaire afin d’assurer
l’unicité. Il n’est donc pas nécessaire de créer un index spécifiquement pour les colonnes
de clés primaires.
Par défaut, les données que contient une table apparaîssent dans l’ordre dans lequel on
les a saisies. Cet ordre ne correspond pas toujours à celui dont on a besoin pour traiter
Séquence 4
les données.
Le langage
de description
des données (LDD)

Page 90

Table "index" Table de données

Créer de "bons" index constitue un pas important vers l’amélioration de la performance


et la maîtrise de la consommation de ressources. Un "bon" index est un index qui vous
permet de trouver des données en consommant moins d’opérations d’entrées/sorties sur
disque et moins de ressources systèmes.
Pour créer de "bons" index, il faut impérativement comprendre :
tComment sont utilisées les données ?
tQuels sont les types de requêtes ?
tÀ quelle fréquence sont-elles exécutées ?
Il faut également comprendre comment le moteur d’exécution des requêtes utilise les
index pour trouver des données plus rapidement.

8 2943 TG PA 00
Comme avec la plupart des techniques d’optimisation des performances, il n’existe
pas de règles générales : par exemple, si notre application effectue principalement des
requêtes d’interrogation ("SELECT"), mettre en œuvre davantage d’index permet à nos
requêtes de s’exécuter plus rapidement. Mais si notre application effectue de nombreuses
opérations de manipulation de données ("INSERT", "UPDATE" et "DELETE"), on doit
alors limiter le nombre d’index créés pour ne pas ralentir ces opérations de manière
significative.
La mise en œuvre d’index implique une étude des requêtes les plus importantes, et plus
particulièrement celles dont les performances ont le plus d’impact sur les utilisateurs.
C’est pourquoi, après avoir créé un index, il faut réexécuter les requêtes que l’on a
étudiées et déterminer si les performances ont été améliorées. Si ce n’est pas le cas, il
faudra supprimer l’index.

Avec PostgreSQL (comme avec presque tous les SGBDR), si on veut créer un index, il suffit
d’utiliser l’instruction "CREATE INDEX" (qui, je le rappelle, ne fait pas partie de la norme
SQL).
tPar exemple, si notre application utilise beaucoup de requêtes portant sur les libel-
lés d’articles, on va créer un index sur cette colonne en triant les libellés par ordre
alphabétique :
CREATE INDEX idx_libelleArticle
ON article (libelle ASC)

tCela aura pour effet de créer Table index "idx_libelleArticle" Séquence 4


cette table index :
libelle n°ligne
Le langage
Camenbert 1 de description
Céréales petit déjeuner au miel 8 des données (LDD)
Ketchup nature 5
Page 91
Merguez 2
Morceaux de poulet au paprika 3
Spaghetti au petit épeautre bio 6
Steaks hachés 15 % M.G. 7
Terrine de campagne 4
… …

tFaisant Table "article"


référence à la
n°ligne idArticle libelle prix …
table article :
1 3354349412151 Camenbert 1,65 …
2 3001889762899 Merguez 4,50 …
3 3525014803501 Morceaux de poulet au paprika 4,95 …
4 3597521436775 Terrine de campagne 2,06 …
5 3481860953738 Ketchup nature 0,99 …
6 3068633167405 Spaghetti au petit épeautre bio 3,58 …
7 3225251717484 Steaks hachés 15% M.G. 2,50 …
8 3151909536785 Céréales petit déjeuner au miel 2,24 …
… … …

8 2943 TG PA 00
On se rend bien compte du temps de traitement économisé lorsque l’on exécute cette
requête :
SELECT *
FROM article
ORDER BY libelle ASC
En effet, au lieu d’avoir à parcourir l’intégralité de la table article, le moteur d’exécution
va se contenter de parcourir la table index "idx_libelleArticle".
Attention, toutefois, à bien rester vigilant sur la mise en œuvre des index et à les utiliser
à bon escient car chaque index doit ensuite subir des opérations de maintenance par le
SGBDR. Ces opérations étant, elles, consommatrices de ressources.

Sous pgAdmin, la création d’un index se fait en cliquant avec le bouton droit sur "Index"
dans l’organisation graphique de la table ciblée puis en choisissant "Ajouter un index…".
Il suffit ensuite de nommer l’index et de choisir les colonnes :

Î Î

Séquence 4

Le langage
de description
des données (LDD)

Page 92

tLa suppression d’un index se fera simplement avec "DROP INDEX":


DROP INDEX idx_libelleArticle

tSous pgAdmin, la suppression d’un index se fera en


cliquant avec le bouton droit sur l’index ciblé dans
l’organisation graphique de la table puis en choisis-
sant "Supprimer":

8 2943 TG PA 00
7. Les vues
La "vue" est comme un filtre permettant de voir uniquement les données qui nous inté-
ressent. C’est pour cette raison qu’on parle de visualiser ou de modifier des données "à
partir" d’une vue.
Une vue n’est rien d’autre qu’une table "virtuelle" s’appuyant sur une ou plusieurs tables
"réelles" appelées, pour l’occasion, "tables sous-jacentes à la vue".
Il faut commencer par créer cette vue grâce à l’instruction "CREATE VIEW".
tPar exemple, on veut en permanence avoir la liste des articles (libellés, prix, noms
de marques et libellés de rayons) ayant un prix inférieur à 1 € :
CREATE VIEW vue_articlesInf1Euro AS
SELECT a.libelle AS "Article",
prix AS "P.U",
nom AS "Marque",
r.libelle AS "Rayon"
FROM article AS a NATURAL JOIN marque
JOIN rayon AS r USING (idRayon)
WHERE prix < 1
ORDER BY prix ASC
tUne fois la vue créée, on l’utilise exactement de la même façon qu’une table
"réelle". Par exemple, ici, on ne veut que les articles dont le prix est inférieur à 1 € Séquence 4
mais tout de même supérieur ou égal à 0,50 € :
Le langage
SELECT * de description
des données (LDD)
FROM vue_articlesInf1Euro
WHERE "P.U" >= 0.5
Page 93

Bien évidemment, les conditions que l’on spécifie dans le "WHERE" viennent s’ajouter
à celles spécifiées dans la vue. La requête précédente est donc équivalente à :
...
FROM article AS a NATURAL JOIN marque
JOIN rayon AS r USING (idRayon)
WHERE prix >= 0.5
AND prix < 1
...

Résultat : vue_articlesinf1Euro
Article P.U. Marque Rayon
Ketchup nature 0,99 Amogla Condiments
Pain de mie nature 0,99 Sally's Pain
Eau minérale aromatisée 0,99 Vilvic Boissons
… … … …

Sous pgAdmin, la création d’une vue se fait en cliquant avec le bouton droit sur "Vues"
qui se trouve au même niveau que les tables et en choisissant "Ajouter une vue…". Il
suffit ensuite de nommer la vue et d’insérer la requête qui va définir la vue dans l’onglet
"Définition":

8 2943 TG PA 00
Î Î

Encore une fois, on voit ici la nécessité de connaître le langage SQL même lorsque l’on
utilise un logiciel graphique !
Attention, l’insertion ou la mise à jour "à partir" d’une vue est possible mais nécessite
d’être encadrée. L’instruction "WITH CHECK OPTION" ajoutée au "CREATE VIEW"
permet d’insérer ou de mettre à jour uniquement les enregistrements accessibles "à par-
tir" de la vue, c’est-à-dire satisfaisants aux conditions définies à la création de la vue.
Une vue a de multiples missions :
Séquence 4
– remplacer une requête complexe par une ou plusieurs requêtes simples ;
– assurer un semblant de confidentialité en ne rendant accessibles que certains
Le langage champs ;
de description – permettre d’avoir des noms de tables et de champs plus simples ;
des données (LDD) – pouvoir réutiliser un même ensemble de tuples pour plusieurs recherches.

Page 94 tLa suppression d’une vue se fera simplement avec "DROP VIEW":
DROP VIEW vue_articlesInf1Euro

tSous pgAdmin, la suppression se fera en cliquant


avec le bouton droit sur la vue ciblée dans l’orga-
nisation graphique de la base puis en choisissant
"Supprimer":

TP 3
tTOUR DE France - suite

8 2943 TG PA 00
Synthèse

CREATE TABLE table : crée la table "table"

t NOT NULL : rend la saisie d’un champ obligatoire.


t PRIMARY KEY : désigne un champ comme clé primaire.
t CONSTRAINT : crée une contrainte sur la table :
syntaxe : CONSTRAINT nomContrainte …
– PRIMARY KEY : contrainte qui permet de désigner un ou plusieurs
champs comme clé primaire ;
syntaxe : CONSTRAINT nomContrainteCléPrimaire
PRIMARY KEY ( champ1 ,champ2 , … , champN )
– FOREIGN KEY : contrainte qui permet de désigner un ou plusieurs
champs comme clé étrangère ;
syntaxe : CONSTRAINT nomContrainteCléEtrangère
FOREIGN KEY ( champCléEtrangère )
REFERENCES tableCible ( champCléPrimaire )

ALTER TABLE table : modifie la structure de la table "table"


Séquence 4
t ADD : ajoute quelque chose à la structure de la table (champ, contrainte …).
t DROP : retire quelque chose à la structure de la table. Le langage
de description
t ALTER : modifie quelque chose à la structure de la table. des données (LDD)

t RENAME TO : modifie le nom de la table. Page 95


t RENAME : modifie le nom d’un élément de la table (champ, contrainte …).
t COLUMN : la modification concerne un champ.
t TYPE : la modification concerne le type d’un champ.
t SET / DROP NOT NULL : la modification concerne la saisie obligatoire ou
non d’un champ.
t CONSTRAINT : la modification concerne une contrainte.

DROP TABLE table : supprime la table "table"

CREATE VIEW : crée une vue basée sur la requête d’interrogation


fournie

8 2943 TG PA 00
Séquence 5
Le langage de contrôle
de données
Cette séquence va nous permettre d’aborder des problématiques essen-
tiellement sécuritaires avec la gestion des utilisateurs, des accès concur-
rents et du maintien de l’intégrité de la base de données.

X Prérequis
Avoir acquis les connaissances liées aux trois premières parties du langage SQL
(LID, LMD, LDD).

X Capacités attendues en fin de séquence


Être capable d’effectuer une gestion d’utilisateurs et de privilèges en SQL.

X Contenu Séquence 5

1. Contexte d’étude (évolution) ............................................................. 98 Le langage


de contrôle
2. Le contrôle des données dans les révisions de SQL ........................ 101 de données (LCD)
3. La gestion des utilisateurs en SQL ................................................... 101
4. Les rôles ............................................................................................ 102 Page 97

5. Les privilèges .................................................................................... 107

..........................................................................................................
Synthèse 117

8 2943 TG PA 00
1. Contexte d’étude (évolution)
Nous allons continuer à étudier un commerce de proximité de type "supérette". Par
rapport aux séquences précédentes, son schéma a légèrement évolué car, d’une part la
supérette s’est agrandie et a ouvert des magasins à Nice et à Marseille (la supérette de
Toulon est donc devenue le siège social), et, d’autre part, elle propose désormais à ses
clients un catalogue de meubles qu’ils peuvent commander (l’achat en magasin n’est pas
possible).

Schéma conceptuel de la base de données "magasin"


LOT ARTICLE RAYON
idLot
1,1 Placer 0,n
idArticle idRayon
(1,1) Appartenir 1,n
dateFabrication libelle libelle
dateLivraison prix
datePeremption packaging
MARQUE
uniteMesure
1,1 1,1 0,n idMarque
quantite Être
Livrer bio nom

0,n
0,n
Séquence 5 ACHAT
FOURNISSEUR ListeCourses 1,n
idAchat
Le langage
de contrôle idFournisseur quantite dateAchat
de données (LCD) raisonSociale montantTotal
adresseRue
Page 98 adresseCP Évolution du système d'information
adresseVille
email CLIENT 0,1
numeroTelephone idClient
distanceKm Effectuer
nom 1,n
prenom
dateDeNaissance
email
newsletter
ristourne VENDEUR
MEUBLE idVendeur
0,n
idMeuble nomV
descMeuble prenomV
Passer
prixMeuble 0,n
qteDispo

0,n 1,1
COMMANDE Prendre
LigneCde 1,1
1,n idCommande
qteCde dateComm
totalCde

8 2943 TG PA 00
Diagramme de classes de la base de données "magasin"

LOT ARTICLE RAYON


idLot 1..* 1 idArticle * 1 idRayon
dateFabrication libelle libelle
dateLivraison prix
datePeremption packaging
uniteMesure
* quantite
* 1 MARQUE
bio
1 idMarque
1..* nom
FOURNISSEUR
idFournisseur
raisonSociale LISTECOURSES
adresseRue
quantite
adresseCP
adresseVille ACHAT
email idAchat
numeroTelephone * dateAchat
distanceKm montantTotal Séquence 5

Le langage
1..* de contrôle
de données (LCD)
Évolution du système d'information
0..1
Page 99
VENDEUR CLIENT

idVendeur idClient
MEUBLE nomV nom
prenomV prenom
idMeuble dateDeNaissance
decsMeuble 1..* email
prixMeuble 1
newsletter
qteDispo ristourne

1
*
* COMMANDE

LIGNECDE idCommande
*
qteCde dateComm
totalCde

8 2943 TG PA 00
Schéma relationnel de la base de données "magasin"
FOURNISSEUR (idFournisseur, raisonSociale, adresseRue,
adresseCP,adresseVille, email, numeroTelephone,
distanceKm)
idFournisseur : Clé primaire
LOT (idLot, idArticle, dateFabrication, dateLivraison,
datePeremption, idFournisseur)
idLot, idArticle : Clé primaire
idArticle : Clé étrangère en référence à idArticle de article
idFournisseur : Clé étrangère en référence à idFournisseur de
fournisseur
ARTICLE (idArticle, libelle, prix, packaging, uniteMesure,
quantite, bio, idMarque, idRayon)
idArticle : Clé primaire
idMarque : Clé étrangère en référence à idMarque de marque
idRayon : Clé étrangère en référence à idRayon de rayon
RAYON (idRayon, libelle)
idRayon : Clé primaire
MARQUE (idMarque, nom)
Séquence 5
idMarque : Clé primaire
LISTECOURSES (idArticle, idAchat, quantite)
Le langage
de contrôle idArticle, idAchat : Clé primaire
de données (LCD) idArticle : Clé étrangère en référence à idArticle de article
idAchat : Clé étrangère en référence à idAchat de achat
Page 100
ACHAT (idAchat, dateAchat, montantTotal)
idAchat : Clé primaire
CLIENT (idClient, nom, prenom, dateDeNaissance, email,
ristourne)
idClient: Clé primaire
COMMANDE (idCommande, dateComm, totalCde, idVendeur, idClient)
idCommande: Clé primaire
idVendeur : Clé étrangère en référence à idVendeur de vendeur
idClient : Clé étrangère en référence à idClient de client
VENDEUR (idVendeur, nomV, prenomV)
idVendeur: Clé primaire
MEUBLE (idMeuble, descmeuble, prixMeuble, qteDispo)
idMeuble: Clé primaire
LIGNECDE (idMeuble, idCommande, qteCde)
idMeuble, idCommande : Clé primaire
idMeuble : Clé étrangère en référence à idMeuble de meuble
idCommande : Clé étrangère en référence à idCommande de
commande

8 2943 TG PA 00
2. Le contrôle des données dans les révisions de SQL
Dès la première version de la norme SQL, les problématiques de sécurité et de gestion
des utilisateurs ont été abordées, mais, au départ, la décision prise par l’ISO a été de
laisser la spécification des commandes définissant les utilisateurs aux concepteurs de
chaque SGBDR.
tSQL-89 : gestion de "privilèges" et attributions avec l’instruction "GRANT". À ce
niveau, SQL permet de limiter l’utilisation de certaines instructions (CREATE, SELECT,
INSERT, UPDATE, DELETE) à des utilisateurs sur l’intégralité du SGBDR, d’une base ou
d’une table spécifique. Toutefois, chaque attribution de privilèges ne peut porter
que sur un objet à la fois (une seule base, ou une seule table).
tSQL-92 : une nouvelle instruction "REVOKE" permet de retirer des privilèges, de
nouvelles instructions peuvent être limitées (DROP, ALTER) et l’on peut désormais
limiter plus finement certaines instructions (SELECT, INSERT, UPDATE) à une liste
restreinte de colonnes.
tSQL-99 : une nouvelle instruction permettant de limiter l’utilisation des clés étran-
gères fait son apparition (REFERENCES) ainsi qu’une instruction pour limiter la
création de déclencheur (TRIGGER). De plus, c’est à cette révision que l’on voit
apparaître des instructions normalisées de création de "rôles".
Les révisions suivantes n’apportent rien de plus, ce qui n’a pas empêché les éditeurs
d’implémenter davantage d’instructions (TRUNCATE, EXECUTE, CONNECT …).
Séquence 5

Le langage
3. La gestion des utilisateurs en SQL de contrôle
de données (LCD)

Comme on vient de le voir, jusqu’à la révision SQL-99, la gestion des utilisateurs reposait Page 101
entièrement sur les concepteurs de SGBDR. C’est pourquoi il est courant de trouver l’ins-
truction non normalisée "CREATE USER" en lieu et place de l’instruction "CREATE ROLE"
que certains éditeurs n’ont même pas encore intégrée dans leur produit.
La question que l’on peut se poser c’est : pourquoi proposer la notion de "rôle" plutôt
que celle d’"utilisateur"? Simplement parce que SQL considère que ce ne sont pas des
utilisateurs (au sens humain) qui vont se connecter au SGBDR, mais des applications
clientes avec des permissions bien définies.
Par exemple, une application qui sert à consulter le contenu d’une base de données doit-
elle utiliser un compte lui permettant de faire autre chose que du "SELECT"? La réponse
est, bien évidemment, non. En informatique, il ne faut jamais commettre l’imprudence
de réfléchir avec le vieil adage "Qui peut le plus, peut le moins": c’est une erreur ! Il faut
au contraire toujours préférer appliquer la politique du moindre privilège : un processus
ne dispose que des privilèges nécessaires à l’exécution d’un travail donné.

Bien que l’instruction "CREATE USER" n’existe pas dans la norme SQL, nous allons tout
de même nous en servir, car elle a le mérite d’exister chez quasiment tous les éditeurs de
SGBDR alors que l’instruction "CREATE ROLE", bien que normalisée, n’existe pas partout.
MySQL, par exemple, ne la prend pas en charge. PostgreSQL, de son côté, a transformé
l’instruction "CREATE USER" en alias de "CREATE ROLE", collant ainsi au plus près à la
norme SQL. Mais c’est le seul rapprochement, car la norme ne fournit pas toutes les
options rattachées à cette instruction (mot de passe, date d’expiration d’un compte …).
D’une manière générale, nous allons voir des instructions qui ne sont pas dans la norme,

8 2943 TG PA 00
car, encore une fois, la spécification des commandes liées aux utilisateurs a été volontai-
rement laissée aux éditeurs des SGBDR. La suite des instructions sera donc très "orientée
PostgreSQL".

À partir de maintenant, lorsque vous verrez ce logo, cela signifiera


SQL
que les instructions sont conformes à la norme SQL.

En l’absence de ce logo, cela signifiera que les instructions ne sont pas dans la norme SQL
mais qu'elles sont propres à PostgreSQL, voire, lorsque c’est signalé, à un autre SGBDR.

4. Les rôles
Dans un projet d’informatisation qui inclut une base de données, les utilisateurs d’une
base de données sont identifiés lors de la phase d’analyse.

Les utilisateurs
Les utilisateurs, appelés "rôles de connexion" sous PostgreSQL, permettent de res-
treindre l’accès au SGBDR aux seuls utilisateurs déclarés.
tPrenons l’exemple du comptable, M. Luca Pacioli. Il doit pouvoir se connecter à la
base de données. Nous allons donc lui créer un compte :
Séquence 5 CREATE ROLE lpacioli
SQL LOGIN PASSWORD 'motdepasse'
Le langage
de contrôle
de données (LCD)
tSous PostgreSQL, on peut également utiliser la commande suivante :

Page 102 CREATE USER lpacioli


LOGIN PASSWORD 'motdepasse'

Pour créer un utilisateur graphiquement sous pgAdmin, il nous suffit d’utiliser la gestion
des "rôles de connexion" présente dans l’organisation graphique :

Les rôles
Les rôles, appelés "rôles de groupe" sous PostgreSQL, permettent de regrouper des uti-
lisateurs amenés à partager les mêmes autorisations.
tImaginons, par exemple, que le comptable ait 2 assistants (Harry Cover et Lara
Tatouille) qui devront avoir les mêmes droits d’accès que lui. Nous allons donc créer
un rôle "compta" et y rattacher nos 3 utilisateurs (créés au préalable) :

8 2943 TG PA 00
CREATE ROLE compta
SQL
GRANT compta
TO lpacioli , hcover , ltatouille

tSous PostgreSQL, on peut également utiliser la commande suivante :


CREATE ROLE compta
WITH ROLE lpacioli , hcover , ltatouille

Pour créer un "groupe" graphiquement sous pgAdmin, il nous suffit d’utiliser la gestion
des "rôles de groupe" présente dans l’organisation graphique :

Comme nous l’avons vu, les "rôles" n’ont fait leur apparition qu’à partir de SQL-99. Or,
avec une grande quantité d’utilisateurs, il était évident que les éditeurs se tourneraient
vers une gestion proche de celle que l’on trouve sur les systèmes d’exploitation, à savoir
une gestion par groupes, représentatifs de l’organisation de l’entreprise. Sans attendre
que la norme prenne en compte leurs besoins, les éditeurs de SGBDR ont alors intégré
la gestion de groupes. C’est pourquoi il est courant de trouver la commande "CREATE Séquence 5
GROUP", ainsi que la commande "ALTER GROUP … ADD USER" pour pouvoir ajouter
Le langage
des utilisateurs : de contrôle
de données (LCD)
CREATE GROUP compta
Page 103
ALTER GROUP compta
ADD USER lpacioli , hcover , ltatouille

La modification de rôle
La norme SQL fournit l’instruction de création (et de destruction, que nous verrons plus
loin), mais pas de modification. Les SGBDR intègrent tout de même une instruction per-
mettant d’effectuer les modifications suivantes :
tOn souhaite, par exemple, renommer le rôle "compta" en "compta_consult":
ALTER ROLE compta
RENAME TO compta_consult
tSi l’on souhaite changer le mot de passe du comptable :
ALTER ROLE lpacioli
WITH LOGIN PASSWORD 'nouveau_pass'

Tout ce qui touche à un rôle peut être modifié avec l’instruction "ALTER ROLE", à l’ex-
ception de la gestion des appartenances pour laquelle l’on devra utiliser les instructions
"GRANT" et "REVOKE" (que nous allons voir un peu plus loin).

8 2943 TG PA 00
Pour modifier un "rôle" graphiquement sous pgAdmin,
il nous suffit d’utiliser les propriétés du rôle ciblé (clic
droit sur le rôle, puis "Propriétés"). Par exemple, ici, il
suffira de saisir le nouveau mot de passe et sa confir-
mation :

Endosser un rôle en cours de session


Abordée en début de chapitre, la politique de sécurité
du "moindre privilège" est utilisée dans tous les sys-
tèmes informatiques qui nécessitent un minimum de
sécurité et de traçabilité. On peut prendre l’exemple de
son système d’exploitation. En fonctionnement normal,
on utilise un compte utilisateur avec uniquement des
permissions qui nous permettent de travailler. Mais, pour des tâches particulières, on
peut être amené à nécessiter des autorisations spécifiques :
tsous Windows, soit il faut utiliser le "Exécuter en tant qu’autre utilisateur" dans le
menu contextuel des programmes à lancer, soit il arrive que le système nous le pro-
pose automatiquement lorsqu’il faut des droits d’administration pour réaliser une
opération particulière (la mise à jour d’un logiciel par exemple) ;
tsous Linux, soit il faut utiliser la commande "sudo 24" ("gksudo" en graphique), soit
comme sous Windows, il arrive que le système nous le propose automatiquement
lorsqu’il faut des droits d’administration pour réaliser une opération particulière (la
Séquence 5 mise à jour d’un logiciel par exemple).
Le langage Cela permet de protéger le système des accidents (ainsi que des actions malveillantes).
de contrôle Par exemple, sous Linux, si un utilisateur maladroit qui souhaite supprimer des fichiers
de données (LCD)
lance cette commande "rm -f *" 25, elle aura pour effet de supprimer tous les fichiers lui
appartenant dans le dossier où il se trouve. Cela peut être ennuyeux pour lui, mais la
Page 104
portée de sa "bêtise" se limitera à "ses" fichiers et n’affectera pas les fichiers des autres
utilisateurs. On imagine aisément la catastrophe si cet utilisateur travaillait avec un
compte d’administration ("root", par exemple).
SQL-99 a normalisé la gestion des rôles dans le but de limiter le plus finement possible
les actions que peut réaliser une application ou un utilisateur. Bien que la norme aborde
la possibilité de changer de rôle en cours de session, elle n’a pas fourni d’instruction nor-
malisée, laissant encore une fois cette spécification aux éditeurs de SGBDR. Ces derniers
s’inspirant de ce qui est fait sur les systèmes d’exploitation ont implémenté leurs propres
"sudo" avec l’instruction SQL "SET ROLE".
tAdmettons que nous soyons connectés à l’aide du rôle "compta_consult" et que
nous ayons besoin de prendre temporairement le rôle de "compta_miseajour". Il
nous suffit de saisir cette commande :
SET ROLE compta_miseajour

Dès lors, les instructions suivantes seront réalisées sous l’identité du rôle "compta_mise-
jour". Nous venons de voir le cas classique où nous récupérons des droits supplémen-

24. Cette instruction, qui est l’acronyme anglais de "Substitute User DO", permet d’exécuter une opération en
substituant son identité à celle d’un autre utilisateur.
25. Pour rappel, la commande "rm" permet de supprimer des fichiers (ReMove) et le paramètre "-f", quant à
lui, permet de lancer une suppression sans demander de confirmation.

8 2943 TG PA 00
taires en substituant son identité à celle d’un rôle plus "privilégié". Il faut savoir que la
démarche inverse est également possible.
tSupposons que l’on se soit connecté avec le compte "postgres" (administrateur du
SGBDR PostgreSQL) et que l’on veuille vérifier ce que peut voir l’utilisateur "lpacio-
li". Il nous suffit d’exécuter la commande suivante pour récupérer provisoirement
l’identité de "lpacioli":
SET ROLE lpacioli

tPour retrouver ensuite son identité de départ, il suffit d’exécuter la commande


suivante :
RESET ROLE

Pour pouvoir changer d’identité graphiquement sous pgAdmin, il faut nous déconnecter,
changer les propriétés de la connexion, puis nous reconnecter avec l’identité désirée. Et
recommencer ensuite pour retrouver son identité de départ :

Î Î

Séquence 5

Le langage
de contrôle
de données (LCD)

Page 105

Cet exemple démontre encore une fois que la connaissance du SQL peut représenter sans
aucun doute un formidable gain de temps !

Supprimer un rôle
Comme dans toute gestion d’utilisateur, il peut arriver que l’on ait à supprimer des
comptes. SQL-92 définit la suppression de rôle avec l’instruction "DROP ROLE".
tPrenons l’exemple d’une application de comptabilité remplacée par un nouveau
produit. Jusqu’alors, cette application utilisait les rôles "pgi_consult" et "pgi_misea-
jour" pour travailler avec une base de données de notre organisation. L’arrêt d’uti-
lisation de cette application entraîne également la suppression de ses rôles dont
l’existence n’est plus justifiée :
DROP ROLE pgi_consult
SQL

DROP ROLE pgi_miseajour

8 2943 TG PA 00
tSous PostgreSQL, on peut également supprimer plusieurs rôles dans la même com-
mande, ce que ne permet pas la norme SQL :
DROP ROLE pgi_consult , pgi_miseajour

Pour pouvoir supprimer un rôle graphique-


ment sous pgAdmin, il suffit de cliquer sur le
rôle ciblé avec le bouton droit et de choisir
"Supprimer":

Clauses prédéfinies dans PostgreSQL


tPostgreSQL (comme d’autres SGBDR) a apporté la possibilité de gérer ses utilisateurs
d’une manière plus aisée en proposant des clauses particulières utilisables lors de
la création des rôles ("CREATE ROLE") ou lors de la modification ("ALTER ROLE"). Il
suffit d’adjoindre la clause "WITH" aux clauses suivantes :
– "SUPERUSER": spécifie si le rôle est un administrateur ;
– "CREATEDB": spécifie si le rôle peut créer des bases de données ("CREATE
DATABASE") ;
– "CREATEROLE": spécifie si le rôle peut à son tour créer des rôles ;
Séquence 5 – "NOINHERIT": spécifie si un rôle ne doit pas hériter des droits d’un rôle dont
il est membre ;
Le langage
de contrôle – "LOGIN PASSWORD": comme on l’a vu précédemment, cette clause (suivie
de données (LCD) d’un mot de passe) spécifie si le rôle est un "rôle de connexion" (peut alors
être vu comme un "utilisateur") ;
Page 106 – "VALID UNTIL": suivie d’une date, cette clause permet de spécifier une date
d’expiration à un rôle ;
Sous pgAdmin, la plupart de ces clauses sont visibles dans les deux premiers onglets lors
de la création d’un rôle :

8 2943 TG PA 00
tPar exemple, si l’on veut créer un rôle "stagiaire" qui expirera automatiquement le
1er juin 2012 :
CREATE ROLE stagiaire
WITH LOGIN PASSWORD 'motdepasse'
VALID UNTIL '2012-06-01'

Notons toutefois que passé la date d’expiration le compte n’est pas supprimé. La
connexion avec ce dernier est certes impossible, mais rien n’empêche son utilisation avec
la commande "SET ROLE".

tSi l’on souhaite créer un nouvel administrateur nommé "admin_bis":


CREATE ROLE admin_bis
WITH LOGIN PASSWORD 'motdepasse'
SUPERUSER

Attention, d’une part la norme SQL recommande de n’avoir qu’un seul rôle d’admi-
nistrateur et d’autre part, comme on l’a vu précédemment, il est fortement déconseillé
de travailler en "superuser". C’est pourquoi une bonne pratique consiste à utiliser un
compte qui dispose des droits "CREATEDB" et "CREATEROLE", mais qui ne soit pas un
"superuser". Cela permet encore une fois de respecter la politique de sécurité du "moindre
privilège" et ainsi d’éviter les dangers encourus en travaillant avec un compte ne se limi-
tant pas aux privilèges nécessaires pour la réalisation d’une tâche donnée. Il vaut donc Séquence 5
mieux créer notre "admin_bis" avec la commande suivante :
Le langage
de contrôle
CREATE ROLE admin_bis de données (LCD)
WITH LOGIN PASSWORD 'motdepasse'
CREATEDB Page 107
CREATEROLE

5. Les privilèges
La création des utilisateurs nous a permis de gérer les connexions au SGBDR. Nous allons
maintenant voir comment gérer l’accès aux données.

Accorder des privilèges à des utilisateurs


tLes privilèges "normalisés" ne concernent que les tables et les vues :
– "SELECT" pour l’interrogation ;
– "INSERT" pour l’insertion ;
– "UPDATE" pour la mise à jour ;
– "DELETE" pour la suppression ;
– "REFERENCES" pour la manipulation de clés étrangères.
tSauf le privilège suivant qui n’est pas applicable aux vues :
– "TRIGGER" pour la création de déclencheurs.

8 2943 TG PA 00
SQL nous fournit le privilège "ALL PRIVILEGES" qui est censé regrouper tous les pri-
vilèges précédents. Seulement, il faut faire attention, car, encore une fois, les éditeurs
sont allés beaucoup plus loin en implémentant des privilèges et des objets recouvrant
toutes les problématiques du SGBDR (création de bases de données, création de rôles,
lancement de procédures …) :
GRANT ...
ON DATABASE
FUNCTIONS
LANGUAGE
...
En utilisant "ALL PRIVILEGES", le risque est donc de donner beaucoup plus de privi-
lèges que prévu, et, surtout, de donner des privilèges outrepassant la simple gestion de
tables ou de vues. Cela ne permet toutefois pas de donner le privilège de transmettre
des privilèges (voir ci-après).
SQL nous fournit également l’option "GRANT OPTION" qui se place à la fin de l’ins-
truction et qui permet à celui qui reçoit ce privilège de pouvoir le transmettre à son tour.
En d’autres termes, cela permet à un rôle de donner des privilèges à d’autres rôles sur
les mêmes objets. C’est le seul privilège qui ne soit pas inclus dans "ALL PRIVILEGES".

tNous allons, par exemple, autoriser le comptable à consulter et à mettre à jour les
tables "fournisseur" et "lot":
GRANT SELECT , UPDATE
Séquence 5 SQL ON fournisseur
TO lpacioli
Le langage
de contrôle
de données (LCD)
GRANT SELECT , UPDATE
ON lot
Page 108 TO lpacioli
SQL n’autorisant pas l’attribution de droits sur plus d’une table par commande, la mise
en place de privilèges sur un nombre important de tables peut rapidement se révéler fas-
tidieuse. L’ayant bien compris, les éditeurs de SGBDR ont rapidement conçu une parade
en étendant l’instruction "GRANT" pour lui permettre d’accepter l’attribution de droits
sur plusieurs tables simultanément. Les 2 commandes précédentes peuvent donc être
regroupées en une seule sur la plupart des SGBDR :
GRANT SELECT , UPDATE
ON fournisseur , lot
TO lpacioli
Comme on vient de le voir, les privilèges sont
attribués sur des tables. Graphiquement, ce
sont donc les propriétés des tables qu’il faudra
modifier pour pouvoir effectuer de l’attribu-
tion de privilèges :

8 2943 TG PA 00
Attention, pgAdmin ne permet pas d’attribuer des privilèges à des "rôles de connexion".
Il faut obligatoirement passer par un rôle de groupe, ou alors le faire en SQL !

Accorder des privilèges à des rôles


tOn souhaite que le "rôle compta" puisse consulter et mettre à jour les tables "four-
nisseur" et "lot":
GRANT SELECT , UPDATE
SQL ON fournisseur
TO compta

GRANT SELECT , UPDATE


ON lot
TO compta
tComme précédemment, on peut également regrouper ces 2 commandes en une
seule dans la plupart des SGBDR :
GRANT SELECT , UPDATE
ON fournisseur , lot
TO compta

SQL nous permet d’utiliser le rôle générique "PUBLIC" qui désigne tous les rôles du Séquence 5
SGBDR. Ce qui veut dire que l’on peut attribuer le droit en "lecture" sur la table "article"
Le langage
à tous les utilisateurs du SGBDR : de contrôle
de données (LCD)
GRANT SELECT
SQL ON article Page 109
TO PUBLIC

Le rôle générique "PUBLIC" est également


accessible graphiquement depuis pgAdmin :

8 2943 TG PA 00
Accorder des privilèges sur des colonnes
Comme on l’a vu précédemment, bien que l’instruction "GRANT" existe depuis SQL-89,
ce n’est qu’avec l’arrivée de SQL-92 que l’on a pu restreindre des privilèges à une partie
d’une table ou d’une vue.
tPar exemple, si l’on souhaite autoriser le rôle "secretariat" à consulter l’intégralité
de la table "fournisseur", mais à ne pouvoir mettre à jour que les colonnes "email"
et "numeroTelephone":
GRANT SELECT , UPDATE (email , numeroTelephone)
SQL ON fournisseur
TO secretariat

Retirer des privilèges


Arrivée avec SQL-92, l’instruction "REVOKE" permet de retirer des droits précédemment
attribués.
tOn souhaite, par exemple, retirer le droit de mise à jour sur la table "lot" au comp-
table "lpacioli":
REVOKE UPDATE
SQL ON lot
FROM lpacioli

Séquence 5
Attention, un rôle (ou un utilisateur, qui, rappelons-le, est également un rôle) possède :
Le langage s la somme des droits qui lui ont été donnés directement ;
de contrôle s la somme des droits qui ont été donnés à un rôle dont il est membre.
de données (LCD)
Ce qui veut dire qu’ici, si "lpacioli" est bien membre du rôle "compta", il continue de
bénéficier du privilège "UPDATE" sur la table "lot". Donc, ici, si l’on veut lui retirer le
Page 110 droit de mise à jour sur la table "lot", il faudra également le retirer du groupe "compta"
avec la commande suivante :

REVOKE compta
SQL FROM lpacioli

Après cela, il ne lui restera que les droits qui le concernent individuellement.

Exercice 1
À partir de l’explication suivante, mettre en place les rôles et privilèges nécessaires
pour prendre en compte tous les besoins :
t2 vendeurs "Alice" et "Bernard" qui doivent pouvoir prendre en compte des
commandes de meubles par des clients.
t3 comptables "lpacioli", "hcover" et "ltatouille" qui doivent pouvoir insérer de
nouveaux fournisseurs et mettre à jour les prix de tous les articles et meubles de
la base de données.

8 2943 TG PA 00
Exercice 2

Extrait du cas ASDOMI (Nouvelle-Calédonie, 2010)


L’ASDOMI est une association qui gère un service de soins infirmiers à domicile
(SSIAD) dans le département de l’Ain. Sa mission est de permettre le maintien à
domicile de personnes dépendantes ou âgées.
L’ASDOMI dispose d’une capacité d’accueil de 96 lits et reçoit une dotation annuelle
globale de la DASS (Direction des Affaires Sanitaires et Sociales) calculée en fonction
du nombre de lits (nombre maximal de patients pouvant être pris en charge simul-
tanément).
L’activité de l’ASDOMI est supervisée par la CPAM (Caisse Primaire d’Assurance
Maladie) de l’Ain, dite "caisse pivot", qui accorde les demandes d’entente préalable
pour la prise en charge des soins et effectue des contrôles.
Pour mener à bien sa mission, l’ASDOMI emploie 35 aides-soignants, 3 infirmières
coordinatrices, une secrétaire, une comptable et une directrice. Elle peut aussi recou-
rir à des prestataires libéraux (infirmiers, pédicures, etc.) pour des soins spécialisés.
Pour faire face à l’explosion prévue des services à la personne, recentrer les aides-
soignants sur leur cœur de métier et répondre aux exigences de qualité définies par
la DASS, l’ASDOMI a décidé de refondre son système d’information devenu obsolète
et a, pour cela, fait appel à une société de service et d’ingénierie informatique (SSII).
Vous faites partie de l’équipe de la SSII chargée de cette mission. Séquence 5
Toutes les semaines, la directrice élabore la tournée des aides-soignants qui inter-
Le langage
viennent au domicile des patients. Les aides-soignants empruntent un véhicule de de contrôle
l’ASDOMI pour leurs déplacements. de données (LCD)

L’association s’est équipée d’un système de télégestion : les aides-soignants sont


Page 111
munis d’un assistant personnel qui leur permet de saisir leurs interventions et de les
transférer à leur retour au siège de l’association. Ils disposent pour cela chacun d’un
compte utilisateur afin de mettre à jour les données concernant les interventions
réalisées.
Les données sont mémorisées dans une base de données (annexe 2A) qui sert au
calcul de la paie et à l’élaboration de diverses statistiques.
Le SGBDR fournit des fonctions sur les données de type date et heure (annexe 2A).

Travail à faire
Écrire les ordres SQL permettant d’autoriser tous les utilisateurs de la base de don-
nées à consulter la table INTERVENTION et l’utilisateur d’identifiant RDeltour à faire
toute insertion, modification ou suppression de données sur cette même table.

8 2943 TG PA 00
Annexe 2 Schéma relationnel de la base de données des tournées

DOSSIER (numéro, nom, prénom ...)


numéro : clé primaire
Relation qui regroupe les informations concernant les dossiers d’admission. Tous les
attributs ne sont pas présentés ici.

SALARIE (matricule, nom, prénom ...)


matricule : clé primaire
Relation qui regroupe les informations concernant les membres du personnel. Tous
les attributs ne sont pas présentés ici.

VEHICULE (numéro, noImmat, marque, catégorie, dateAcquisition)


numéro : clé primaire
Relation qui regroupe les informations concernant les véhicules du SSIAD.

INTERVENTION (dateIntervention, heureDébut, matriculeSalarié, duréeInterven-


tion, nbKm, noDossier, noVéhicule)
dateIntervention, heureDébut, matriculeSalarié : clé primaire
matriculeSalarié : clé étrangère en référence à matricule de
SALARIE noDossier : clé étrangère en référence à numéro de
DOSSIER
Séquence 5
noVéhicule : clé étrangère en référence à numéro de VEHICULE
Le langage
Relation qui regroupe les informations concernant les tournées.
de contrôle
de données (LCD) Les colonnes heureDébut, duréeIntervention représentent respectivement l’heure de
début et la durée en minutes de l’intervention au domicile d’un patient. La colonne
Page 112 heureDébut est de type TIME qui correspond au format 'hh:mm:ss’.
La colonne nbKm représente le nombre de kilomètres parcourus par l’aide-soignant
pour se rendre au domicile du patient.
Toutes les clés étrangères sont des entiers.

8 2943 TG PA 00
Exercice 3
Extrait du cas EPOKA (Métropole, 2004)
EPOKA PRESSE est une société de presse qui conçoit, réalise et publie des magazines
vendus sur tout le territoire français (métropole et DOM-TOM). Le dernier titre mis
sur le marché par EPOKA PRESSE est le magazine mensuel Savoir vendre. Ce maga-
zine très spécialisé vise un public de vendeurs qu’il a pour objectif de conseiller dans
l’exercice de leur métier.
EPOKA PRESSE souhaite se doter d’un intranet pour assurer une meilleure coopé-
ration et une communication plus rapide entre les différents acteurs (rédacteurs,
pigistes, maquettistes) participant à l’élaboration de ses publications. La revue Savoir
vendre a été choisie pour expérimenter cette nouvelle forme de travail. Vous avez
été recruté(e) afin de participer au développement de cet intranet ainsi qu’à celui de
plusieurs applications de gestion permettant de mieux exploiter la revue.
Vocabulaire utilisé :
tOn emploie indifféremment les termes "magazine" et "revue".
tUn(e) pigiste est une personne qui écrit des articles et qui est payée "à la pige",
c’est-à-dire à l’article.
tUn feuillet est un ensemble de 1 500 signes ou caractères alphanumériques. La
longueur d’un article s’exprime en nombre entier de feuillets (on arrondit au
nombre entier le plus proche).
Séquence 5
tLe chapeau d’un article est un texte court qui présente succinctement le conte-
nu de l’article. Le langage
de contrôle
tMettre en ligne un article sur l’intranet signifie le rendre accessible en lec- de données (LCD)
ture à tous les utilisateurs de l’intranet.
tPublier un article dans le magazine signifie insérer cet article dans un Page 113
numéro précis du magazine.
Les magazines édités par EPOKA PRESSE sont distribués par une entreprise de diffu-
sion qui assure aussi le retour des invendus.
EPOKA PRESSE gère les invendus à l’aide d’une base de données dont le schéma
relationnel est présenté en annexe 3. Un taux d’invendus (TI) est calculé pour chaque
point de vente à partir du nombre d’exemplaires reçus (NR) et du nombre d’exem-
plaires vendus (NV) par le point de vente.
TI = (NR-NV) / NR

Travail à faire
Écrire en langage SQL les requêtes permettant de supprimer tous les anciens droits
sur les tables NUMERO ET VENTE pour le compte utilisateur REDACT et donner à ce
compte les droits de suppression, d’insertion, de consultation, de mise à jour sur la
table NUMERO et uniquement le droit de consultation sur la table VENTE.

8 2943 TG PA 00
Annexe 3 Extrait du schéma relationnel de la base "Diffusion"

REVUE (CodeR, TitreR, Thème, PaginationMaxi)


CodeR : clé primaire
Exemple : la revue Savoir vendre codée "SV", dont le thème principal est "techniques
de vente", a une pagination maximale de 204 pages.

POINTVENTE (NoPoint, NomDép, MélRespon)


NoPoint : clé primaire
Exemple : le point de vente du numéro 44 se trouve dans le département de la
"Loire-Atlantique" et son responsable a comme adresse électronique "paul.dupont@
laposte.net".

NUMERO (CodeN, CodeR, NbePages, Tirage, DateParution, DateRetour, NbeInv)


CodeN : clé primaire
CodeR : clé étrangère en référence à CodeR de REVUE
Exemple : le numéro codé "020V" de la revue codée "SV" compte 152 pages ; il a
été tiré à 25 000 exemplaires ; il est paru le samedi 14 février 2004 ; les exemplaires
invendus devaient être retournés pour le samedi 20 mars 2004 ; le nombre d’inven-
dus est connu : il est égal à 3 054.

VENTE (NoPoint, CodeN, NbeReçu, NbeVendu)


Séquence 5
NoPoint, CodeN : clé primaire
Le langage NoPoint : clé étrangère en référence à NoPoint de POINTVENTE
de contrôle CodeN : clé étrangère en référence à CodeN de NUMERO
de données (LCD)
Exemple : le point de vente du numéro 44 a reçu le numéro codé "020V" en
Page 114 180 exemplaires ; 153 exemplaires ont ensuite été réellement vendus.

8 2943 TG PA 00
Exercice 4
Extrait du cas JMS (Métropole, 2002)
La société JMS est une unité d’entretien agréée par le Groupement de Sécurité de
l’Aviation Civile (GSAC), administration chargée, en France, de la sécurité dans le
domaine aéronautique. JMS assure la maintenance des avions pour le compte de
plusieurs aéro-clubs.
La société JMS emploie du personnel administratif et des mécaniciens. Elle dispose
d’un atelier où sont réceptionnés les avions acheminés là pour y subir leurs visites
d’entretien, programmées régulièrement. Un magasin jouxte l’atelier et permet aux
mécaniciens de disposer immédiatement des pièces détachées utiles à leurs interven-
tions.
Toutes les interventions sur les avions donnent lieu à la rédaction des documents
exigés par le GSAC.
On considère la base de données "AERO" où sont enregistrées les interventions réa-
lisées dans le cadre de l’entretien des avions. Elle a été conçue à partir des schémas
de relation suivants :

AEROCLUB (CodeClub, Nom, Rue, CP, Ville, Tel)


CodeClub : clé primaire

AVION (CodeAvion, Modele, Constructeur, CodeClub)


Séquence 5
CodeAvion : clé primaire
CodeClub : clé étrangère en référence à CodeClub de AEROCLUB Le langage
de contrôle
de données (LCD)
INTERVENTION (CodeInt, Libelle, Type)
CodeInt : clé primaire
Page 115
SUBIR (CodeAvion, CodeInt, Date, NbHeures, Montant)
CodeAvion, CodeInt, Date : clé primaire
CodeAvion : clé étrangère en référence à CodeAvion de AVION
CodeInt : clé étrangère en référence à CodeInt de INTERVENTION.

Travail à faire
Écrire en langage SQL les requêtes permettant d’autoriser la nouvelle secrétaire,
dont le compte vient d’être ouvert sous le nom d’utilisateur "MONIQUE", à autoriser
toutes les opérations sur la table SUBIR et, lui interdire toute intervention, sauf la
sélection sur les autres tables.

8 2943 TG PA 00
Exercice 5
Extrait du cas SECOLOG (Métropole, 2001)
SECOLOG (Société Européenne de Conception de Logiciel) est une SSII spécialisée
dans le développement d’applications de gestion. Solidement implantée au niveau
régional, elle regroupe une quinzaine de personnes occupant des bureaux situés
dans un immeuble récent. L’activité de l’entreprise est centrée autour de 3 pôles
d’activité :
tLe développement d’applications.
tLe support technique apporté aux clients.
tLa formation des utilisateurs.
L’entreprise emploie 6 développeurs, un commercial, 2 techniciens, une secrétaire
polyvalente et 2 formateurs. L’encadrement est assuré par 2 chefs de projet et le
directeur, fondateur de la société.
Concernant la gestion des formations proposées par SECOLOG à ses clients, une
étude a déjà été réalisée et a conduit à la production du schéma relationnel décrit
dans l’annexe 2.

Travail à faire
Rédiger en langage SQL les requêtes correspondant au besoin suivant : autoriser
Séquence 5 l’utilisateur DUPARC à insérer, mettre à jour et supprimer des lignes dans la table
SALARIÉ
Le langage
de contrôle
de données (LCD)
Annexe 2 Schéma relationnel du domaine "Gestion des formations"
Page 116
SALARIÉ (Matricule, NomSalarié, PrénomSalarié, Adr1Salarié, Adr2Salarié, CPSalarié,
VilleSalarié, DateEmbauche)
PRODUIT (CodeProduit, NomProduit)
SPÉCIALISER (Matricule#, CodeProduit#)
FORMATION (CodeForm, LibelléForm, NbMaxStagiaires, CodeProduit#)
SESSION (CodeForm#, NoSession, DateSession, Matricule#)
STAGIAIRE (NoStagiaire, NomStagiaire, PrénomStagiaire, NoClient#)
PARTICIPER (CodeForm#, NoSession#, NoStagiaire#)
CLIENT (NoClient, NomClient, Adr1Client, Adr2Client, CPClient, VilleClient)
Remarques :
tLes clés primaires sont soulignées et les clés étrangères sont suivies du carac-
tère #.
tNbMaxStagiaires désigne le nombre maximum de stagiaires pour une forma-
tion.
tLa clé étrangère Matricule# de la relation SESSION référence le formateur de la
session.
tLa relation CLIENT provient de l’entité CLIENT du domaine "Gestion des pro-
positions commerciales" et représente donc les organisations en relation avec
l’entreprise ; les stagiaires en formation sont issus de ces entreprises.

8 2943 TG PA 00
Synthèse

CREATE ROLE rôle : créer le rôle "rôle"


t WITH : permet de spécifier des options supplémentaires.
– ROLE rôle1, rôle2, …, rôleN : permet de spécifier les utilisateurs (rôle1
à rôleN) qui seront membres de ce nouveau rôle.
– LOGIN PASSWORD 'ChaîneMotDePasse' : spécifie que c’est un "rôle
de connexion" et que son mot de passe est "ChaîneMotDePasse".
– SUPERUSER : spécifie si le rôle est un rôle administrateur.
– CREATEDB : spécifie si le rôle peut créer des bases de données.
– CREATEROLE : spécifie si le rôle peut à son tour créer des rôles.
– NOINHERIT : spécifie si un rôle ne doit pas hériter des droits d’un rôle
dont il est membre.
– VALID UNTIL 'Année-Mois-Jour' : spécifie la date 'Année-Mois-Jour'
comme date d’expiration du rôle.
– GRANT OPTION : spécifie si le rôle peut à son tour donner des privi-
lèges.
ALTER ROLE rôle : modifie le rôle "rôle"
t WITH : permet de spécifier les mêmes options supplémentaires qu’avec le
CREATE. Séquence 5
t RENAME NouveauNom : permet de renommer le rôle en "NouveauNom".
Le langage
SET ROLE AutreRôle : substitue l’identité actuelle à celle de "AutreRôle" de contrôle
de données (LCD)
RESET ROLE : reprend le rôle initial s’il y a eu une substitution avec la
commande "SET ROLE"
Page 117
DROP ROLE rôle : supprime le rôle "rôle"
GRANT rôle : ajoute un ou plusieurs membres au rôle "rôle"
t TO : spécifie les rôles qui deviennent membres du rôle "rôle".
syntaxe : GRANT rôleA , rôleB , … , rôleN
TO rôle1 , rôle2 , … , rôleN
GRANT privilège : octroie un ou plusieurs privilèges ("SELECT", "INSERT",
"UPDATE", "DELETE", "REFERENCES", "TRIGGER")
t ON : spécifie un ou plusieurs objets sur lesquels portent les privilèges
(colonnes, tables, vues, bases de données, procédures stockées, langages …).
t TO : spécifie un ou plusieurs rôles destinataires de ces privilèges.
syntaxe : GRANT privilège
ON objet1 , objet2 , … , objetN
TO rôle1 , rôle2 , … , rôleN
REVOKE rôle : retire un ou plusieurs membres du rôle "rôle"
t FROM : spécifie les rôles qui cessent d’être membres du rôle "rôle".
syntaxe : REVOKE rôleA , rôleB , … , rôleN
FROM rôle1 , rôle2 , … , rôleN

8 2943 TG PA 00
REVOKE privilège : retire un ou plusieurs privilèges ("SELECT", "INSERT",
"UPDATE", "DELETE", "REFERENCES", "TRIGGER")
t ON : spécifie un ou plusieurs objets sur lesquels portent les privilèges
(colonnes, tables, vues, bases de données, procédures stockées, langages …).
t FROM : spécifie un ou plusieurs rôles destinataires de ces privilèges.
syntaxe : REVOKE privilège
ON objet1 , objet2 , … , objetN
FROM rôle1 , rôle2 , … , rôleN

Séquence 5

Le langage
de contrôle
de données (LCD)

Page 118

8 2943 TG PA 00
Séquence 6
Le langage de contrôle
des transactions
À la séquence précédente, nous avons vu comment protéger un
SGBDR en restreignant son accès aux seuls utilisateurs autorisés,
et avec une liste de privilèges restreinte à leurs besoins. Nous al-
lons à présent voir comment veiller à ce que les manipulations
d’un utilisateur ne portent pas préjudice à un autre utilisateur.
Dans cette partie, nous verrons exclusivement du SQL car les différentes
instructions de contrôle des transactions ne sont pas réalisables en gra-
phique.

X Prérequis
Avoir acquis les connaissances liées aux quatre premières parties du langage
SQL (LID, LMD, LDD, LCD) et, de préférence, avoir quelques notions en adminis-
tration des systèmes d’information.
Séquence 6

X Capacités attendues en fin de séquence Le langage


de contrôle
des transactions (LCT)
Être capable de comprendre les risques liés aux accès simultanés et comprendre
également le mécanisme des transactions.
Page 119

X Contenu
1. Accès simultanés, quels sont les risques ? ....................................... 120
2. Les transactions ................................................................................ 123

.........................................................................................................
Synthèse 132

8 2943 TG PA 00
1. Accès simultanés, quels sont les risques ?
Dans la séquence 4, nous avons vu différents procédés nous permettant d’assurer la
cohérence des données (clé primaire avec "PRIMARY KEY", clé étrangère avec "FOREIGN
KEY", existence avec "NOT NULL").
Ces contraintes d’intégrité référentielle sont là pour veiller à ce que les données soient
cohérentes entre elles, mais, avec les accès simultanés aux bases de données par plusieurs
utilisateurs et / ou applications, ces procédés se révèlent insuffisants, car ils ne sont pas
capables d’identifier les incidences que peuvent avoir les manipulations d’un utilisateur
sur les manipulations d’un autre utilisateur.

La lecture "non renouvelable"


Prenons le cas de deux vendeurs, "Alice" et "Bernard", qui sont chacun avec un client
différent. Ils sont tous les deux connectés au SGBDR et effectuent simultanément des
commandes :
tLe client d’Alice souhaite commander 3 tables basses en hêtre référencées "TBH007".
Alice consulte le stock et voit qu’il en reste 3. Elle lance donc la commande ;
tAu même moment, le client de Bernard souhaite commander une table basse en
hêtre référencée "TBH007". Bernard consulte le stock et voit qu’il en reste 3. Il lance
donc la commande.26

Séquence 6 QteDispo
Temps26 Alice Bernard
(TBH007)
Le langage SELECT qteDispo
de contrôle
des transactions (LCT) T FROM meuble 3
WHERE idMeuble = 'TBH007'
Page 120 SELECT qteDispo
T+1 3 FROM meuble
WHERE idMeuble = 'TBH007'
UPDATE meuble
T+2 SET qteDispo = qteDispo - 3 0
WHERE idMeuble = 'TBH007'
UPDATE meuble
T+3 -1 SET qteDispo = qteDispo - 1
WHERE idMeuble = 'TBH007'
INSERT INTO commande
T+4 -1
VALUES ( '110901001' , '2011-09-01' , 89.7 )
INSERT INTO commande
T+5 -1
VALUES ( '110901002' , '2011-09-01' , 29.9 )
INSERT INTO ligneComm
T+6 -1
VALUES ( '110901001' , ' TBH007' , 3 )
INSERT INTO ligneComm
T+7 -1
VALUES ( '110901002' , ' TBH007' , 1 )

26. Le temps représenté ici est en réalité en millisecondes, voire en nanosecondes.

8 2943 TG PA 00
Le résultat ici est catastrophique, Bernard vient de prendre la commande d’un meuble
alors qu’il n’y en a plus de disponible !
Pour sa défense, le SGBDR ne dispose pas d’éléments qui lui permettent d’ordonner les
opérations, ou de prioriser des opérations par rapport à d’autres. C’est là qu’intervient
le langage de contrôle des transactions que nous allons étudier plus loin.

La lecture "fantôme"
Reprenons un autre cas avec nos deux vendeurs, "Alice" et "Bernard". Ils sont tous les
deux connectés au SGBDR et effectuent simultanément des commandes :
tAlice est avec un client qui souhaite commander une chaise en bois référencée
"CHB12". Après quelques hésitations, le client demande finalement à annuler sa
commande (événement qui survient à "T+6" ci-dessous).
tAu même moment, Bernard, qui est, lui aussi, avec un client, souhaite trouver tous
les modèles de chaises pour lesquels il en reste au moins 4 disponibles.

QteDispo
Temps Alice Bernard
(CBH12)
SELECT *
FROM meuble
T 4
WHERE descMeuble LIKE '%chaise%'
AND qteDispo >= 4
SELECT qteDispo
Séquence 6
T+1 FROM meuble 4
WHERE idMeuble = 'CBH12' Le langage
UPDATE meuble de contrôle
des transactions (LCT)
T+2 SET qteDispo = qteDispo - 1 3
WHERE idMeuble = 'CBH12'
Page 121
SELECT *
FROM meuble
T+3 3
WHERE descMeuble LIKE '%chaise%'
AND qteDispo >= 4
INSERT INTO commande
T+4 3
VALUES ( '110901025' , '2011-09-01' , 5.95 )
INSERT INTO ligneComm
T+5 3
VALUES ( '110901025' , 'CH12' , 1 )
DELETE FROM ligneComm
T+6 3
WHERE idComm = '110901025'
DELETE FROM commande
T+7 3
WHERE idComm = '110901025'
UPDATE meuble
T+8 SET qteDispo = qteDispo + 1 4
WHERE idMeuble = 'CBH12'
SELECT *
FROM meuble
T+9 4
WHERE descMeuble LIKE '%chaise%'
AND qteDispo >= 4

8 2943 TG PA 00
Si l’on se met à la place de Bernard, qu’a-t-il vu ?
tÀ la première recherche, la chaise "CBH12" apparaît dans les résultats.
tAu deuxième lancement, la chaise "CBH12" n’apparaît plus (il n’y alors plus que
3 unités disponibles, ce qui ne satisfait plus le critère de recherche).
tAu troisième lancement, la chaise "CBH12" réapparaît dans les résultats (c’est en
général à ce moment-là que les personnes devant l’écran froncent les sourcils…).
Ce phénomène d’apparition et de disparition d’enregistrements est appelé phénomène
de "lecture fantôme" dans le monde des SGBDR (Boooooh !).

La lecture "sale"
Cette fois-ci, le comptable et la vendeuse "Alice" travaillent simultanément sur la base
de données :
tLe comptable souhaite répercuter la hausse de 3,5 % des coûts de livraison (suite à
la hausse des coûts du carburant) sur le prix des meubles. Seulement, en mettant à
jour les prix, il se trompe et saisit 35 % au lieu de 3,5 %. S’apercevant de son erreur,
il effectue alors la correction en veillant à augmenter les prix d’uniquement 3,5 %.
tAu même moment, Alice, qui est avec un client, s’apprête à passer la commande
d’un meuble de salon (référencé "MS2") pour un client qui a été séduit par son prix
à 100 €.

prixMeuble
Temps Alice Le comptable
(MS2)
Séquence 6
SELECT *
T 100
Le langage FROM meuble
de contrôle
SELECT *
des transactions (LCT)
T+1 FROM meuble 100
Page 122 WHERE idMeuble = 'MS2'
UPDATE meuble
T+2 135
SET prixMeuble = prixMeuble * 1.35
UPDATE meuble
T+3 SET qteDispo = qteDispo - 1 135
WHERE idMeuble = 'MS2'
INSERT INTO commande
T+4 135
VALUES ( '110901041' , '2011-09-01' , 135 )
UPDATE meuble
T+5 103.50
SET prixMeuble = prixMeuble / 1.35 * 1.035
INSERT INTO ligneComm
T+6
VALUES ( '110901041' , 'MS2' , 1 )
On peut s’attendre à ce que le client d’Alice soit pour le moins surpris lorsqu’au moment
de payer on lui demandera 135 € au lieu des 100 prévus…
En toute logique, le SGBDR aurait dû attendre que le comptable termine sa série d’ins-
tructions avant de permettre à Alice de travailler sur les mêmes données. Ce phénomène
est ce que l’on appelle une “lecture sale”, qui représente le fait de lire des données à un
instant où elles ne sont peut-être pas définitives.
Mais, encore une fois, le SGBDR ne dispose pas d’éléments qui lui permettent d’ordonner
ou de prioriser des opérations par rapport à d’autres. Nous allons donc maintenant voir
le concept de transaction qui répond à ce besoin.

8 2943 TG PA 00
2. Les transactions
Arrivée avec SQL-92, la gestion des transactions est un concept fondamental qui met en
avant la prévention des incidents liés aux accès simultanés (car, comme on vient de le voir,
ils peuvent être nombreux) et la reprise après incident (panne logicielle ou matérielle).
Appelé "modèle ACID" en référence à l’acronyme des quatre objectifs à atteindre
(Atomicité, Cohérence, Isolation, Durabilité) 27, ce modèle fait partie des concepts les
plus anciens et les plus fondamentaux de la théorie des bases de données. C’est pour-
quoi un SGBDR qui ne satisfait pas à ces objectifs ne peut dès lors être considéré comme
"fiable 28".

Atomicité
Une transaction doit être considérée comme un assemblage de plusieurs étapes pour
former une opération "atomique" de type "tout ou rien":

Transaction T

État cohérent T-1 État cohérent T+1

Séquence 6

États intermédiaires Le langage


de contrôle
des transactions (LCT)
Début Fin temps
Page 123
tUne transaction débute par l’instruction "START TRANSACTION" et se termine par :
– soit l’instruction "COMMIT" si l’on souhaite "valider" la transaction (ce qui
veut dire, ici, passer à l’état T+1) ;
– soit l’instruction "ROLLBACK" si l’on souhaite annuler la transaction (et repas-
ser, ici, à l’état T-1).
tReprenons l’exemple du comptable qui se trompe en augmentant les prix :

START TRANSACTION
SQL /* Modification du prix des meubles */
UPDATE meuble
SET prixMeuble = prixMeuble * 1.35
/* Annulation des modifications (retour à T-1) */
ROLLBACK

27. Acronyme présent dans SQL-92 (termes anglais) : Atomicity - Consistency - Isolation - Durability.
28. Ce qui est le cas pour "MyISAM", le moteur par défaut de MySQL auquel il faudra préférer "innoDB" si
l’on veut disposer du respect du modèle "ACID".

8 2943 TG PA 00
tAprès l’annulation, il recommence donc l’opération :

START TRANSACTION
SQL /* Modification du prix des meubles */
UPDATE meuble
SET prixMeuble = prixMeuble * 1.035
/* Validation des modifications (passage à T+1) */
COMMIT

Cohérence
Une transaction doit être "cohérente", c’est-à-dire qu’elle débute sur un état cohérent
de la base (T-1) et doit donc se terminer sur un nouvel état cohérent (T+1) :
tSi le SGBDR ne rencontre pas de problèmes et réussit à exécuter toutes les étapes
qui composent la transaction, les mises à jour peuvent être effectuées (passage à
l’état T+1).
tSi une seule violation des règles d’intégrité référentielle est rencontrée, c’est la
transaction dans son intégralité qui doit être annulée et aucune des étapes ne doit
affecter la base de données (retour à l’état T-1).

Isolation
Une transaction doit être "isolée" des autres transactions pour éviter de possibles
Séquence 6 interférences. Les états intermédiaires entre les étapes sont transparents pour les autres
transactions concurrentes. Bien entendu, le concept d’isolation ne remet pas en question
Le langage la concurrence des accès et des transactions. Deux mécanismes permettent d’isoler les
de contrôle
des transactions (LCT) transactions : le verrou et la sérialisation.
tLe verrou fait appel au concept d’"accès exclusif". C’est-à-dire que tant qu’une
Page 124 transaction accède à une donnée, aucune autre transaction ne peut y accéder. Les
transactions qui souhaiteraient accéder à cette donnée doivent attendre que la
transaction qui a verrouillé l’accès ait terminé. L’utilisation de verrous pose deux
grands problèmes :
– La famine : lorsqu’une transaction se termine et qu’un verrou est libéré, le
SGBDR choisit la transaction suivante "T" parmi les transactions en attente
et dont les ressources nécessaires sont disponibles. Ainsi, si une transaction a
besoin d’accéder à 2 données qui ne sont jamais "libres" en même temps, elle
peut se retrouver à passer son tour indéfiniment.

X
T T
X

– L’impasse ("deadlock" en anglais) : certains verrouillages peuvent également


conduire à une situation d’impasse où des transactions se bloquent mutuelle-
ment. Prenons l’exemple d’une transaction "T1" qui aurait besoin d’accéder à
2 tables "tab1" et "tab2" et d’une seconde transaction "T2" qui aurait besoin
d’accéder aux mêmes tables, mais dans l’ordre inverse, "tab2" et "tab1". "T1"
va accéder à "tab1" et la verrouiller, au même moment "T2" va accéder à
"tab2" et la verrouiller. Ensuite, "T1" va accéder à "tab2" et, voyant qu’elle est

8 2943 TG PA 00
verrouillée, va attendre sa libération. De son côté, "T2" va accéder à "tab1" et,
voyant qu’elle est verrouillée, va attendre sa libération également.

T1 T1 X T1

T2 T2 X T2

tLa sérialisation est une contrainte forte qui impose aux transactions concurrentes
de s’exécuter séquentiellement les unes après les autres. Il faut pour cela que l’exé-
cution des transactions se fasse en 2 étapes :
– Acquisition des verrous : la transaction commence par verrouiller toutes les
ressources dont elle a besoin ;
– Libération des verrous : une fois terminée ("validée" ou "annulée"), la tran-
saction libère tous les verrous.
L’acquisition de verrous se fait automatiquement sur la plupart des SGBDR qui le
gèrent plutôt bien. La norme SQL, quant à elle, ne nous parle pas explicitement de ver-
rous, ce concept est sous-entendu (c’est pourquoi de nombreux SGBDR ont implémenté
l’instruction "LOCK" qui permet de verrouiller l’accès à une table). SQL nous fournit
la commande "SET TRANSACTION" à laquelle nous pouvons adjoindre des niveaux
d’isolation en fonction des anomalies que l’on souhaite éviter :
Anomalies qui peuvent se produire
Lecture Lecture Lecture Séquence 6
Niveau d'isolation
"non renouvelable" "fantôme" "sale"
Le langage
0 – Read Uncommited X X X
de contrôle
1 – Read Commited X X des transactions (LCT)
2 – Repeatable Read X
3 – Serializable Page 125

s Niveau 0 : "Read Uncommited" ("Lecture de données non validées" en français) est le


niveau où le risque d’anomalie est le plus élevé. À ce niveau, il est possible de lire les
données qui sont en train d’être écrites par une autre transaction.
s Niveau 1 : "Read Commited" ("Lecture de données validées" en français) est le niveau
où une transaction ne voit que les données validées avant le début de la requête sans
jamais voir les données non validées ni les modifications validées pendant l’exécution
de la requête par des transactions exécutées en parallèle.
s Niveau 2 : "Repeatable Read" ("Lecture répétée" en français) est le niveau où une tran-
saction concurrente ne peut pas modifier de données qui ont été lues par la transaction
active tant que celle-ci n’est pas terminée. Par contre, les autres transactions peuvent
insérer de nouvelles lignes.
s Niveau 3 : " Serializable" (" Sérialisable") est le niveau où la sécurité est la plus élevée.
À ce niveau, les transactions sont exécutées l’une après l’autre plutôt que parallèlement.

La compréhension de ces mécanismes est fondamentale pour les développeurs qui sou-
haitent créer des solutions fiables et rapides de traitement des données. Les niveaux plus
hauts réduisent la possibilité de paralléliser les traitements. C’est pourquoi le choix d’un
niveau d’isolation est le choix du développeur en fonction de plusieurs critères : perfor-
mances, sécurité et / ou contraintes métiers.

8 2943 TG PA 00
Durabilité
L’effet d’une transaction doit être "durable", c’est-à-dire qu’une fois terminée les
modifications doivent persister. Cette persistance est assurée par l’utilisation conjointe
de sauvegardes et de journaux de transactions qui assurent le maintien des effets d’une
transaction même en cas de défaillance logicielle ou matérielle qui se produirait avant
la fin d’une transaction :
tSi c’est la transaction qui est à la cause du problème, il faudra que le SGBDR puisse
"défaire" ses effets. En prenant le nouvel état d’une donnée et les consignations
faites dans les journaux de transactions, le système est capable de restaurer l’état
antérieur à la panne (T-1).

Transaction T

État cohérent T-1 État cohérent T+1

T+x

Début Défaillance Fin temps


Log
SQL
Séquence 6

Le langage
de contrôle tToutefois, si ce n’est pas la transaction qui est à l’origine de la défaillance, au
des transactions (LCT) redémarrage, le SGBDR va consulter les journaux de transaction pour restaurer
automatiquement les transactions incomplètes jusqu’au moment où il y a eu une
Page 126 défaillance (T+x).

Transaction T

État cohérent T-1 État cohérent T+1

T+x

Début Log
Défaillance Fin temps
SQL

Les sauvegardes intermédiaires


On vient de voir qu’une transaction, de par son objectif d’atomicité, représentait une
opération de type "tout ou rien". SQL-99 est venu aménager cette atomicité en propo-
sant de découper une transaction en "sous-transaction".
Page 123, nous avons vu qu’après avoir effectué un "ROLLBACK" notre comptable a dû
refaire un "START TRANSACTION". Admettons qu’avant de se tromper sur le montant de
l’augmentation des prix il ait fait d’autres opérations, l’ajout de 2 meubles, par exemple.

8 2943 TG PA 00
Que seraient-ils devenus ? Eh bien, ils auraient également subi le "ROLLBACK" et notre
comptable aurait dû les ressaisir…
La norme SQL nous fournit l’instruction "SAVEPOINT" nous permettant d’effectuer
des sauvegardes en cours de transaction, ce qui permet de faire des "retours arrière"
partiels, sans avoir à annuler intégralement toutes les manipulations réalisées depuis le
début de la transaction.
tReprenons les manipulations de notre comptable, en admettant, cette fois-ci, qu’il
a procédé à l’insertion de 2 nouveaux fournisseurs avant de commettre son impair :
START TRANSACTION
SQL /* Ajout de deux nouveaux meubles */

INSERT INTO meuble


VALUES ('BFC01','Buffet en chêne',259.95),
('BFH08','Buffet en hêtre',199.95)
/* Création d’un point de sauvegarde */
SAVEPOINT sauv1
/* Modification du prix des meubles */
UPDATE meuble SET prixMeuble = prixMeuble * 1.35
/* Annulation des modifications (retour à sauv1)*/
ROLLBACK TO SAVEPOINT sauv1
/* Modification du prix des meubles */
UPDATE meuble SET prixMeuble = prixMeuble * 1.035 Séquence 6
/* Validation des modifications (passage à T+1) */
Le langage
COMMIT de contrôle
des transactions (LCT)

Différer la vérification des contraintes


Page 127
Nous avons vu que l’objectif de cohérence d’une transaction contraint une transaction
à terminer sur un état cohérent de la base de données. Ce qui veut dire qu’à l’intérieur
d’une transaction on peut se trouver à un moment dans un état incohérent. Le com-
portement préconisé par la norme SQL-92 et son objectif d’atomicité est donc bien de
vérifier les contraintes à la validation d’une transaction.
tOn doit donc pouvoir créer un article avec un "idMarque" à "31", sans qu’il y ait de
marque "31" dans la table "marque". L’important étant qu’avant la validation de
la transaction ("COMMIT") il y ait bien une marque 31 dans la table marque, sans
quoi une erreur de type "Violation de la contrainte de clé étrangère "fk_marque"
surviendrait et la transaction serait annulée (même résultat que "ROLLBACK") :
START TRANSACTION
SQL INSERT INTO article (idarticle , idrayon , idmarque)
VALUES (1234567890123 , 2 , 31)
/* A ce niveau, la marque "31" n’existant pas, la
base est donc dans un état incohérent */
INSERT INTO marque (idmarque , nom)
VALUES (31 , 'Nouvelle marque')
/* La base est de nouveau cohérente, on valide */

COMMIT

8 2943 TG PA 00
Certains éditeurs de bases de données ont implémenté l’instruction "SET CONSTRAINTS"
pour permettre aux développeurs d’avoir le choix :
ts’ils souhaitent que les contraintes soient vérifiées immédiatement après chaque
instruction en utilisant la clause "IMMEDIATE";
tou s’ils souhaitent que la vérification des contraintes soit différée à la validation de
la transaction en utilisant la clause "DEFERRED".
Attention, certains éditeurs, comme PostgreSQL ou MySQL, ont choisi de faire l’inverse
des préconisations de SQL-92. C’est-à-dire qu’ils considèrent que, par défaut, la vérifi-
cation des contraintes est immédiate après chaque instruction et cela même si l’on se
trouve dans une transaction.
s Ils vont même plus loin, car, pour qu'une contrainte puisse être différée, elle doit
avoir été au préalable déclarée comme "DEFERRABLE", et ne doit pas porter sur un
champ ayant une contrainte "NOT NULL" :
CREATE TABLE article
(
idarticle numeric(13) NOT NULL,
...
idrayon numeric(2) NOT NULL,
idmarque numeric(3),
CONSTRAINT pk_article
PRIMARY KEY(idarticle),
Séquence 6 CONSTRAINT fk_rayon FOREIGN KEY (idrayon)
REFERENCES rayon (idrayon),
Le langage
de contrôle
CONSTRAINT fk_marque FOREIGN KEY (idmarque)
des transactions (LCT) REFERENCES marque (idmarque) DEFERRABLE
)
Page 128
s Et seulement ensuite, différer les vérifications de contraintes avec l’instruction "SET
CONSTRAINTS", car, par défaut, ces SGBDR considèrent que toutes les contraintes
sont "NOT DEFERRABLE":
– Le report des vérifications peut porter sur toutes les contraintes auxquelles la
transaction va avoir affaire :

START TRANSACTION
SET CONSTRAINTS ALL DEFERRED
...
COMMIT

– Ou uniquement sur certaines contraintes spécifiques :

START TRANSACTION
SET CONSTRAINTS fk_rayon DEFERRED
...
COMMIT

8 2943 TG PA 00
Exercice 1
Extrait du cas CREDAUTO (Métropole, 2006)
La société CREDAUTO est spécialisée dans le crédit automobile accordé aux particu-
liers. Elle agit en partenariat avec des garagistes, établissements commercialisant des
véhicules neufs ou d’occasion. Un prêt CREDAUTO est proposé à un particulier qui
souhaite acheter un véhicule et éprouve le besoin de financer tout ou partie de cet
achat.
En fin de mois, la secrétaire reçoit les demandes de remboursement de frais de repas
et de nuitée engagés par les intervenants lors de leurs déplacements. Les frais d’es-
sence et de péage sont réglés à l’aide d’une carte de société mise à leur disposition.
Un dossier mensuel de demandes de remboursement de frais est créé pour chaque
intervenant lors de la saisie de sa première demande du mois. Pour chaque demande,
la secrétaire enregistre autant de "notes de frais" qu’il y a de nuitées et de repas,
en précisant, pour chacune, la date, le montant déclaré ainsi que le type (nuitée ou
repas). Elle indique également la présence ou non d’un justificatif.
Si la secrétaire dispose de tous les justificatifs, le dossier mensuel de notes de frais
pourra être traité ; dans le cas contraire, elle réclame les justificatifs manquants à
l’intervenant. Celui-ci dispose de quinze jours pour les lui remettre.
Une analyse a permis l’élaboration d’un schéma entité-association (annexe 3A). Il est
accompagné de 2 règles de gestion R1 et R2 exprimées textuellement :
Séquence 6
tR1 : Un intervenant travaille obligatoirement soit sur une région, soit pour une
marque de véhicule, mais jamais pour les deux en même temps. Le langage
tR2 : Un intervenant ne peut déposer que des notes de frais dont le type lui est de contrôle
des transactions (LCT)
autorisé.
Un exemple de séquence d’ordres SQL exécutée lors de la saisie de notes de frais par Page 129
la secrétaire est présenté ci-après. On souhaite analyser l’impact d’un incident (panne
de courant, etc.) survenant au cours de l’exécution de cette séquence, en particulier
suite à l’exécution de la troisième requête INSERT.

BEGIN TRANSACTION ; /* Début de transaction */


INSERT INTO DOSSIERMENSUEL (codeIntervenant,année,mois,dateRéception)
VALUES ('980045',2006,'avril','02/05/2006');
COMMIT TRANSACTION ; /* Validation de transaction */
BEGIN TRANSACTION ; /* Début de transaction */
INSERT INTO NOTEDEFRAIS VALUES ('980045',2006,'avril',1,'02/04/2006',25,true,'R');
INSERT INTO NOTEDEFRAIS VALUES ('980045',2006,'avril',2,'03/04/2006',12,false,'R');
INSERT INTO NOTEDEFRAIS VALUES ('980045',2006,'avril',3,'03/04/2006',50,false,'N');
COMMIT TRANSACTION ; /* Validation de transaction */

Travail à faire
Dans le cas d’un incident survenant suite à l’exécution de la troisième requête
INSERT :
A. Indiquer quelles seront les lignes ajoutées dans les tables DOSSIERMENSUEL et
NOTEDEFRAIS pour l’intervenant de code "980045" en avril 2006. Justifier la
réponse.

8 2943 TG PA 00
B. Indiquer, en utilisant l’annexe 3A, la règle de gestion qui ne sera pas respectée
dans ce cas.
C. Proposer un réaménagement de la séquence d’ordres SQL figurant ci-dessus
afin de résoudre ce problème.

Annexe 3A Schéma entité-association "Gestion des frais"

REGION ANNÉE
0,n Travaille région année
codeRégion
libelléRégion 0,n

0,1 Porte
(1,1)
INTERVENANT DOSSIER MENSUEL
Travaille marque
0,1 codeIntervenant 0,n dateRéception
Donne Concerne
nomIntervenant 0,n datePaiement (1,1)
prénomIntervenant montantTotalPayé
0,n 0,n 1,n
Séquence 6
MARQUE
Autorise Comporte 0,n
Le langage codeMarque MOIS
de contrôle libelléMarque
mois
des transactions (LCT) 0,n 0,n
TYPE NOTE DE FRAIS
Page 130 codeType
Correspond
numéroOrdre
libelléType 0,n 1,1
date
plafond montantNoteFrais
justificatif_O_N

Remarque : les cardinalités (1,1) caractérisent un lien identifiant (entité dépendante).

8 2943 TG PA 00
Annexe 3B Extrait du schéma relationnel "Gestion des frais"
(Afin de ne pas alourdir le schéma, seules les tables utiles sont présentées)

INTERVENANT (code, nom, prénom, codeMarque, codeRégion)


code : clé primaire
codeMarque : clé étrangère en référence à code de MARQUE (non présentée ici)
codeRégion : clé étrangère en référence à code de REGION (non présentée ici)

DOSSIERMENSUEL (codeIntervenant, année, mois, dateRéception, datePaiement,


montantTotalDu)
codeIntervenant, année, mois : clé primaire
codeIntervenant : clé étrangère en référence à code de INTERVENANT

NOTEDEFRAIS (codeIntervenant, année, mois, numéroOrdre, date, montant,


justificatif_O_N, codeType)
codeIntervenant, année, mois, numéroOrdre : clé primaire
codeIntervenant, année, mois : clé étrangère en référence à codeIntervenant,
année, mois de DOSSIERMENSUEL
codeType : clé étrangère en référence à code de
TYPE

TYPE(code, libellé, plafond)


code : clé primaire Séquence 6

Le langage
Remarques : de contrôle
des transactions (LCT)
tLe champ justificatif_O_N de la table NOTEDEFRAIS prend les valeurs true ou
false selon la présence ou l’absence de justificatif pour la note de frais. Page 131
tLe champ MontantTotalDu prend pour valeur le cumul de tous les rembourse-
ments plafonnés correspondant aux notes de frais déposées par un intervenant
pour le mois.

8 2943 TG PA 00
Synthèse

START TRANSACTION : démarrer une transaction


SET TRANSACTION : initialise les caractéristiques de la transaction
t ISOLATION LEVEL : détermine les données que la transaction peut voir
quand d’autres transactions fonctionnent en concurrence.
– READ UNCOMMITED: niveau d’isolation le plus bas. Lecture de don-
nées non validées possible en cours de transaction ;
– READ COMMITED : modification de données possible par une tran-
saction concurrente ;
– REPEATABLE READ : Insertion d’enregistrement possible par une tran-
saction concurrente ;
– SERIALIZABLE : niveau d’isolation le plus haut, les transactions ne
sont pas mises en parallèle.

SET CONSTRAINTS ALL : indique à quel moment de la transaction devra


se faire la vérification de toutes les contraintes
t DEFERRED : reporte la vérification des contraintes à la validation de la tran-
saction (qui rappelons le, est le comportement préconisé par SQL-92) ;
t IMMEDIATE : indique que la vérification des contraintes doit être faite à
Séquence 6
chaque instruction.
Le langage
de contrôle SET CONSTRAINTS nomcontrainte : Indique à quel moment de la transac-
des transactions (LCT) tion devra se faire la vérification de la contrainte "nomcontrainte"
t DEFERRED : reporte la vérification de la contrainte "nomcontrainte" à la
Page 132 validation de la transaction (qui, rappelons-le, est le comportement préco-
nisé par SQL-92) ;
t IMMEDIATE : indique que la vérification de la contrainte "nomcontrainte"
doit être faite à chaque instruction.

SAVEPOINT pointsauv : crée un point de sauvegarde nommé "pointsauv"

ROLLBACK TO SAVEPOINT pointsauv : annule les modifications réalisées


sur la base de données jusqu’à obtenir l’état qu’elle avait lors de la créa-
tion du point de sauvegarde nommé "pointsauv"

ROLLBACK : annule les modifications réalisées sur la base de données


jusqu’à obtenir l’état qu’elle avait avant le début de la transaction

COMMIT : valide les modifications réalisées depuis le début de la tran-


saction

8 2943 TG PA 00
Corrigé des exercices
Vous trouverez ici le corrigé de tous les exercices du fascicule. Les exercices
étant numérotés par séquence, vous les retrouverez classés par séquence.

X Contenu
Conseils généraux ................................................................................. 133
Séquence 1 ............................................................................................. 134
Séquence 2 ............................................................................................. 139
Séquence 3 ............................................................................................. 151
Séquence 4 ............................................................................................. 153
Séquence 5 ............................................................................................. 155
Séquence 6 ............................................................................................. 159

Conseils généraux
Dès la fin de l’exercice 1, je vous invite à tester les requêtes du cours ainsi que les vôtres
directement sur PostgreSQL grâce à l’outil "Query" de pgAdmin (explication page 9).

Rôles des différentes composantes logicielles que vous allez utiliser


pgAdmin et FlySpeed Base de Corrigé des exercices
PostgreSQL
SQL Query données
Page 133

tpgAdmin : c’est un outil graphique qui permet d’administrer des bases de données
PostgreSQL. Ce logiciel est livré avec l’installation et ne nécessite pas de pilote sup-
plémentaire pour communiquer avec PostgreSQL.
tFlySpeed SQL Query : ce logiciel permet d’interroger des bases de données en conce-
vant des requêtes graphiquement ou directement en SQL.
tPostgreSQL : c’est le système de gestion de bases de données relationnelles et objets
(SGBDRO). C’est le logiciel "serveur" qui stocke les bases de données.
Il est important pour vous de bien connaître le rôle de chaque logiciel que vous utilisez.
En effet, lors d’un oral, il est toujours mal perçu de dire que vous avez utilisé pgAdmin
comme SGBDR… N’oubliez pas que pgAdmin est juste une interface d’administration
du "SGBDR PostgreSQL".

8 2943 TG PA 00
Séquence 1

Exercice 1

On va donc poursuivre la création de nos tables. Soit on les crée dans l’ordre, qui permet
de respecter les contraintes d’intégrités (fonctionnelles et référentielles), soit on les créer
dans n’importe quel l’ordre, et on déclare les clés étrangères ensuite.
N’oubliez pas que, lorsque vous utilisez un outil d’administration comme pgAdmin, il
faut créer les tables et les colonnes en utilisant uniquement des minuscules.

Création de la table de données "marque"


tCliquez avec le bouton droit sur "Tables" et choisissez "Ajoutez une table…".
tSaisissez le "Nom" de la table (marque) et son propriétaire (myuser).
tAllez dans l’onglet "Colonnes" et cliquez sur le bouton "Ajouter".
tSaisissez le "Nom" de la colonne (idmarque), le "Type de données" (numeric), la
"Longueur" (3), la "Précision" (0), cochez la case "Non NULL" et validez par "OK".
tCliquez de nouveau sur "Ajouter".
tSaisissez le "Nom" de la colonne (nom), le "Type de données" (character varying)
et validez par "OK".
tAllez maintenant dans l’onglet "Contraintes", choisissez "Clé primaire" dans le
menu déroulant et cliquez sur le bouton "Ajouter".
Corrigé des exercices tSaisissez le "Nom" de la clé primaire (pk_marque), dans l’onglet "Colonnes" choisis-
sez "idmarque" dans le menu déroulant et cliquez sur le bouton "Ajouter".
Page 134
tValidez l’ajout de cette clé en cliquant sur "OK".
tValidez l’ajout de cette table en cliquant à nouveau sur "OK".

Modification de la table "article"


tDépliez l’arborescence de la table "article" et de ses "Colonnes". Cliquez avec le
bouton droit sur "Colonnes" puis choisissez dans le menu contextuel "Ajouter une
colonne".
tSaisissez le "Nom" de la colonne (idmarque), le "Type de données" (numeric), la
"Longueur" (3), la "Précision" (0), cochez la case "Non NULL" et validez par "OK".
tDépliez l’arborescence de la table "article" et de ses "Contraintes". Cliquez avec
le bouton droit sur "Contraintes", choisissez dans le menu contextuel "Ajouter un
objet" puis "Ajouter une clé étrangère":

tSaisissez le "Nom" de la clé étrangère (fk_marque), sélectionnez "marque" dans le


menu déroulant "Références".

8 2943 TG PA 00
tDans l’onglet "Colonnes", choisissez "idmarque" dans le menu déroulant "Colonne
locale" et "idmarque" dans le menu déroulant "Référence vers". Cliquez sur le
bouton "Ajouter".
tValidez l’ajout de cette clé en cliquant sur "OK".

Création de la table de données "achat"


tCliquez avec le bouton droit sur "Tables" et choisissez "Ajoutez une table".
tSaisissez le "Nom" de la table (achat) et son propriétaire (myuser).
tAllez dans l’onglet "Colonnes" et cliquez sur le bouton "Ajouter".
tSaisissez le "Nom" de la colonne (idachat), le "Type de données" (numeric), la
"Longueur" (8), la "Précision" (0), cochez la case "Non NULL" et validez par "OK".
tCliquez de nouveau sur "Ajouter".
tSaisissez le "Nom" de la colonne (dateachat), le "Type de données" (date) et validez
par "OK".
tCliquez de nouveau sur "Ajouter".
tSaisissez le "Nom" de la colonne (montanttotal), le "Type de données" (numeric), la
"Longueur" (6), la "Précision" (2) et validez par "OK".
tAllez maintenant dans l’onglet "Contraintes", choisissez "Clé primaire" dans le
menu déroulant et cliquez sur le bouton "Ajouter".
tSaisissez le "Nom" de la clé primaire (pk_achat), dans l’onglet "Colonnes" choisissez
"idachat" dans le menu déroulant et cliquez sur le bouton "Ajouter".
tValidez l’ajout de cette clé en cliquant sur "OK".
tValidez l’ajout de cette table en cliquant à nouveau sur "OK".

Création de la table de données "listecourses" Corrigé des exercices


tCliquez avec le bouton droit sur "Tables" et choisissez "Ajoutez une table".
tSaisissez le "Nom" de la table (listecourses) et son propriétaire (myuser). Page 135
tAllez dans l’onglet "Colonnes" et cliquez sur le bouton "Ajouter".
tSaisissez le "Nom" de la colonne (idarticle), le "Type de données" (numeric), la
"Longueur" (13), la "Précision" (0), cochez la case "Non NULL" et validez par "OK".
tCliquez de nouveau sur "Ajouter".
tSaisissez le "Nom" de la colonne (idachat), le "Type de données" (numeric), la
"Longueur" (8), la "Précision" (0), cochez la case "Non NULL" et validez par "OK".
tCliquez de nouveau sur "Ajouter".
tSaisissez le "Nom" de la colonne (quantite), le "Type de données" (numeric), la
"Longueur" (3), la "Précision" (0) et validez par "OK".
tAllez maintenant dans l’onglet "Contraintes", choisissez "Clé primaire" dans le
menu déroulant et cliquez sur le bouton "Ajouter".
tSaisissez le "Nom" de la clé primaire (pk_listecourses), dans l’onglet "Colonnes"
choisissez "idarticle" dans le menu déroulant et cliquez sur le bouton "Ajouter".
Choisissez "idachat" dans le menu déroulant et cliquez sur le bouton "Ajouter".
tValidez l’ajout de cette clé en cliquant sur "OK".
tValidez l’ajout de cette table en cliquant à nouveau sur "OK".
tDépliez l’arborescence de la table "listecourses" et de ses "Contraintes". Cliquez
avec le bouton droit sur "Contraintes", choisissez dans le menu contextuel "Ajouter
un objet" puis "Ajouter une clé étrangère".

8 2943 TG PA 00
tSaisissez le "Nom" de la clé étrangère (fk_lc_article), sélectionnez "article" dans le
menu déroulant "Références".
tDans l’onglet "Colonnes" choisissez "idarticle" dans le menu déroulant "Colonne
locale" et "idarticle" dans le menu déroulant "Référence vers". Cliquez sur le bou-
ton "Ajouter".
tValidez l’ajout de cette clé en cliquant sur "OK".
tCliquez avec le bouton droit sur "Contraintes", choisissez dans le menu contextuel
"Ajouter un objet" puis "Ajouter une clé étrangère".
tSaisissez le "Nom" de la clé étrangère (fk_lc_achat), sélectionnez "achat" dans le
menu déroulant "Références".
tDans l’onglet "Colonnes", choisissez "idachat" dans le menu déroulant "Colonne
locale" et "idachat" dans le menu déroulant "Référence vers". Cliquez sur le bou-
ton "Ajouter".
tValidez l’ajout de cette clé en cliquant sur "OK".

Création de la table de données "fournisseur"


Corrigé des exercices
tCliquez avec le bouton droit sur "Tables" et choisissez "Ajoutez une table".
Page 136 tSaisissez le "Nom" de la table (fournisseur) et son propriétaire (myuser).
tAllez dans l’onglet "Colonnes" et cliquez sur le bouton "Ajouter".
tSaisissez le "Nom" de la colonne (idfournisseur), le "Type de données" (numeric), la
"Longueur" (4), la "Précision" (0), cochez la case "Non NULL" et validez par "OK".
tCliquez de nouveau sur "Ajouter".
tSaisissez le "Nom" de la colonne (raisonsociale), le "Type de données" (character
varying) et validez par "OK".
tCliquez de nouveau sur "Ajouter".
tSaisissez le "Nom" de la colonne (adresserue), le "Type de données" (character
varying) et validez par "OK".
tCliquez de nouveau sur "Ajouter".
tSaisissez le "Nom" de la colonne (adressecp), le "Type de données" (character), la
"Longueur" (5) et validez par "OK".
tCliquez de nouveau sur "Ajouter".
tSaisissez le "Nom" de la colonne (adresseville), le "Type de données" (character
varying) et validez par "OK".
tCliquez de nouveau sur "Ajouter".
tSaisissez le "Nom" de la colonne (email), le "Type de données" (character varying)
et validez par "OK".
tCliquez de nouveau sur "Ajouter".

8 2943 TG PA 00
tSaisissez le "Nom" de la colonne (numerotelephone), le "Type de données" (charac-
ter varying) et validez par "OK".
tCliquez de nouveau sur "Ajouter".
tSaisissez le "Nom" de la colonne (distancekm), le "Type de données" (numeric), la
"Longueur" (4), la "Précision" (1) et validez par "OK".
tAllez maintenant dans l’onglet "Contraintes", choisissez "Clé primaire" dans le
menu déroulant et cliquez sur le bouton "Ajouter".
tSaisissez le "Nom" de la clé primaire (pk_fournisseur), dans l’onglet "Colonnes" choi-
sissez "idfournisseur" dans le menu déroulant et cliquez sur le bouton "Ajouter".
tValidez l’ajout de cette clé en cliquant sur "OK".
tValidez l’ajout de cette table en cliquant à nouveau sur "OK".

Création de la table de données "lot"


tCliquez avec le bouton droit sur "Tables" et choisissez "Ajoutez une table".
tSaisissez le "Nom" de la table (lot) et son propriétaire (myuser).
tAllez dans l’onglet "Colonnes" et cliquez sur le bouton "Ajouter".
tSaisissez le "Nom" de la colonne (idlot), le "Type de données" (character), la
"Longueur" (10), cochez la case "Non NULL" et validez par "OK".
tCliquez de nouveau sur "Ajouter".
tSaisissez le "Nom" de la colonne (idarticle), le "Type de données" (numeric), la
"Longueur" (13), la "Précision" (0), cochez la case "Non NULL" et validez par "OK".
tCliquez de nouveau sur "Ajouter".
tSaisissez le "Nom" de la colonne (datefabrication), le "Type de données" (date) et
validez par "OK".
tCliquez de nouveau sur "Ajouter". Corrigé des exercices

tSaisissez le "Nom" de la colonne (datelivraison), le "Type de données" (date) et


validez par "OK". Page 137

tCliquez de nouveau sur "Ajouter".


tSaisissez le "Nom" de la colonne (dateperemption), le "Type de données" (date) et
validez par "OK".
tCliquez de nouveau sur "Ajouter".
tSaisissez le "Nom" de la colonne (idfournisseur), le "Type de données" (numeric), la
"Longueur" (4), la "Précision" (0), cochez la case "Non NULL" et validez par "OK".
tAllez maintenant dans l’onglet "Contraintes", choisissez "Clé primaire" dans le
menu déroulant et cliquez sur le bouton "Ajouter".
tSaisissez le "Nom" de la clé primaire (pk_lot), dans l’onglet "Colonnes" choisissez
"idlot" dans le menu déroulant et cliquez sur le bouton "Ajouter". Choisissez "idar-
ticle" dans le menu déroulant et cliquez sur le bouton "Ajouter".
tValidez l’ajout de cette clé en cliquant sur "OK".
tChoisissez "Clé étrangère" dans le menu déroulant et cliquez sur le bouton
"Ajouter".
tSaisissez le "Nom" de la clé étrangère (fk_article), sélectionnez "article" dans le
menu déroulant "Références".
tDans l’onglet "Colonnes", choisissez "idarticle" dans le menu déroulant "Colonne
locale" et "idarticle" dans le menu déroulant "Référence vers". Cliquez sur le bou-
ton "Ajouter".
tValidez l’ajout de cette clé en cliquant sur "OK".

8 2943 TG PA 00
tChoisissez "Clé étrangère" dans le menu déroulant et cliquez sur le bouton
"Ajouter".
tSaisissez le "Nom" de la clé étrangère (fk_fournisseur), sélectionnez "fournisseur"
dans le menu déroulant "Références".
tDans l’onglet "Colonnes", choisissez "idfournisseur" dans le menu déroulant
"Colonne locale" et "idfournisseur" dans le menu déroulant "Référence vers".
Cliquez sur le bouton "Ajouter".
tValidez l’ajout de cette clé en cliquant sur "OK".
tValidez l’ajout de cette table en cliquant à nouveau sur "OK".

Saisie des données

Outil : Query Outil : Edit Data

Corrigé des exercices

Page 138

PgAdmin nous permet d’insérer manuellement des données grâce à


l’outil "Edit Data".

Comme on ne retire aucun bénéfice de la saisie manuelle, nous allons


utiliser le fichier "insertion-magasin.sql" qui va nous permettre de
gagner du temps :
tCliquez sur le bouton "Query".
tDans la fenêtre "Query" qui s’ouvre, cliquez sur "Fichier", "Ouvrir"
et choisissez le fichier "insertion-magasin.sql".
tCliquez sur "Exécuter la requête" (F5 ou bouton vert X.)

8 2943 TG PA 00
Séquence 2

Exercice 1
tLa liste des fournisseurs ("n°F" doit apparaître à la place de "idFournisseur" et
"Nom" à la place de "raisonSociale":
SELECT idFournisseur AS "n°F", raisonSociale AS "Nom",
adresseRue, adresseCP, adresseVille, email,
numeroTelephone, distanceKm
FROM fournisseur
tLa liste des références d’articles qui ont déjà été sur des listes de courses ("Code
barre" doit apparaître à la place de "idArticle") :
SELECT DISTINCT idArticle AS "Code barre"
FROM listeCourses
tLa liste des marques ("m" doit être utilisé comme alias de la table "marque".
Utilisez également le préfixage des champs) :
SELECT m.idMarque, m.nom
FROM marque AS m
tLa liste des achats :
– "N°" doit apparaître à la place de "idAchat", "Date" à la place de "date
Achat" et "Prix à payer" à la place de "montantTotal".
– Utilisez "a" comme alias de la table "achat". Corrigé des exercices
– Utilisez le préfixage des champs :
SELECT a.idAchat AS "N°", a.dateAchat AS "Date", Page 139
a.montantTotal AS "Prix à payer"
FROM achat AS a

Exercice 2
tLa liste des fournisseurs dont la distance est de moins de 100 km :
SELECT *
FROM fournisseur
WHERE distanceKm < 100
tLa liste des fournisseurs qui se situent à plus de 10 km mais à moins de 100 km :
SELECT *
FROM fournisseur
WHERE distanceKm > 10
AND distanceKm < 100

Vous avez peut être été tentés d’écrire la requête avec "BETWEEN":
SELECT *
FROM fournisseur
WHERE distanceKm BETWEEN 10 AND 100

8 2943 TG PA 00
Attention, cette version n’est pas correcte. Rappelons-nous bien : "BETWEEN" inclut les
bornes dans l’intervalle, ce qui veut dire qu’il faut utiliser "10.1" et "99.9" (précision de 1
décimale lors de la création du champ distanceKm) pour qu’elle réponde à notre besoin :
SELECT *
FROM fournisseur
WHERE distanceKm BETWEEN 10.1 AND 99.9
tLa liste des fournisseurs ayant une adresse email chez "orange.fr":
SELECT *
FROM fournisseur
WHERE email LIKE '%@orange.fr'

N’oublions pas que lorsque, l’on utilise "LIKE", il faut absolument utiliser un caractère
"joker".

tLa liste des lots fabriqués avant le 23 mars 2010 et qui ont été livrés entre le 24 et
le 26 mars :
SELECT *
FROM lot
WHERE datefabrication < '23/03/2010'
AND datelivraison BETWEEN '24/03/2010'
AND '26/03/2010'
tLa liste des articles du rayon n° 12 dont le packaging ou l'unité de mesure n’a pas
Corrigé des exercices été renseigné :
SELECT *
Page 140
FROM article
WHERE ( packaging IS NULL OR unitemesure IS NULL )
AND idRayon = 12

Rappel : on ne peut pas écrire "= NULL" parce que NULL n’est pas " égal à " NULL
(la valeur NULL représente une valeur inconnue et il est impossible de dire si 2 valeurs
inconnues sont égales).

tLa liste des articles dont le packaging est "Par 3", "Par 6" ou "Par 12":
SELECT *
FROM article
WHERE packaging IN ('Par 3','Par 6','Par 12')

On peut également remplacer le "IN" par une succession de "OR":


SELECT *
FROM article
WHERE packaging = 'Par 3'
OR packaging = 'Par 6'
OR packaging = 'Par 12'

8 2943 TG PA 00
Exercice 3

tLa liste des articles ("idArticle", "libelle", "prix" que l’on renomme en "prix en €")
avec, en plus, les prix en livres sterling (on prend comme taux de change : 1 £ =
1,21 €) :
SELECT idArticle, libelle,
prix AS "Prix en €",
prix/1.21 AS "Prix en £"
FROM article

Cet exemple nous montre encore une fois la facilité avec laquelle on peut utiliser des
opérateurs mathématiques directement dans ce qu’on veut afficher.

tLe nombre de marques référencées dans notre base de données :


SELECT COUNT(*) AS "Nb. Marques"
FROM marque
tLe chiffre d’affaires pour le mois d’avril 2010 :
SELECT SUM(montantTotal) AS "CA avril 2010"
FROM achat
WHERE dateAchat BETWEEN '01/04/2010' AND '30/04/2010'

On peut également utiliser la fonction "EXTRACT" (rapidement abordée dans le cours) Corrigé des exercices
permettant d’isoler les composantes d’une date :
SELECT SUM(montantTotal) AS "CA avril 2010" Page 141
FROM achat
WHERE EXTRACT(MONTH FROM dateAchat) = 4
AND EXTRACT(YEAR FROM dateAchat) = 2010

tEXTRACT(MONTH FROM champDate) permet d’extraire le mois d’une date.


tEXTRACT(YEAR FROM champDate) permet d’extraire l’année d’une date.
tLa date de la dernière livraison reçue :
SELECT MAX(dateLivraison) AS "Dernière livraison reçue"
FROM lot
tLa distance moyenne des fournisseurs du Var (département 83) :
SELECT AVG(distanceKm) AS "Distance moy. fourn. Var"
FROM fournisseur
WHERE adresseCP LIKE '83 %'
tLe prix HT (taux de TVA de 19,6%) de l’article le plus cher :
SELECT MAX(prix)/1.196
AS "Prix HT de l’art. le plus cher"
FROM article

8 2943 TG PA 00
tLe prix moyen au kilo des articles dont l’unité de mesure est le gramme :
SELECT AVG(prix/quantite)*1000 AS "Prix moyen au Kg"
FROM article
WHERE uniteMesure='g'

Exercice 4
tLa liste des articles (références et libellés) qui ont été achetés :
SELECT DISTINCT lc.idArticle, libelle
FROM listeCourses AS lc, article AS a
WHERE lc.idArticle = a.idArticle
Cet exemple utilise la jointure "classique" qui est de moins en moins utilisée. Mémorisez-
la bien tout de même car il arrive encore qu’elle apparaîsse dans des sujets d’examen.
Mais, maintenant que l’on sait utiliser l’opérateur "JOIN" offert par SQL-92, il faut
l’utiliser :
SELECT DISTINCT lc.idArticle, libelle
FROM listeCourses AS lc JOIN article AS a
USING (idArticle)
Rappel : le mot-clé "AS" est facultatif, on peut donc écrire notre requête sans ce dernier :
SELECT DISTINCT lc.idArticle, libelle
FROM listeCourses lc JOIN article a
USING (idArticle)
tLa liste des articles (références et libellés) qui ont été achetés avec la date à laquelle
Corrigé des exercices
ils ont été achetés :

Page 142 SELECT DISTINCT lc.idArticle, libelle, dateAchat


FROM listeCourses lc JOIN article a USING (idArticle)
JOIN achat USING (idAchat)
tLa liste des articles (références, libellés et prix) avec le nom de la marque de l’ar-
ticle (renommé en "Marque") et le libellé du rayon d’appartenance (renommé en
"Rayon") :
SELECT idArticle, a.libelle, prix,
nom AS "Marque", r.libelle AS "Rayon"
FROM article a JOIN rayon r USING (idRayon)
JOIN marque USING (idMarque)

Lorsque l’on utilise des alias de tables, c’est parce qu’on va être amené à les utiliser.
Ici, il est inutile de créer un alias de "marque" car on ne l’utilisera pas, contrairement
aux alias de "article" et de "rayon".

tLa liste des articles (références, libellés et prix) avec le nom de la marque de
l’article et le libellé du rayon d’appartenance qui ont été achetés, ainsi que la date
à laquelle ils ont été achetés :

8 2943 TG PA 00
SELECT lc.idArticle, a.libelle, prix, nom, r.libelle,
dateAchat
FROM article a JOIN marque USING (idMarque)
JOIN rayon r USING (idRayon)
JOIN listeCourses lc USING (idArticle)
JOIN achat USING (idAchat)

Entre "article" et "marque", ainsi qu’entre "listecourses" et "achat", on peut également


utiliser une jointure naturelle :
SELECT lc.idArticle, a.libelle, prix,
nom, r.libelle, dateAchat
FROM article a NATURAL JOIN marque
JOIN rayon r USING (idRayon)
JOIN listeCourses lc
USING (idArticle)
NATURAL JOIN achat

Gardez bien à l’esprit que l’on peut mélanger à loisir différents types de jointures. Il
est évident que, dans une même requête, on peut trouver tous les types de jointures, à
condition, bien sûr, que cela soit justifié et cohérent.

tReprenez la requête précédente et utilisez des alias de champs pour chaque champ
utilisé :
– idArticle Î "Référence"; – nom Î "Marque";
– libelle Î "Produit"; – libelle Î "Rayon";
Corrigé des exercices
– prix Î "P.U"; – dateAchat Î "Date".
Page 143
SELECT lc.idArticle AS "Référence",
a.libelle AS "Produit",
prix AS "P.U",
nom AS "Marque",
r.libelle AS "Rayon",
dateAchat AS "Date"
FROM article a JOIN marque USING (idMarque)
JOIN rayon r USING (idRayon)
JOIN listeCourses lc USING (idArticle)
JOIN achat USING (idAchat)

Comme pour la déclaration d’un alias de table, le "AS" permettant de déclarer un alias
de colonne est également facultatif, ce qui veut dire que l’on peut écrire notre requête
de la manière ci-dessous. En règle générale, bien que facultatif, essayez toujours de le
mettre à l’écrit, certains correcteurs d’examen y étant très attachés :

8 2943 TG PA 00
SELECT lc.idArticle "Référence",
a.libelle "Produit",
prix "P.U",
nom "Marque",
r.libelle "Rayon",
dateAchat "Date"
FROM ...
tLa liste des fournisseurs qui n’ont pas encore effectué de livraison :
SELECT DISTINCT f.*
FROM fournisseur f LEFT JOIN lot USING (idFournisseur)
WHERE lot.idFournisseur IS NULL

La jointure gauche nous permet de conserver les lignes de la table de gauche qui n’ont
pas de lignes équivalentes dans la table de droite.
Bien que peut abordée, j’imagine que vous avez bien compris ce que signifiait la nota-
tion "nomTable.*" : cela signifie simplement tous les champs de la table "nomTable".
Si on met uniquement "*", on aura tous les champs, de toutes les tables, ce qui nous
donnera ici tous les champs de "fournisseur" et tous les champs de "lot".
Notons ici que la jointure gauche, peut également être naturelle :
SELECT DISTINCT f.*
FROM fournisseur f NATURAL LEFT JOIN lot
WHERE lot.idFournisseur IS NULL
On peut également ne pas utiliser de jointure avec "NOT IN":
Corrigé des exercices
SELECT *
Page 144 FROM fournisseur
WHERE idFournisseur NOT IN
( SELECT idFournisseur
FROM lot
)
tLa liste des rayons qui n’ont aucun article attribué :
SELECT r.libelle "Rayon sans articles"
FROM article RIGHT JOIN rayon r USING (idRayon)
WHERE idArticle IS NULL

L’utilisation d’une jointure droite nous permet de conserver les lignes de la table de
droite qui n’ont pas de lignes équivalentes dans la table de gauche.
La jointure naturelle, ici, n’est pas possible car il y a le champ "libelle" qui existe dans
les 2 tables et qui n’a rien à voir dans une table et dans l’autre.
Mais, grâce à "NOT IN", si on veut, on peut encore une fois se passer de jointure :
SELECT libelle "Rayon sans articles"
FROM rayon
WHERE idRayon NOT IN ( SELECT idRayon
FROM article
)

8 2943 TG PA 00
Exercice 5
tLa liste des marques par ordre alphabétique :
SELECT *
FROM marque
ORDER BY nom ASC
tLa liste des articles en affichant les articles "bio" en premier :
SELECT *
FROM article
ORDER BY bio DESC
tLa liste des marques avec les articles correspondants. Les noms de marques doivent
être triés par ordre alphabétique inverse et les libellés d’articles par ordre alphabé-
tique :
SELECT nom, libelle
FROM article NATURAL JOIN marque
ORDER BY nom DESC, libelle ASC
tLa liste des lots avec le nom des fournisseurs et le libellé des articles en commençant
par la livraison la plus ancienne. Chaque article sera, lui, trié par ordre alphabé-
tique :
SELECT raisonSociale, dateLivraison, idLot, libelle
FROM fournisseur NATURAL JOIN lot NATURAL JOIN article
ORDER BY dateLivraison DESC, libelle ASC
Corrigé des exercices

Exercice 6 Page 145


tLe ou les articles les moins chers :
SELECT *
FROM article
WHERE prix = ( SELECT MIN(prix)
FROM article
)
On pouvait également utiliser l’expression de sous-requête "EXISTS" de cette manière :
SELECT *
FROM article AS a1
WHERE NOT EXISTS ( SELECT prix
FROM article AS a2
WHERE a1.prix > a2.prix
)
tLa liste des lots qui ont été livrés le même jour que le lot "L593078838":
SELECT *
FROM lot
WHERE dateLivraison = ( SELECT dateLivraison
FROM lot
WHERE idLot = 'L593078838'
)
AND idLot <> 'L593078838'

8 2943 TG PA 00
Pourquoi, ici, avoir écarté volontairement notre lot de la sélection ? Tout simplement
parce qu’il ne serait pas cohérent de dire que ce lot a été livré le même jour que lui-
même… Il vaut donc mieux l’écarter de notre résultat.

tLa liste des rayons qui ont été approvisionnés à la dernière livraison :
SELECT idRayon, r.libelle, dateLivraison
FROM rayon r JOIN article USING (idRayon)
NATURAL JOIN lot
WHERE dateLivraison = ( SELECT MAX(dateLivraison)
FROM lot )
tLa liste des rayons qui ont été approvisionnés à l’avant-dernière livraison :
SELECT idRayon, r.libelle, dateLivraison
FROM rayon r JOIN article USING (idRayon)
NATURAL JOIN lot
WHERE dateLivraison = ( SELECT MAX(dateLivraison)
FROM lot
WHERE dateLivraison <>
( SELECT MAX(dateLivraison)
FROM lot
)
)

On sait trouver la dernière livraison ; pour trouver l’avant-dernière, il suffit d’écarter la


Corrigé des exercices dernière de notre résultat.

Page 146

Exercice 7

Le nombre d’articles par achat :


SELECT idAchat, COUNT(*) AS "Nb art. achetés"
FROM ListeCourses
GROUP BY idAchat
tLe nombre d’articles par rayon :
SELECT r.libelle "Rayon", COUNT(idArticle) "Nb. art."
FROM article RIGHT JOIN rayon r USING (idRayon)
GROUP BY "Rayon"

Si on avait utilisé une jointure équivalente, on aurait perdu une information essentielle, à savoir
les rayons vides (Nb. art. = 0).

8 2943 TG PA 00
tLe nombre de lots livrés par fournisseur :
SELECT raisonSociale,
COUNT(*) AS "Nb lots livrés"
FROM fournisseur NATURAL JOIN lot
GROUP BY raisonSociale
tLa liste des articles avec le nombre de fois où ils ont été achetés en affichant les plus
"populaires" en premier :
SELECT article.idArticle AS "Article",
SUM(listeCourses.quantite) AS "Quantité achetée"
FROM article LEFT JOIN listeCourses USING (idArticle)
GROUP BY "Article"
ORDER BY "Quantité achetée" DESC

Avec une jointure gauche, on a également les articles qui n’ont jamais été achetés. Mais
un article acheté 0 fois, peut-on dire qu’il a déjà été acheté ?
Il est clair que non. Il vaut donc mieux, ici, utiliser une jointure équivalente.

SELECT article.idArticle AS "Article",


SUM(listeCourses.quantite) AS "Quantité achetée"
FROM article JOIN listeCourses USING (idArticle)
GROUP BY "Article"
ORDER BY "Quantité achetée" DESC
tLe prix moyen au kilo des articles par rayon :
SELECT r.libelle AS "Rayon", Corrigé des exercices
AVG(prix/quantite*1000) AS "Prix au Kg"
FROM article JOIN rayon AS r USING (idRayon) Page 147
WHERE uniteMesure = 'g'
GROUP BY "Rayon"

Exercice 8
tLe nombre d’articles par achat avec uniquement les achats concernant moins de
5 articles :
SELECT idAchat, COUNT(*) AS "Nb art. achetés"
FROM listeCourses
GROUP BY idAchat
HAVING COUNT(*) < 5
tLe nombre d’articles par rayon avec uniquement les rayons avec 4 articles :
SELECT r.libelle "Rayon avec 4 art."
FROM article RIGHT JOIN rayon r USING (idRayon)
GROUP BY r.libelle
HAVING COUNT(idArticle) = 4

8 2943 TG PA 00
tLe nombre de lots livrés par fournisseur en ne gardant que les fournisseurs qui ont
livré au moins 10 lots :
SELECT raisonSociale,
COUNT(*) AS "Nb lots livrés"
FROM fournisseur NATURAL JOIN lot
GROUP BY raisonSociale
HAVING COUNT(*) >= 10
tLa liste des articles avec le nombre de fois où ils ont été achetés en affichant les
plus "populaires" en premier et en ne conservant que les articles achetés entre 2 et
5 fois :
SELECT article.idArticle AS "Article",
SUM(listeCourses.quantite) AS "Quantité achetée"
FROM article JOIN listeCourses USING (idArticle)
GROUP BY article.idArticle
HAVING SUM(listeCourses.quantite) BETWEEN 2 AND 5
ORDER BY SUM(listeCourses.quantite) DESC

Exercice 9

tLa liste des marques qui n’ont aucun article en magasin :


SELECT nom
FROM marque
Corrigé des exercices WHERE idMarque NOT IN ( SELECT idMarque
FROM article
Page 148 )

On peut également faire une soustraction avec "EXCEPT":


SELECT nom
FROM marque
WHERE idMarque IN ( SELECT idMarque FROM marque
EXCEPT
SELECT idMarque FROM article
)
Ou encore utiliser une jointure droite, jointure qui, ici, peut être "naturelle":
SELECT nom
FROM article NATURAL RIGHT JOIN marque
WHERE idArticle IS NULL

tLa liste des fournisseurs qui n’ont pas effectué de livraison :


SELECT raisonSociale
FROM fournisseur
WHERE idFournisseur NOT IN ( SELECT idFournisseur
FROM lot
)

8 2943 TG PA 00
On peut également faire une soustraction avec "EXCEPT":
SELECT raisonSociale
FROM fournisseur
WHERE idFournisseur IN ( SELECT idFournisseur
FROM fournisseur
EXCEPT
SELECT idFournisseur
FROM lot
)
Ou encore utiliser une jointure gauche, jointure qui, ici, peut également être "naturelle":
SELECT raisonSociale
FROM fournisseur NATURAL LEFT JOIN lot
WHERE idLot IS NULL

Exercice 10
tLa liste des fournisseurs qui ont déjà livré plusieurs lots lors d’une livraison :
SELECT "Fournisseur",
COUNT("Date de livraison") AS "Nb livraisons",
SUM("Nb lots livrés") AS "Nb total lots"
FROM ( SELECT raisonSociale AS "Fournisseur",
dateLivraison AS "Date de livraison",
COUNT(idLot) AS "Nb lots livrés"
FROM fournisseur NATURAL JOIN lot Corrigé des exercices
GROUP BY "Fournisseur", "Date de livraison"
) AS "Sous-requête" Page 149
GROUP BY "Fournisseur"
HAVING COUNT("Date de livraison") <>
SUM("Nb lots livrés")

Bien qu’elle puisse paraître impressionnante, n’oubliez pas qu’une grande requête est
souvent décomposable en requêtes plus petites. N’hésitez donc pas à prendre le temps de
décomposer la requête pour mieux la comprendre.
D’ailleurs, il y a une petite astuce dans l’outil "Query" de pgAdmin : il vous suffit de
mettre en surbrillance une partie de la requête pour n’exécuter que cette partie.
tLe numéro du ou des fournisseurs qui ont effectué le plus de livraisons :
SELECT idFournisseur AS "Fournisseur(s) le + actif"
FROM ( SELECT COUNT(*) AS nbLivraisons, idFournisseur
FROM lot
GROUP BY idFournisseur
) AS req
WHERE nbLivraisons =
( SELECT MAX(nbLivraisons)
FROM ( SELECT COUNT(*) AS nbLivraisons
FROM lot
GROUP BY idFournisseur
) AS req
)

8 2943 TG PA 00
tLe nom du ou des fournisseurs qui ont effectué le plus de livraisons :
SELECT raisonSociale AS "Fournisseur(s) le + actif"
FROM ( SELECT COUNT(*) AS nbLivraisons, raisonSociale
FROM lot NATURAL JOIN fournisseur
GROUP BY raisonSociale
) AS req
WHERE nbLivraisons =
( SELECT MAX(nbLivraisons)
FROM ( SELECT COUNT(*) AS nbLivraisons
FROM lot
GROUP BY idfournisseur
) AS req
)

Il suffisait, ici, d’améliorer une partie de la requête précédente pour pouvoir aller chercher
le champ "raisonSociale" dans la table fournisseur.
Petit à petit, on est capable de faire croître une requête. Vous devez maintenant vous
rendre compte que les "grandes" requêtes ne sont pas si impressionnantes que ça.

Corrigé des exercices

Page 150

8 2943 TG PA 00
Séquence 3

Exercice 1

tInsertion du nouveau fournisseur n°12 "Zap 83", se situant au "916 rue Pourquoi
pas" à Toulon (83000) soit à 4,2 km :
INSERT INTO fournisseur (idFournisseur, raisonSociale,
adresseRue, adresseCP,
adresseVille, distanceKm)
VALUES (12,'Zap 83','916 rue Pourquoi pas','83000',
'Toulon',4.2)

On peut également utiliser "SELECT" à la place de "VALUES" pour récupérer le dernier


numéro de fournisseur. Bien évidemment, il faut privilégier la numérotation automa-
tique lorsque le SGBDR nous le permet :
INSERT INTO fournisseur (idFournisseur,
raisonSociale,
adresseRue,
adresseCP,
adresseVille,
distanceKm)
SELECT MAX(idFournisseur)+1, 'Zap 83',
'916 rue Pourquoi pas', '83000',
'Toulon', 4.2 Corrigé des exercices
FROM fournisseur
Page 151
tInsertion 29 dans la table "article" des articles présents dans la table temporaire
"nouveauxArticles":
INSERT INTO article (idArticle,libelle,prix,bio,
idRayon,idMarque)
SELECT * FROM nouveauxArticles

Exercice 2

tIl y a une promotion, tous les articles du rayon "Surgelés" baissent de 10% :
UPDATE article
SET prix = prix * 0.9
WHERE idRayon IN ( SELECT idRayon
FROM rayon
WHERE libelle = 'Surgelés'
)

29. La table "nouveauxArticles" n’existant pas dans notre base, la requête ne pourra pas être testée avec
pgAdmin.

8 2943 TG PA 00
tUne autre promotion réduit le prix de tous les articles de la marque "Bonduil" de
1€ :
UPDATE article
SET prix = prix - 1
WHERE idMarque IN ( SELECT idMarque
FROM marque
WHERE nom = 'Bonduil'
)
tUne personne rapporte un paquet de "glaces chocolat en cornets" et désire qu’on
lui reprenne contre remboursement (ticket de caisse n° 1) :
UPDATE listeCourses
SET quantite = quantite - 1
WHERE idAchat = 1
AND idArticle = ( SELECT idArticle
FROM article
WHERE libelle =
'Glaces chocolat en cornets'
)

On a mis à jour la table "listeCourses", mais il ne faut pas oublier de mettre à jour le
montant total de l’achat correspondant. Encore une fois, il faut toujours bien garder à
l’esprit le contexte dans lequel on travaille pour être sûr de ne rien oublier :
UPDATE achat
SET montantTotal = montantTotal –
Corrigé des exercices
( SELECT prix
Page 152
FROM article
WHERE libelle =
'Glaces chocolat en cornets'
)
WHERE idAchat = 1

8 2943 TG PA 00
Séquence 4

Exercice 1

Attention à l’ordre de création des tables. Par exemple, on ne peut pas créer la table
"article" avant les tables "rayon" et "marque". On verra plus tard qu’on peut créer les
tables dans n’importe quel ordre en ajoutant les contraintes après les créations, mais
nous n’y sommes pas encore.
tCréation 30 de la table "rayon" :
CREATE TABLE "rayon"
(
idRayon numeric(2) NOT NULL,
libelle character varying,
CONSTRAINT pk_rayon PRIMARY KEY(idRayon)
)
tCréation de la table "marque" :
CREATE TABLE marque
(
idMarque numeric(3) NOT NULL,
nom character varying,
CONSTRAINT pk_marque PRIMARY KEY(idMarque)
)
Corrigé des exercices
tCréation de la table "article" :
CREATE TABLE "article" Page 153
(
idArticle numeric(13) NOT NULL,
libelle character varying,
prix numeric(6,2),
packaging character varying,
uniteMesure character varying,
quantite numeric(8,3),
bio boolean,
idRayon numeric(2) NOT NULL,
idMarque numeric(3) NOT NULL,
CONSTRAINT pk_article PRIMARY KEY(idArticle),
CONSTRAINT fk_rayon FOREIGN KEY (idRayon)
REFERENCES rayon (idRayon),
CONSTRAINT fk_marque FOREIGN KEY (idMarque)
REFERENCES marque (idMarque)
)

30. Attention, les tables étant déjà créées, vous ne pourrez pas tester ces requêtes via pgAdmin.

8 2943 TG PA 00
Exercice 2

tLe champ "libelle" de la table "rayon" est renommé en "nomRayon":


ALTER TABLE rayon
RENAME COLUMN libelle TO nomRayon
tLe champ "packaging" de la table "article" est supprimé :
ALTER TABLE article
DROP COLUMN packaging
tLe champ "raisonSociale" de la table "fournisseur" devient obligatoire :
ALTER TABLE fournisseur
ALTER COLUMN raisonSociale SET NOT NULL

Exercice 3

tSuppression 31 de la table "nouveauxArticles" de l’exercice 1 de la séquence 3 :


DROP TABLE nouveauxArticles

Corrigé des exercices

Page 154

31. La table "nouveauxArticles" n’existant pas dans notre base, la requête ne pourra pas être testée avec
pgAdmin.

8 2943 TG PA 00
Séquence 5
Dans ce domaine, les questions sont généralement simplistes. Ce qui pose le plus de dif-
ficultés réside bien dans la compréhension du sujet et des questions posées. Veillez donc
bien à relire plusieurs fois les questions posées afin de faire au mieux ce qui est demandé.

Exercice 1
t2 vendeurs, "Alice" et "Bernard", qui doivent pouvoir prendre en compte des com-
mandes de meubles par des clients.
– On commence par créer les rôles :
CREATE ROLE alice
LOGIN PASSWORD 'motdepassealice'
CREATE ROLE bernard
LOGIN PASSWORD 'motdepassebernard'
CREATE ROLE vendeur

– On rattache ensuite nos vendeurs au rôle "vendeur":


GRANT vendeur
TO alice,bernard
– Il fallait au minimum attribuer des privilèges sur les tables "commande" et
"lignecde" ainsi que sur la table "meuble" (consultation) :
GRANT SELECT
ON meuble Corrigé des exercices
TO vendeur
GRANT ALL Page 155
ON commande
TO vendeur
GRANT ALL
ON lignecde
TO vendeur
– Mais on imagine bien que les vendeurs seront amenés à travailler avec la table
"client" pour retrouver les coordonnées, mettre à jour les adresses … On peut
donc également ajouter l’instruction suivante :
GRANT SELECT, INSERT, UPDATE
ON client
TO vendeur
t3 comptables "lpacioli", "hcover" et "ltatouille", qui doivent pouvoir insérer de
nouveaux fournisseurs et mettre à jour les prix de tous les articles et meubles de la
base de données.
– On commence par créer les rôles :
CREATE ROLE lpacioli
LOGIN PASSWORD 'motdepasselpacioli'
CREATE ROLE hcover
LOGIN PASSWORD 'motdepassehcover'

8 2943 TG PA 00
CREATE ROLE ltatouille
LOGIN PASSWORD 'motdepasseltatouille'
CREATE ROLE compta

– On rattache ensuite nos 3 comptables au rôle "compta":


GRANT compta
TO lpacioli,hcover,ltatouille
– On attribue ensuite les privilèges :
GRANT SELECT, INSERT
ON fournisseur
TO compta
GRANT SELECT, UPDATE
ON article
TO compta
GRANT SELECT, UPDATE
ON meuble
TO compta

Exercice 2

GRANT SELECT
ON intervention
TO PUBLIC
Corrigé des exercices
GRANT INSERT, DELETE, UPDATE
ON intervention
Page 156
TO RDeltour

Exercice 3

tOn commence par supprimer tous les anciens droits de "redact" sur la table
"numero":
REVOKE ALL
ON numero
FROM redact
tOn lui donne ensuite les droits de suppression, d’insertion, de consultation et de
mise à jour sur la table "numero":
GRANT DELETE, INSERT, SELECT, UPDATE
ON numero
TO redact
tOn retire ensuite tous les anciens droits de "redact" sur la table "vente":
REVOKE ALL
ON vente
FROM redact

8 2943 TG PA 00
tOn donne ensuite uniquement le droit de consultation à "redact" sur la table
"vente":
GRANT SELECT
ON vente
TO redact

L’ordre suivant est accepté bien que cet ordre ne soit pas strictement équivalent à l’énu-
mération des 4 permissions :

GRANT ALL
ON numero
TO redact

En effet, "ALL" inclut également la permission "REFERENCES", moins usitée que les
4 autres. Dans la plupart des SGBDR, on rencontre également les permissions ALTER et
INDEX pour une table.
L’ordre suivant était pénalisé :
REVOKE ALL
ON numero, vente
TO redact

Une des particularités des ordres "GRANT" et "REVOKE" étant que l’attribution et le
retrait de permission portent sur un seul objet.

Corrigé des exercices


Exercice 4
Page 157
tOn commence par autoriser la consultation uniquement sur les tables "aeroclub",
"avion" et "intervention":
GRANT SELECT
ON aeroclub
TO monique
GRANT SELECT
ON avion
TO monique
GRANT SELECT
ON intervention
TO monique
tIl faut ensuite permettre à "Monique" d’autoriser toutes les opérations sur la table
"subir". Il ne faut donc pas oublier "WITH GRANT OPTION":
GRANT ALL
ON subir
TO monique
WITH GRANT OPTION

8 2943 TG PA 00
On considère que la secrétaire "Monique" ne possède aucun droit au départ sur les tables
(en tant que nouvelle employée). Dans le cas contraire, il aurait fallu utiliser au préa-
lable la requête "REVOKE" pour lui supprimer tous les droits qu’elle pouvait posséder
sur toutes les tables.
L’absence de la clause "WITH GRANT OPTION" pour la dernière instruction est péna-
lisée.

Exercice 5

tBien que 4 instructions soient acceptées, on pouvait tout faire avec une seule :
GRANT SELECT, INSERT, UPDATE, DELETE
ON salarié
TO duparc

Corrigé des exercices

Page 158

8 2943 TG PA 00
Séquence 6

Exercice 1

A. La ligne ('980045', 2006, 'avril', '02/04/2006', NULL, NULL) est ajoutée dans la table
"dossiermensuel". En revanche, aucune ligne ne sera ajoutée dans la table "notede-
frais"; en effet, seule l’instruction validée par le premier commit est effective.
B. Dans le dossier, on précise que "Un dossier mensuel de notes de frais est alors créé par
intervenant lors de la saisie de la première note de frais du mois pour l’intervenant" et,
sur le schéma conceptuel des données, le rôle joué par l’entité "dossiermensuel" dans
l’association "comporte" possède une cardinalité minimale égale à 1 : pour un dossier,
il y a toujours au moins une note de frais ; c’est cette règle de gestion qui ne sera donc
pas respectée.
C. Gérer une seule transaction : elle débutera avant l’insertion du dossier mensuel et
sera validée après l’insertion de toutes les notes de frais. Il faut donc supprimer les ins-
tructions "COMMIT" et "BEGIN" se trouvant après l’insertion de la ligne dans "dossier".

BEGIN TRANSACTION -- Début de transaction


INSERT INTO dossiermensuel (codeIntervenant,année,mois,
dateRéception)
VALUES ('980045',2006,'avril','02/05/2006')
INSERT INTO notedefrais
VALUES ('980045',2006,'avril',1,'02/04/2006',25,true,'R') Corrigé des exercices
INSERT INTO notedefrais
VALUES ('980045',2006,'avril',2,'03/04/2006',12,false,'R') Page 159
INSERT INTO notedefrais
VALUES ('980045',2006,'avril',3,'03/04/2006',50, false,'N')
COMMIT TRANSACTION -- Validation de transaction

Une solution à 2 transactions était également envisageable :


tLa première se terminerait après la première insertion dans "notedefrais" permet-
tant ainsi de respecter la règle de gestion.
tEt la seconde pourrait contenir les 2 insertions suivantes dans "notedefrais".

8 2943 TG PA 00

Vous aimerez peut-être aussi