Vous êtes sur la page 1sur 6

PrepaVogt-ESSCA Management & Finances 2 Année Académique : 2018-2019

Requête SQL avec Microsoft Access !


Travail à faire :
Assurez-vous d’avoir pris connaissance du contenu du cours sur SQL. Durant ce TP, nous allons définir un
schéma de base de données, y ajouter des contraintes, des vues, des déclencheurs (triggers), ainsi qu’un certain
nombre d’informations. La base de données s’intitule Agence de voyages, et propose de d’écrire les activités de
différents clients lors d’un séjour dans une station balnéaire.

a. Création des tables

Voici le schéma Agence de voyages :


• STATION (nomStation,capacité, lieu, région, tarif)
• ACTIVITE (nomStation, libellé, prix)
• CLIENT (id, nom, prénom, ville, région, solde)
• SEJOUR (id, station, début, nbPlaces)

Voici les autres contraintes portant sur ces tables.


1. Les données capacité, lieu, nom, ville, solde et nbPlaces doivent toujours être connues.
2. Les montants (prix, tarif et solde) ont une valeur par défaut à 0.
3. Il ne peut pas y avoir deux stations dans le même lieu et la même région.
4. Les régions autorisées sont : ’Océan Indien’, ’Antilles’, ’Europe’, ’Amériques’ et ’Extrême Orient’.
5. La destruction d’une station doit entraîner la destruction de ses activités et de ses séjours.

Créer les tables du schéma Agence de voyages.


On veillera à bien définir les clés primaires et étrangères, et à donner des noms explicites au contraintes check,
primary key et foreign key

b. Formulaire + Insertion de données


1. Créer pour chaque table un formulaire de saisie

2. Tester ensuite les contraintes avec quelques ordres SQL. Par exemple : détruire la station et vérifier
que les activités ont disparu ; insérer une autre station en (Guadeloupe, Antilles) ; insérer une station
dans une région 'Nullepart', etc.
3. Insérer les données suivantes dans vos différentes tables :

Par Etienne KOUOKAM 1/6 Version du 9 octobre 2018


PrepaVogt-ESSCA Management & Finances 2 Année Académique : 2018-2019

STATION
NomStation Capacité Lieu Région Tarif
Venusa 350 Guadeloupe Antilles 1200
Farniente 200 Seychelles Océan Indien 1500
Santalba 150 Martinique Antilles 2000
Passac 400 Alpes Europe 1000

ACTIVITES
NomStation Libellé Prix
Venusa Plongée 120
Venusa voile 150
Farniente Plongée 130
Passac Ski 200
Passac Piscine 20
Santalba Kayac 50

CLIENT
id nom prenom ville région solde
10 Fogg Phileas Londres Europe 12465
20 Pascal Blaise Paris Europe 6763
30 Kerouac Jack New York Amérique 9812

SEJOUR
idClient station début nbPlaces
20 Venusa 01/07/1998 4
10 Passac 01/07/1998 2
30 Santalba 14/08/1996 5
20 Santalba 03/08/1998 4
30 Passac 15/08/1998 3
30 Venusa 03/08/1998 3
30 Farniente 24/06/1999 5
10 Farniente 05/09/1998 3

c. Requêtes
La base de données que vous avez créée contient déjà un petit jeu de données plus ou moins réaliste. A présent, il
faut concevoir, saisir et exécuter les ordres SQL correspondant aux requêtes suivantes.

Créons, la requête qui extrait de la table "STATION" (contenant une liste de stations) tous les enregistrements.

Pour cela, activons Menu « Créer », puis « Création de Requêtes ». Cliquons sur la petite flèche située à droite de
l'outil "Affichage", et dans la liste déroulante, choisissons "Mode SQL".

Sélection
Introduisons alors la requête suivante :
1. SELECT *
2. FROM STATION ;
On remarque alors que sont affichés tous les champs de la table Station, il n’y a pas eu de sélection particulière.

Projection
Si d’aventure on s’intéresse à la requête qui extrait de la table "STATION" (contenant une liste de stations)
uniquement les trois champs « NomStation », «Capacité » et « Lieu », on aura alors

Par Etienne KOUOKAM 2/6 Version du 9 octobre 2018


PrepaVogt-ESSCA Management & Finances 2 Année Académique : 2018-2019

1. SELECT STATION.NomStation, STATION.Capacité, STATION.Lieu


2. FROM STATION ;
La syntaxe relative aux noms des champs consiste à écrire le nom de la table, suivi d'un point et du nom du champ.
Cette façon de procéder s'appelle la qualification. Dans le cas présent, cette qualification est redondante, et nous
pouvons très bien écrire : SELECT NomStation, Capacité, Lieu
La politique la plus raisonnable consiste à qualifier les champs chaque fois qu'une ambiguïté existe (même nom de
champ dans deux tables différentes, lors d'une requête multi-table), et de ne pas les qualifier dans le cas contraire.

Récupérons la requête précédente dans l'interface graphique et faisons en sorte qu'elle crée une table appelée
"Essai", puis basculons en mode SQL. Nous obtenons :
1. SELECT NomStation, Capacité, Lieu INTO ESSAI
2. FROM STATION ;
Dans Access, cette syntaxe fonctionne à condition que la table "Essai" préexiste, et contienne au moins les champs
« NomStation », « Capacité » et « Lieu » avec les mêmes propriétés que dans la table STATION.
Access effectue alors une requête ajout des trois premières colonnes de la table STATION à la table ESSAI. Il
s’agit là de l’opération de Projection vu dans le cadre de l’algèbre relationnelle.

Tri
Nous pouvons demander que le résultat de la requête soit trié sur un ou plusieurs champs. Récupérons la requête
précédente dans l'interface graphique, faisons en sorte que le résultat soit trié sur le nom de la station d'abord, sur
le lieu ensuite, et basculons en mode SQL. Nous obtenons :
1. SELECT NomStation, Capacité, Lieu INTO ESSAI
2. FROM STATION
3. ORDER BY NomStation, Lieu ;

Nous voyons que le tri (dans l'ordre croissant) s'obtient grâce à la clause ORDER BY, suivi des noms des champs.
Le tri multiple est effectué dans l'ordre d'énumération des champs. Le tri d'un champ dans l'ordre décroissant s'obtient
en faisant suivre le nom de ce champ par l'opérateur DESC. L'exemple suivant effectue un tri croissant sur les noms,
suivi d'un tri décroissant sur les prénoms :
1. SELECT NomStation, Capacité, Lieu INTO ESSAI
2. FROM STATION
3. ORDER BY NomStation, Lieu DESC;
La requête simple peut créer des doublons, et il est possible de remédier de façon simple à cette situation en jouant
sur les propriétés de la requête. Créons dans l'interface graphique une requête de sélection simple qui concerne le
seul champ « NomStation » de la table « Activités ». Que constatez-vous ?
L'élimination des doublons s'obtient à l'aide de l'opérateur DISTINCT placé juste après la clause SELECT en suivant
la syntaxe SELECT DISTINCT (NomStation)
Une syntaxe plus ancienne est également comprise par Access, mais elle ne semble plus guère utilisée
Pour éviter de créer des doublons sur deux champs, la commande SQL s'écrit :
SELECT DISTINCT Champ1, Champ2

Requête emboîtée
Il est possible de créer dans Access une requête à partir du résultat d'une autre requête, à condition que cette
dernière ne crée pas de table. En mode SQL, la commande s'écrit :
1. SELECT Requête1.Nom
2. FROM Requête1 ;
On ne peut pas rêver plus simple pour emboîter deux requêtes ! Cette belle simplicité ne se retrouve pas en SQL
pur et dur, où l'emboîtement de deux requêtes est d'une écriture plutôt complexe. Que l'on en juge :
• Si la première requête (encore appelée sous-requête, ou sous-interrogation) ramène une valeur numérique
unique (résultat d'une opération du type comptage, sommation, calcul de moyenne, etc.), on utilise les
opérateurs arithmétiques usuels : =, <, >, >=, <= et <> ;
• Si la première requête ramène une seule ligne, on utilise les opérateurs IN, ALL, ou ANY suivant les cas ;
• Si la première requête est susceptible de ramener plusieurs lignes, on utilise EXISTS ou NON EXISTS

Restriction
Outre l’opération de projection, on utilise également Access pour effectuer la restriction (selon une qualification) ou
encore la jointure. La restriction est faite en se servant de l’opération WHERE pour fixer les conditions recherchées.
Par exemple, on veut déterminer la liste (nom et prénom des clients dont on ignore le prénom).
1. SELECT nom, prenom
2. FROM Client
3. WHERE prenom IS NULL;
Dans l’exemple précédent, identifiez les différentes opérations de l’algèbre opérationnelle vues en cours.

Jointure
Et maintenant, la jointure qui est obtenu en faisant un peu le produit cartésien de deux tables ou plus, simplement
en indiquant les différentes table dans la clause « FROM »

Par Etienne KOUOKAM 3/6 Version du 9 octobre 2018


PrepaVogt-ESSCA Management & Finances 2 Année Académique : 2018-2019

Exemple, on veut avoir la liste (nom et prénom) des clients ayant séjourné à Santalba. Alors, on a dans SQL 1 :
1. SELECT nom, prenom
2. FROM CLIENT, SEJOUR
3. WHERE station = 'Santalba'
4. AND id = idClient;
Essayez d’expliquer très clairement la requête précédente en identifiant les opérations de l’algèbre relationnelle
que vous y reconnaissez.
Le SGBD Access accepte cette syntaxe mais, si nous revenons dans l'interface graphique, nous constatons que
cette dernière a changé : la relation entre les deux tables a disparu ! Elle est remplacée par la condition d'égalité
de contenu entre les champs id et idClient des deux tables (condition exprimée en utilisant la syntaxe du
SQL). C’est une façon élémentaire, mais parfaitement exacte, de créer une relation entre deux tables. On notera
que la relation normale entre les deux tables n'est pas supprimée, mais simplement éliminée de la fenêtre de
création de la requête.
La clause INNER JOIN a fait son apparition avec la version 2 de SQL, parce que le besoin s'était fait sentir de
préciser à quel type de jointure appartenait une relation. Plus précisément, on distingue :
• la jointure interne, qui utilise INNER JOIN. Ne sont incluses dans le résultat final que les lignes qui se
correspondent dans les deux tables. Ce cas est celui que nous avons traité précédemment ;
• la jointure externe gauche, dans laquelle INNER JOIN est remplacé par LEFT OUTER JOIN. Toutes les
lignes de la première table sont incluses dans le résultat de la requête, même s'il n'existe pas de ligne
correspondante dans la seconde table ;
• la jointure externe droite, dans laquelle INNER JOIN est remplacé par RIGHT OUTER JOIN. Toutes les
lignes de la seconde table sont incluses dans le résultat de la requête, même s'il n'existe pas de ligne
correspondante dans la première table.
Dans Access, la syntaxe des jointures gauche et droite est simplifiée en LEFT JOIN et RIGHT JOIN.
Essayez d’appliquer les différents types de jointure comme sur l’exemple suivant, correspondant au précédent.
1. SELECT nom, prenom
2. FROM CLIENT INNER JOIN SEJOUR ON id = idClient
3. WHERE station = 'Santalba' ;

Regroupement
Nous effectuons le regroupement des activités par station et nous sommons sur le Prix pour déterminer le montant
total des prix d’activité par station. Nous obtenons le code SQL suivant dans lequel le regroupement est exprimé
par la clause GROUP BY.
1. SELECT nomStation, sum (Prix)
2. FROM ACTIVITE
3. GROUP BY nomStation;
Et si on veut déterminer le nombre total de places pour chaque séjour effectué dans chaque station
1. SELECT Date, Sum(nbPlaces) AS nbPlace_total
2. FROM SEJOURS
3. GROUP BY debut;
Nous reconnaissons une requête de sélection classique (dans les 3 premières lignes), suivie d'un regroupement.
Une requête avec regroupement peut être filtrée avant ou après regroupement. Nous créons un exemple de
filtrage avant regroupement en éliminant la station Passac. Nous obtenons le code SQL suivant :
1. SELECT Date, Sum(nbPlaces) AS nbPlace_total
2. FROM SEJOURS
3. WHERE station Not Like "Passac"
4. GROUP BY debut;
Nous rajoutons ensuite un filtrage après regroupement en ne retenant que les dates pour lequelles le nombre total
de places est strictement supérieur à 5. Nous obtenons le code SQL suivant dans lequel le filtrage après
regroupement utilise la clause HAVING.
1. SELECT Date, Sum(nbPlaces) AS nbPlace_total
2. FROM SEJOURS
3. WHERE station Not Like "Passac"
4. GROUP BY debut
5. HAVING Sum(nbPlaces)>5;

Sous-requête (Requête imbriquée)


Une sous-requête est une instruction SELECT imbriquée dans une instruction
SELECT, SELECT…INTO, INSERT…INTO, DELETE ou UPDATE ou imbriquée dans une autre sous-requête.
Vous pouvez utiliser trois variantes de syntaxe pour créer une sous-requête :
comparaison [ANY | ALL | SOME] (instructionsql)
expression [NOT] IN (instructionsql)
[NOT] EXISTS (instructionsql)

Par Etienne KOUOKAM 4/6 Version du 9 octobre 2018


PrepaVogt-ESSCA Management & Finances 2 Année Académique : 2018-2019

Vous pouvez utiliser une sous-requête au lieu d’une expression, dans la liste de champs d’une instruction WHERE ou
dans une clause HAVING. Dans une sous-requête, vous utilisez une instruction SELECT pour fournir un jeu d’une ou
plusieurs valeurs spécifiques à évaluer dans l’expression de la clause WHERE ou HAVING.
Utilisez les prédicats ANY ou SOME, qui sont synonymes, pour rechercher par comparaison les enregistrements de la
requête principale en correspondance avec n'importe quel enregistrement de la sous-requête.
Utilisez le prédicat ALL pour rechercher par comparaison uniquement les enregistrements de la requête principale en
correspondance avec n’importe quel enregistrement de la sous-requête. Si dans l’exemple précédent, vous avez
remplacé ANY par ALL, la requête ne renvoie que les produits dont le prix unitaire est supérieur aux prix de tous les
produits vendus avec une remise de 25 pourcent ou davantage. La recherche est beaucoup plus restrictive.
Utilisez le prédicat IN pour rechercher les enregistrements de la requête principale pour lesquels on trouve des
enregistrements avec une valeur identique dans la sous-requête.
À l'inverse, vous pouvez utiliser le prédicat NOT IN pour rechercher les enregistrements de la requête principale pour
lesquels aucun enregistrement avec une ne contient une valeur identique dans la sous-requête.
Utilisez le prédicat EXISTS (avec le mot réservé facultatif NOT) dans des comparaisons vrai/faux pour déterminer si la
sous-requête renvoie des enregistrements
Vous pouvez également utiliser des alias de nom de table dans une sous-requête pour faire référence à des tables
répertoriées dans une clause FROM en dehors de la sous-requête. Dans l’exemple suivant, la requête renvoie le nom
des employés dont le salaires est supérieur ou égal au salaire moyen de l’ensemble des employés occupant le même
poste. L’alias affecté à la table Employees est « T1 » :

Dans l'exemple suivant, la requête renvoie toutes les stations habitées par un client quelconque :
SELECT * FROM STATION
WHERE region IN
(SELECT region FROM CLIENT );

Union de deux tables


L'union de deux tables est une une feuille de données (ou une table) contenant chaque ligne de la première
table et chaque ligne de la seconde table. Les lignes communes aux deux tables ne sont conservées qu'en un seul
exemplaire, c'est à dire que l'opération d'union élimine les doublons. Les champs que l'on fait correspondre dans les deux
tables n'ont pas besoin de porter les mêmes noms ni de se présenter dans le même ordre -- ni même de posséder le
même type de donnée si la transposition est possible (une date en texte, par exemple). Il n'existe pas dans Access
d'interface graphique permettant de créer une requête Union. Il faut donc écrire soi-même le code SQL requis. Pour
ouvrir l'éditeur de requêtes SQL, nous sélectionnons l'objet "Requêtes" dans la fenêtre "Base de données", nous
n'introduisons aucune table dans l'interface graphique de définition des requêtes, et nous basculons en mode SQL.
En outre, le SGBD sait que "last-name" correspond à "nom", et "first-name" à "prénom", parce que les champs sont cités
dans cet ordre dans les deux clauses SELECT. La feuille de données résultante emprunte les noms de ses champs à la
première table. La présence des crochets traduit le fait que SQL ne tolère pas le tiret dans les noms des tables ni dans
ceux des champs (caractère non autorisé). Si notre base contient les deux tables précitées, nous pouvons exécuter
la requête SQL suivante, contenant l'opérateur UNION :
SELECT nom, prénom SELECT nom, prénom
FROM Table1 FROM Table1
UNION UNION
SELECT nom, prénom SELECT [last-name], [first-name]
FROM Table2; FROM Table2;
A l'exécution de la requête, nous constatons qu'une feuille de données est créée, qui rassemble le contenu des
deux tables, et en élimine les doublons. Si nous enregistrons la requête (sa structure, pas son contenu), Access
fait précéder son nom de l'icône pour rappeler qu'il s'agit d'une requête de type "Union".

Intersection de deux tables


L'intersection de deux tables est une une feuille de données (ou une table) contenant seulement les lignes
communes aux deux tables. Les conditions sont les mêmes que pour l'union. La figure ci-dessous illustre
l'opération intersection. Le code SQL correspondant dépend de la version utilisée

En SQL 1 En SQL 2
SELECT nom, prénom SELECT nom, prénom
FROM Table1 FROM Table1
WHERE Table1.nom IN (SELECT nom FROM INTERSECT

Par Etienne KOUOKAM 5/6 Version du 9 octobre 2018


PrepaVogt-ESSCA Management & Finances 2 Année Académique : 2018-2019

Table2) AND Table1.prénom IN (SELECT SELECT nom, prénom


prénom FROM Table2); FROM Table2;
Mais... le SGBD Access ne reconnaît pas l'opérateur INTERSECT. Il affiche un message d'erreur qui, bien entendu,
ne correspond pas à la situation (une habitude bien ancrée en informatique). Seule reste en lice la première syntaxe,
qui apparaît de la manière suivante dans l'interface graphique :

La différence de deux tables


La différence de deux tables est une feuille de données (ou une table) contenant les enregistrements de la première
table qu'on ne retrouve pas dans la seconde. Les conditions sont les mêmes que pour l'union. Le code SQL
correspondant dépend de la version du langage utilisée. En SQL1, il s'écrit comme pour l'intersection, à ceci près
que IN est remplacé par NOT IN.

En SQL 1 En SQL 2
SELECT nom, prénom SELECT nom, prénom
FROM Table1 FROM Table1
WHERE Table1.nom NOT IN (SELECT nom EXCEPT
FROM Table2) AND Table1.prénom NOT IN SELECT nom, prénom
(SELECT prénom FROM Table2); FROM Table2;

Le SGBD Access ne reconnaît ni l'opérateur INTERSECT, ni l'opérateur MINUS, et il affiche un message d'erreur.
On peut bien sûr s'en tirer comme pour l'intersection, mais il faut cette fois utiliser la jointure gauche.

Exercices :

En vous appuyant sur tout ce qui précède et en exploitant au mieux les exemples donnés, produire les requêtes
SQL correspondant aux questions suivantes :
1. Quelles sont les activités dont le libellé commence par « S » ? (commande LIKE)
2. Quels sont les clients dont on ignore le prénom ?
3. Combien de fois a-t-on effectué de séjours à Santalba en 1999?
4. Nom et ville des clients ayant moins de 7000 euros en solde.
5. Liste des séjours à Passac.
6. Qui a séjourné à Santalba (nom et prénom) ?
7. Libellé des activités de la station de Venusa.
8. Liste des clients (nom et prénom) ayant visité Farniente dès 1999
9. Dans quelle station n’a-t-on jamais séjourné ?
10. Liste des stations qui n’ont pas le ski comme activités
11. Total des capacités de la station de Passac
12. Tarif minimum et maximum des stations.
13. Total des prix des activités par station.
14. Nom et prénom des clients, et nombre de séjours qu'ils ont effectués.

Par Etienne KOUOKAM 6/6 Version du 9 octobre 2018