Les requêtes, langage SQL

solutions
(un retour vers la question est possible à chaque réponse)
cuy copyleft
  See You Why?  

 

Cette page contient toutes les réponses, les solutions aux exercices proposés dans ce cours d'Access.
Un simple 'clic' sur le lien présent à la suite de chaque réponse vous permet de lire ou relire l'énoncé de l'exercice.
Bon amusement avec cette collection d'exercices.

 

 

 

  

R1

 

Requête de projection qui affichera tous les champs 'Société' de la table 'Clients' toute entière.

retour Q1

 

 

 

 

  

R2

 

Requête de jointure (puisqu'elle fait appel à plusieurs tables) qui affichera tous les champs des tables 'Produit' et 'Détail_commande' qui ont un champ commun 'Code_produit'.

Ou : la liste des enregistrements de la table 'Produit' qui ont le champ 'Code_produit' qui apparaît aussi dans la table 'Détail_commande'.

Ou : la liste des infos concernant les produits commandés et les détails de ces commandes.

retour Q2

 

 

 

 

  

R3

 

Requête de sélection (ou restriction) qui affichera tous les champs de la table 'Etudiant' dont la ville a été enregistrée... et négligera donc les enregistrements où la ville n'a pas été encodée...

ATTENTION : Une erreur fréquemment rencontrée est de faire précéder le NULL de = et non de IS ; ainsi :

SELECT *
FROM ETUDIANT
WHERE Ville IS NULL ;

est valable alors que la requête suivante est incorrecte :

SELECT *
FROM ETUDIANT
WHERE Ville = NULL ;

retour Q3

 

 

 

 

  

R4

 

Requête de restriction (sélection) qui affichera tous les noms, prénoms et salaires annuels du personnel qui gagne plus de 45 000 par an (12 fois le salaire mensuel... si ce sont des employés), et cela par ordre décroissant de salaire (du plus haut au plus bas) et si égalité de salaire, par ordre alphabétique des noms.

retour Q4

 

 

 

 

  

R5

 

Le filtre permet de n'afficher que les informations répondant à des critères spécifiques.

La requête permet diverses mises en forme des tables: le tri, les filtres, afficher ou non des données, …

Tout ce que peut faire un filtre pourra être fait par une requête, mais une requête peut faire bien plus :
* elle permet de réunir les données de plusieurs tables en vue de leur utilisation comme source de données pour un formulaire ou un état, ou même pour créer une nouvelle table, en modifier une, etc.
* elle permet de rassembler des données à partir de plusieurs tables et d'en afficher le résultat, ou de modifier les enregistrements sources
* en plus des champs calculés, Accès possède des fonctions prédéterminées pour vous aider à réaliser des requêtes et des analyses plus complexes. Il y a 176 fonctions disponibles qui sont regroupées en 16 catégories.
.

retour Q5

 

 

 

 

  

R6

 

Requête de projection qui affichera tous les champs 'Société' de la table 'Clients' toute entière.

retour Q6

 

 

 

 

  

 

R7

 

Requête de projection qui affichera tous les champs 'Société' de la table 'Clients' toute entière.

retour Q7

 

 

 

 

  

 

R10

 

SELECT *
FROM LIVRE

Dans cet exemple, le lecteur notera l’utilisation du symbole * pour spécifier que l’on souhaite conserver dans le résultat tous les attributs (ou champs) de la relation (ou table) LIVRE.

Le lecteur attentif aura noté l'absence du point-virgule final de la requête.

retour Q10

 

 

 

 

  

R11

 

SELECT Titre
FROM LIVRE
WHERE Editeur = ‘Flammarion’ and Genre = ‘Roman’

Dans cette requête la condition porte sur les attributs (ou champs) Editeur et Genre et le résultat retourné par la requête est la liste des titres. Il n’y a en effet pas nécessairement de liens entre les attributs retournés et ceux sur lesquels portent la condition. Le lecteur attentif aura noté l'absence du point-virgule final de la requête.

Pour mieux distinguer les champs des tables, nous suggérons l'écriture suivante :

SELECT cTitre
FROM tLIVRE
WHERE cEditeur = ‘Flammarion’ and cGenre = ‘Roman’;

retour Q11

 

 

 

 

  

R12

 

SELECT D.Titre
FROM DISQUE D, LIVRE L
WHERE D.titre = L.Titre;

 

retour Q12

 

 

 

 

  

R13

 

SELECT A1.Identité
FROM DISQUE D, LIVRE L, AUTEUR A1, AUTEUR A2
WHERE D.CodeOuv = A1.CodeOuv and L.CodeOuv = A2.CodeOuv and A1.Identité = A2.Identité;

retour Q13

 

 

 

 

  

R14

Analyse préalable

Champs à afficher tous les champs
Tables concernées Clients
Conditions aucune
Classement aucun

SELECT *
FROM Clients

Dans cet exemple, le lecteur notera l’utilisation du symbole * pour spécifier que l’on souhaite conserver dans le résultat tous les attributs (ou champs) de la relation (ou table) Clients.

retour Q14

 

 

 

 

  

R15

Analyse préalable

Champs à afficher Nom, Prenom
Tables concernées Clients
Conditions aucune
Classement aucun

SELECT Clients.Nom, Clients.Prenom
FROM Clients;

Dans cet exemple, le lecteur notera l’utilisation du point qui sépare le nom de la table (ou relation) et les attributs (ou champs).
Lorsqu'il n'y a aucun risque de confusion (homonymie, etc.), il est possible de supprimer le nom de la table (et le point qui sépare). On aurait alors :

SELECT Nom, Prenom
FROM Clients;

retour Q15

 

 

 

 

  

R16

Analyse préalable

Champs à afficher Nom, Prenom
Tables concernées Clients
Conditions Ville = Mouscron
Classement aucun

SELECT Clients.Nom, Clients.Prenom
FROM Clients
WHERE Ville=Mouscron;

Dans cet exemple, le lecteur notera l’utilisation du point qui sépare le nom de la table (ou relation) et les attributs (ou champs).
Lorsqu'il n'y a aucun risque de confusion (homonymie, etc.), il est possible de supprimer le nom de la table (et le point qui sépare). On aurait alors :

SELECT Nom, Prenom
FROM Clients
WHERE Ville=Mouscron;

retour Q16

 

 

 

 

 

  

R17

Analyse préalable

Champs à afficher Nom, Tel
Tables concernées Clients
Conditions Prenom = Marc ou Philippe
Classement aucun

SELECT Clients.Nom, Clients.Tel
FROM Clients
WHERE Clients.Prenom LIKE "Marc" OR Clients.Prenom LIKE "Philippe";

Le lecteur attentif aura remarqué que la condition ne doit pas porter sur un champ qui doit être affiché. Les prénoms n'apparaissent pas dans les champs à présenter à l'écran... puisque l'utilisateur a demandé les clients se prénomment Marc ou Philippe, il devinera (on espère) que les prénoms des clients affichés sont... Marc ou Philippe.

Dans cet exemple, une dernière fois, le lecteur notera l’utilisation du point qui sépare le nom de la table (ou relation) et les attributs (ou champs).
Lorsqu'il n'y a aucun risque de confusion (homonymie, etc.), il est possible de supprimer le nom de la table (et le point qui sépare). On aurait alors :

SELECT Nom, Tel
FROM Clients
WHERE Prenom LIKE "Marc" OR Prenom LIKE "Philippe";

Un lecteur attentif aura remarqué (merci Fred) que la réponse donnée ici n'est pas celle de la question : "Afficher les nom et prénom des clients dont les prénoms sont Marc ou Philippe", mais plutôt de la question : "Afficher les nom et numéro de téléphone des clients dont les prénoms sont Marc ou Philippe".

retour Q17

 

 

 

 

 

  

R18

Analyse préalable

Champs à afficher Nom, Tel
Tables concernées Clients
Conditions Nom compris entre B et EZZ
Classement aucun

SELECT Clients.Nom, Clients.Tel
FROM Clients
WHERE Clients.Nom BETWEEN "B" AND "EZZ";

Dans cet exemple, une erreur fréquemment rencontrée est de limiter le critère à
"WHERE Clients.Nom BETWEEN "B" AND "E" " ;
dans ce cas, tous les autres noms commençant par E seraient ignorés (sauf le nom "E").

Comme dans la question 17, le lecteur attentif aura noté que la réponse notée ici est la réponse à "Afficher les nom et numéro de téléphone (et pas nom et prénom) des clients dont le nom commence par une lettre comprise entre B et E.".

D'autres lecteurs, tout aussi attentifs, pourraient faire remarquer qu'une autre solution pouvait être acceptée :
"SELECT Nom, Tel FROM Clients WHERE Nom LIKE "[B-E]*"; "
précisant dont la première lettre du nom est comprise entre B et E, suivie de n'importe quoi. Ce serait parfait aussi.

retour Q18

 

 

 

 

 

  

R19

Analyse préalable

Champs à afficher Ville
Tables concernées Clients
Conditions aucune
Classement aucun

SELECT DISTINCT Clients.Ville
FROM Clients ;

Dans cet exemple, le paramètre DISTINCT qui élimine les doublons est nécessaire ; dans le cas contraire, toutes les villes seraient affichées... autant de fois qu'elles apparaissent dans la liste... inutile de lire 300 fois Mouscron si l'on a 300 clients mouscronnois.

retour Q19

 

 

 

 

 

  

R20

Analyse préalable

Champs à afficher Num
Tables concernées Clients, Commande
Conditions Clients.Codecli = Commande.Codecli ET
Clients.Nom = "Royal" ET Clients.Prenom = "Ségolène"
Classement aucun

SELECT Commande.Num
FROM Commande
WHERE Clients.Codecli = Commande.Codecli AND Clients.Nom LIKE "Royal" AND Clients.Prenom LIKE "Ségolène";

Dans cet exemple, les champs Codecli de la table Clients et de la table Commande n'ont servi quà établir le lien entre les deux tables.
Ce lien (jointure) est un lien de "UN à PLUSIEURS" ; en effet :
* une commande n'est passée que par UN SEUL client,
* un client peut passer PLUSIEURS commandes.

retour Q20

 

 

 

 

 

  

R21

Analyse préalable

Champs à afficher Num
Tables concernées Clients, Commande
Conditions Clients.Codecli = Commande.Codecli ET
Clients.Nom = "Royal" ET Clients.Prenom = "Ségolène"
Classement ordre décroissant de date

SELECT Commande.Num
FROM Commande
WHERE Clients.Codecli = Commande.Codecli AND Clients.Nom LIKE "Royal" AND Clients.Prenom LIKE "Ségolène"
ORDER BY Commande.Date DESC ;

Un ordre de date croissant est l'ordre chronologique... donc, ici, l'ordre est l'inverse de l'ordre chronologique, donc descendant.

retour Q21

 

 

 

 

 

  

R22

Analyse préalable

Champs à afficher Désignation, PU_TVAC
Tables concernées Produits
Conditions aucune
Classement aucun

SELECT Produits.Désignation, Produits.PU_HTVA*1.21 AS PU_TVAC
FROM Produits ;

Il n'y a que deux éléments à afficher... ils sont séparés par une virgule ;
le deuxième élément n'est pas un élément de la table, mais résulte d'un calcul opéré sur un champ de la table.

L'opérateur AS permet de créer un nouveau champ, résultat d'un calcul sur un champ existant ;
ce nouveau champ n'est pas un champ de la table... on ne peut donc pas le précéder du nom de la table ;
le calcul porte sur un champ de la table... on peut donc faire apparaître le nom de la table devant le nom du champ employé.

Access travaille avec le point décimal, pas la virgule décimale... il y aurait risque de confusion avec les séparateurs de champs.

retour Q22

 

 

 

 

 

  

R23

Analyse préalable

Champs à afficher Quantité de produits (dénombrement des champs 'Produits.Codeprod' qui vérifient la condition)
Tables concernées Produits
Conditions PU_TVAC >= 50
Classement aucun

SELECT COUNT (Produits.Codeprod) AS Q_prod
FROM Produits
WHERE Produits.PU_HTVA * 1.21 >= 50 ;

Il n'y a qu'un seul élément à afficher... qui n'est pas un élément de la table, mais résulte d'un calcul opéré sur un/plusieurs champs de la table.

La fonction Count(...) est une fonction de regroupement... elle dénombre les champs qui répondent à la condtion donnée dans WHERE.

L'opérateur AS permet de nommer, créer ce nouvel élément, résultat d'un calcul (d'une fonction statistique) portant sur ce champ existant [le lecteur aura remarqué que n'importe quel champ aurait pu convenir, puisqu'il s'agit de compter le nombre d'enregistrements répondant au critère]  ;
ce nouvel élément Q_prod n'est pas un champ de la table... on ne peut donc pas le précéder du nom de la table ;
le calcul porte sur un champ de la table... on peut donc faire apparaître le nom de la table devant le nom du champ employé.

Access travaille avec le point décimal, pas la virgule décimale... il y aurait risque de confusion avec les séparateurs de champs.

Le lecteur ayant observé qu'il était fait mention de plusieurs tables dans l'énoncé se sera étonné de voir cet exercice présent ici et pas dans la série d'exercices concernant les jointures. La résolution ne fait appel qu'à une seule table, donc pas de jointure.

retour Q23

 

 

 

 

 

  

R24

Analyse préalable

Champs à afficher Quantité de produits vendus (somme des Comporter.Quantite)
Tables concernées Comporter
Conditions Codeprod = FL0425
Classement aucun

SELECT SUM (Comporter.Quantite) AS Q_prodvend
FROM Comporter
WHERE Comporter.Codeprod = FL0425 ;

Il n'y a qu'un seul élément à afficher... qui n'est pas un élément de la table, mais résulte d'un calcul opéré sur un/plusieurs champs de la table.

La fonction Sum(...) est une fonction de regroupement... elle fait la somme des champs qui répondent à la condtion donnée dans WHERE.

L'opérateur AS permet de nommer, créer ce nouvel élément, résultat d'un calcul (d'une fonction statistique) portant sur ce champ existant [le lecteur aura remarqué que seul le champ Comporter.Quantite aurait pu convenir, puisqu'il s'agit de faire la somme des quantités vendues de ce produit pour toute les commandes qui comportaient ce produit]  ;
ce nouvel élément Q_prodvend n'est pas un champ de la table... on ne peut donc pas le précéder du nom de la table ;
le calcul porte sur un champ de la table... on peut donc faire apparaître le nom de la table 'Comporter' devant le nom du champ 'Quantite' employé.

Ici aussi, le lecteur qui a observé qu'il était fait mention de plusieurs tables dans l'énoncé, se sera étonné de voir cet exercice présent ici et pas dans la série d'exercices concernant les jointures. La résolution ne fait appel qu'à une seule table, donc pas de jointure.

retour Q24

 

 

 

 

 

  

R25

Analyse préalable

Champs à afficher Prix moyen hors TVA (moyenne des Produits.PU_HTVA)
Tables concernées Produits
Conditions aucune
Classement aucun

SELECT AVG (Produits.PU_HTVA) AS Prix_moyen
FROM Produits ;

Il n'y a qu'un seul élément à afficher, Prix_moyen... qui n'est pas un élément de la table, mais résulte d'un calcul opéré sur tous les champs 'PU_HTVA' de la table.

La fonction Avg(...) est une fonction de regroupement... elle fait la moyenne des champs qui répondent à la condition donnée dans WHERE (même si dans ce cas, il n'y a pas de WHERE).

L'opérateur AS permet de nommer, créer ce nouvel élément, résultat d'un calcul (d'une fonction statistique) portant sur ce champ existant [le lecteur aura remarqué que seul le champ Produits.PU_HTVA aurait pu convenir, puisqu'il s'agit de faire la moyenne des prix HTVA pour tous les produits]  ;
ce nouvel élément Prix_moyen n'est pas un champ de la table... on ne peut donc pas le précéder du nom de la table ;
le calcul porte sur un champ de la table... on peut donc faire apparaître le nom de la table 'Produits' devant le nom du champ 'PU_HTVA' employé.

La fonction MOYENNE se note AVG, raccourci de AVERAGE.

retour Q25

 

 

 

 

 

  

R26

Analyse préalable

Champs à afficher Prix maximal hors TVA (maximum des Produits.PU_HTVA)
Tables concernées Produits
Conditions aucune
Classement aucun

SELECT MAX (Produits.PU_HTVA) AS Prix_maximal
FROM Produits ;

Il n'y a qu'un seul élément à afficher, Prix_maximal... qui n'est pas un élément de la table, mais résulte d'un calcul opéré sur tous les champs 'PU_HTVA' de la table.

La fonction Max(...) est une fonction de regroupement... elle dénombre les champs qui répondent à la condition donnée dans WHERE (même si dans ce cas, il n'y a pas de condition WHERE).

L'opérateur AS permet de nommer, créer ce nouvel élément, résultat d'un calcul (d'une fonction statistique) portant sur ce champ existant [le lecteur aura remarqué que seul le champ Produits.PU_HTVA aurait pu convenir, puisqu'il s'agit de trouver la plus grande valeur des prix HTVA pour tous les produits]  ;
ce nouvel élément Prix_maximal n'est pas un champ de la table... on ne peut donc pas le précéder du nom de la table ;
le calcul porte sur un champ de la table... on peut donc faire apparaître le nom de la table 'Produits' devant le nom du champ 'PU_HTVA' employé.

La fonction MAXIMUM se note MAX, et le lecteur aura deviné le sens de MIN.

retour Q26

 

 

 

 

 

  

R27

Analyse préalable

Champs à afficher Num, Nbre_ref (dénombrement pour chaque numéro de commande, dont le détail est dans la table 'Comporter')
Tables concernées Comporter
Conditions aucune
Regroupement Num
Classement aucun

SELECT Comporter.Num, COUNT (Comporter.Codeprod) AS Nbre_ref
FROM Comporter
GROUP BY Comporter.Num ;

Il y a plusieurs éléments à afficher, Nbre_ref... qui ne sont pas des éléments de la table, mais résultent (pour chaque Num de commande) d'un calcul opéré sur tous les champs 'Codeprod' de la table 'Comporter'.

La fonction Count(...) est une fonction de regroupement... elle dénombre les champs qui répondent à la condition donnée dans WHERE (inexistante ici).

L'opérateur AS permet de nommer, créer ce nouvel élément, résultat d'un calcul (d'une fonction statistique) portant sur ce champ existant... sans que ce soit sur tous les champs de la table, mais bien sur des champs regroupés (par Num de commande) ;
ce nouvel élément Nbre_ref n'est pas un champ de la table... on ne peut donc pas le précéder du nom de la table ;
le calcul porte sur un champ de la table... on peut donc faire apparaître le nom de la table 'Comporter' devant le nom du champ 'Codeprod' employé.

Tous les champs ne faisant pas partie d’une fonction d’agrégat de l’ordre SELECT (donc ici, le champ 'Num') doivent être repris dans la clause GROUP BY.

La clause GROUP BY permet de créer des groupes d’enregistrements sur lesquels pourront être utilisées les fonctions d’agrégat. Elle est nécessaire dès lors que l’on souhaite afficher des données issues des tables et des données issues de fonctions d’agrégat. Le lecteur aura compris que ceci explique le pourquoi du paragraphe précédent.

retour Q27

 

 

 

 

 

  

R28

Analyse préalable

Champs à afficher Num, Nbre_ref (dénombrement pour chaque numéro de commande, dont le détail est dans la table 'Comporter')
Tables concernées Comporter
Conditions aucune
Regroupement Num
Filtre Nbre_ref > 5
Classement aucun

SELECT Comporter.Num, COUNT (Comporter.Codeprod) AS Nbre_ref
FROM Comporter
GROUP BY Comporter.Num
HAVING COUNT (Comporter.Codeprod) >5 ;

Le lecteur relira ce qui a été dit dans la question (et la réponse) 27.

La clause HAVING permet d’appliquer des sélections sur les regroupements créés à l’aide de la clause GROUP BY (nous les avons appelés filtres dans notre analyse préalable). Le lecteur pourrait confondre les conditions introduites par WHERE et les 'filtres' introduits par HAVING :
contrairement à l’ordre WHERE qui sélectionne les enregistrements, la clause HAVING sélectionne les résultats d’une fonction d’agrégat.

Tous les champs ne faisant pas partie d’une fonction d’agrégat de l’ordre SELECT (donc ici, le champ 'Num') doivent être repris dans la clause GROUP BY ;
de même, le filtre (having) porte sur la fonction d'agrégat (ici : COUNT (Comporter.Codeprod)) et surtout pas sur son résultat, élément calculé (ici : Nbre_ref).

La clause GROUP BY permet de créer des groupes d’enregistrements sur lesquels pourront être utilisées les fonctions d’agrégat et de filtres sur ces agrégats. Elle est nécessaire dès lors que l’on souhaite afficher des données issues des tables et des données issues de fonctions d’agrégat.

retour Q28

 

 

 

 

 

  

R29

Analyse préalable

Champs à afficher MEDICAMENT.Mmed, MEDICAMENT.Mlib, MEDICAMENT.Mtaux, MEDICAMENT.Mprix,
Remb (calculé sur Mprix et Mlib),
Part (calculé sur Mprix et Mlib),
Tot (somme de Remb et Part)
Tables concernées MEDICAMENT
Conditions aucune
Regroupement aucun
Filtre aucun
Classement aucun

 

En requêteur graphique :

En SQL :

SELECT Medicament.Mmed, Medicament.Mlib, Medicament.Mtaux, Medicament.Mprix, Medicament.Mtaux * Medicament.Mprix AS Remb, (1-Medicament.Mtaux)*Medicament.Mprix AS Part, Remb + Part AS Tot
FROM MEDICAMENT ;

Le lecteur relira ce qui a été dit dans la question (et la réponse) 27.

La clause HAVING permet d’appliquer des sélections sur les regroupements créés à l’aide de la clause GROUP BY (nous les avons appelés filtres dans notre analyse préalable). Le lecteur pourrait confondre les conditions introduites par WHERE et les 'filtres' introduits par HAVING : contrairement à l’ordre WHERE qui sélectionne les enregistrements, la clause HAVING sélectionne les résultats d’une fonction d’agrégat.

Tous les champs ne faisant pas partie d’une fonction d’agrégat de l’ordre SELECT (donc ici, le champ 'Num') doivent être repris dans la clause GROUP BY ;
de même, le filtre porte sur la fonction d'agrégat (ici : COUNT (Comporter.Codeprod)) et surtout pas sur son résultat, élément calculé (ici : Nbre_ref).

La clause GROUP BY permet de créer des groupes d’enregistrements sur lesquels pourront être utilisées les fonctions d’agrégat et de filtres sur ces agrégats. Elle est nécessaire dès lors que l’on souhaite afficher des données issues des tables et des données issues de fonctions d’agrégat.

retour Q29

 

 

 

 

 

  

R30 (d'après PhDa)

 

SELECT Code Client SUM commandes

FROM Client, Articles

WHERE Client, Code client = Utiliser.code client

AND Code client = P0152

 

Cette requête totalise la somme de toutes les commandes d'un client qui a comme clef P0152.

On remarquera cependant les incorrections suivantes :
- Le champ 'code client', comprenant une espace, aurait dû soit remplacer l'espace par un underscore, soit s'écrire entre crochet ;
- L'écriture du champ 'code client' se fait tantôt avec deux capitales, tantôt avec une seule et tantôt sans aucune capitale... il faut considérer que cette requête ne sera pas portable sur les OS autres que Windows...
- Le champ 'code client' de la table 'client' ne doit pas être séparé par une virgule suivie d'une espace, mais uniquement d'un point ;
- La requête devrait se terminer par un point-virgule.

retour Q30

 

 

 

 

 

  

R31

Analyse préalable

Champs concernés tous (nouvel enregistrement à insérer)
Tables concernées Produits
Conditions aucune
Regroupement aucun
Filtre aucun
Classement aucun

INSERT INTO Produits (Codeprod, Designation, PU_HTVA)
VALUES ('P14689' , 'Tout ce que les étudiants ont toujours voulu savoir sur le logiciel Access' , '22') ;

Le lecteur notera que la requête d'insertion de nouveaux enregistrements nécessite :
* de préciser après l'instruction INSERT INTO, le nom de la table et des champs (pas nécessairement tous) que l'on veut préciser ;
* de préciser dans l'instruction VALUES la valeur de ces champs dans le même ordre que les champs notés dans l'instruction INSERT INTO.

ATTENTION, les valeurs des champs nouveaux entrées ne peuvent pas contenir d'apostrophes... sinon confusion entre les apostrophes délimitateurs de champs. :-(

retour Q31

 

 

 

 

  

R32

Analyse préalable

Champs concernés Designation (enregistrement à corriger)
Tables concernées Produits
Conditions Codeprod='P146889'
Regroupement aucun
Filtre aucun
Classement aucun

UPDATE Produits
SET Produits.Designation = 'La bible pour un Accesseur'
WHERE Codeprod='P146889' ;

Le lecteur notera que la requête de modification de nouveaux enregistrements nécessite :
* de préciser après l'instruction UPDATE, le nom de la table ;
* de préciser après l'instruction SET le nom de champs à modifier, suivi d'un égal et de la nouvelle valeur entre apostrophes ;
* et surtout un WHERE qui précisera quel enregistrement est à modifier (suggestion : emploi d'une clé primaire).

ATTENTION, les valeurs des champs nouveaux entrées ne peuvent pas contenir d'apostrophes... sinon confusion entre les apostrophes délimitateurs de champs. :-(

retour Q32

 

 

 

 

 

  

R33

Analyse préalable

Champs concernés PU_HTVA (champ à corriger)
Tables concernées Produits
Conditions aucune
Regroupement aucun
Filtre aucun
Classement aucun

UPDATE Produits
SET Produits.PU_HTVA = Produits.PU_HTVA * 1.02 ;

Le lecteur notera une dernière fois que la requête de modification de nouveaux enregistrements nécessite :
* de préciser après l'instruction UPDATE, le nom de la table ;
* de préciser après l'instruction SET le nom de champs à modifier, suivi d'un égal et de la nouvelle valeur entre apostrophes ;
* et surtout un WHERE qui précisera quel(s) enregistrement(s) est(sont) à modifier (suggestion : emploi d'une clé primaire)... mais ici inutile, car la modification portait sur tous les enregistrements.

Le lecteur aura compris qu'on aurait pu modifier les prix des articles en magasin qui coûtaient plus de 5 €... ou toute autre précision.

ATTENTION, les valeurs des champs nouveaux entrées ne peuvent pas contenir d'apostrophes... sinon confusion entre les apostrophes délimitateurs de champs. :-(
Un début de solution :
remplacer le ' par \' pour tout ce qui est du SQL en javascript ;
doubler l'apostrphe en ASP ' deviendra '', qui n'est pas un guillemet...
remplacer le ' par " pour le contenu du champ qui aurait dû contenir une apostrophe.

retour Q33

 

 

 

 

 

  

R34

Analyse préalable

Champs concernés tous
Tables concernées Clients
Conditions Ville='Charleroi' ou Ville='La Louvière'
Regroupement aucun
Filtre aucun
Classement aucun

DELETE FROM Clients
WHERE Clients.Ville LIKE 'Charleroi' OR Clients.Ville LIKE 'La Louvière'  ;

Le lecteur notera une dernière fois que la requête de suppression d'enregistrements nécessite :
* de préciser après l'instruction DELETE FROM, le nom de la table ;
* et surtout un WHERE qui précisera quel(s) enregistrement(s) est(sont) à modifier (suggestion : emploi d'une clé primaire pour l'effacement d'un enregistrement précis)... .

ATTENTION, si le WHERE est absent... tous les enregistrements seront effacés... quelle tristesse.

retour Q34

 

 

 

 

 

  

R35

Analyse préalable :

Les 3 tables comprennent au moins les champs suivants :
Vente(code_produit, code_client, qté, ...)
Produit(code_produit, intitulé, type, fournisseur, prix, ...)
Client(code_client, nom, prénom, adresse, ...)

Bien que non précisé dans la requête,
le champ 'prix' ne peut être que le prix d'un produit...
le champ 'qté' pourrait être un champ soit de la table 'produit' soit de la table 'vente'...

Comme la requête multiplie le prix par la quantité...
on croira plus à des quantités vendues qu'à des quantités stockées.

La requête demandera le nom du client,

et pour ce client, affichra les coordonnées du clients, ainsi que les quantités vendues et prix totaux de ces ventes, relatives à ce client.

 

Le but de la requête est donc de saisir toutes les informations demandées pour un client spécifique.

retour Q35

 

 

 

 

 

  

R36

Analyse préalable

Champs à afficher Montant total déboursé par un client
(somme des produits : quantité vendue * prix du produit vendu)
Tables concernées Client, Vente, Produit
Conditions C.nom=[saisir_le_nom]
Et V.code_produit=P.code_produit
Et V.code_client=C.code_client
Classement aucun

SELECT SUM (Comporter.Quantite) AS Q_prodvend
FROM Client, Vente, Produit
WHERE C.nom=[saisir_le_nom] and V.code_produit=P.code_produit and V.code_client=C.code_client ;

Il n'y a qu'un seul élément à afficher... qui n'est pas un élément de la table, mais résulte d'un calcul opéré sur un/plusieurs champs des différentes tables.

La fonction Sum(...) est une fonction de regroupement... elle fait la somme des champs qui répondent aux conditions données dans WHERE.

L'opérateur AS permet de nommer, créer ce nouvel élément, résultat d'un calcul (d'une fonction statistique) portant sur ce champ existant [le lecteur aura remarqué que seuls les champs Vente.qté (ou V.qté) et Produit.prix (ou P.prix) auraient pu convenir, puisqu'il s'agit de faire la somme des produits des quantités vendues de ce produit par le prix du produit, pour toute les commandes qui comportaient un ou plusieurs produits]  ;
ce nouvel élément 'total à payer' n'est pas un champ de la table... on ne peut donc pas le précéder du nom de la table ;
le calcul porte sur des champs de tables... on peut donc faire apparaître le nom de la table 'Vente' devant le nom du champ 'qté' employé, et le nom de la table 'Produit' devant le nom du champ 'prix' employé.

SELECT SUM([qté]*[prix]) AS [total à payer]
FROM Vente AS V, Produit AS P, Client AS C
WHERE (((C.nom)=[saisir_le_nom]) And ((V.code_produit)=P.code_produit) And ((V.code_client)=C.code_client));

retour Q36

 

 

 

 

  

R37

 

SELECT nom, prénom, adresse, intitule, type, fournisseur, qté, prix_total,
          (SELECT SUM([qté]*[prix]) AS [total à payer]
          FROM Vente AS V, Produit AS P, Client AS C
          WHERE (((C.nom)=result.nom) And ((V.code_produit)=P.code_produit) And ((V.code_client)=C.code_client))) as [total à payer]

FROM (
          SELECT C.nom as nom, C.prénom as prénom, C.adresse as adresse, P.intitule as intitule, P.type as type, P.fournisseur as fournisseur, qté, [qté]*[prix] AS [prix_total]
          FROM Vente AS V, Produit AS P, Client AS C
          WHERE (((C.nom)=[saisir_le_nom]) And ((V.code_produit)=P.code_produit) And ((V.code_client)=C.code_client))) as result;

retour Q37

 

 

 

 

 

  

R38

SELECT Enom
FROM Etudiants s, Exams e
WHERE s.Enumero = e.Enumero
AND e.NomCours = ’BD’;

retour Q38

 

 

 

 

 

  

R39

SELECT NomCours, Note
FROM Etudiants, Exams
WHERE EAnNaissance = 1985
     AND Etudiants.Enumero = Exams.Enumero;

retour Q39

 

 

 

 

 

  

R40

SELECT year(dateDeNaissance), count(*) AS combien
FROM stud_anciens GROUP BY year(dateDeNaissance)

La liste ne commencera par forcément par l'année de naissance la plus ancienne, mais sera affichée par ordre des années de naissance rencontrées dans la table... le lecteur pourrait supposé que l'ordre des naissances et l'ordre d'établissement de la table soit identique... c'est faire sans penser qu'un étudiant de quarante ans aurait pu s'inscrire en l'an 2000... et dans une école qui a plus de 160 ans d'histoire...

retour Q40

 

 

 

 

 

  

R41

SELECT year(dateDeNaissance), count(*) AS combien
FROM stud_anciens GROUP BY year(dateDeNaissance)

1.-
SELECT year(dateDeNaissance) AS annee, count(*) AS combien
FROM stud_anciens GROUP BY year(dateDeNaissance) ORDER BY annee

2.-
SELECT year(dateDeNaissance), count(*) AS combien
FROM stud_anciens GROUP BY year(dateDeNaissance) ORDER BY combien

retour Q41

 

 

 

 

  

R42

SELECT year(dateDeNaissance), count(*) AS combien
FROM stud_anciens GROUP BY year(dateDeNaissance)

Le lecteur se rappellera que dans des regroupements, la sélection ne s'effectue pas par un WHERE, mais par un HAVING. La requête se transformera donc en :
SELECT year(dateDeNaissance), count(*) AS combien
FROM stud_anciens GROUP BY year(dateDeNaissance) HAVING cp BETWEEN 6000 et 7999

Comme le suggère la question, les codes postaux commençant par :
1.- 1000 Bruxelles (Brabant)
2.- 2000 Antwerpen (province d'Anvers)
3.- 3000 Hasselt (province de Limbourg)
4.- 4000 Liège (province de Liège)
5.- 5000 Namur (province de Namur)
6.- 6000 Charleroi (partie de la province du Hainaut - oriental)
7.- 7000 Mons (partie de la province du Hainaut - occidental)
8.- 8000 Gent (Flandre occidentale)
9.- 9000 Brugge (Flandre orientale)

 

 

retour Q42

 

 

 

 

 

  

R43

 

24 requêtes concernant une table unique des employés d'une entreprise :

emp (nom, num, fonction, nsup, embauche,salaire, comm, ndept)


num est le numéro de matricule de l'employé (c'est un numéro unique) ;
nsup est le numéro de matricule du supérieur de l'employé ;
embauche est la date à laquelle l'employé a été embauché ;
comm est sa commission annuelle ;
ndept est le numéro du département pour lequel il travaille.

1. Donner les noms et les départements des employés gagnant entre 20000 et 25000.
SELECT nom, ndept
FROM emp
WHERE salaire BETWEEN 20000 AND 25000;
2. Donner les noms et les salaires des employés commerciaux ou ingénieurs.
SELECT nom, salaire
FROM emp
WHERE fonction IN('commercial, 'ingenieur');
3. Donner les noms des employés dont le nom commence par M.
SELECT nom
FROM emp
WHERE nom LIKE 'M%';
4. Donner la liste des employés ayant un nom de 4 lettres se terminant par "O".
SELECT nom
FROM emp
WHERE LENGTH(nom)=4 AND nom LIKE '%O';
5. Donner les noms des employés du département 30 ayant un salaire supérieur à 25000.
SELECT nom
FROM emp
WHERE ndept=30 AND salaire>25000;
6. Donner les noms des employés directeurs, ou commerciaux et travaillants dans le
département 10.
SELECT nom
FROM emp
WHERE fonction='directeur' OR (fonction='commercial' AND ndept=10);
7. Donner les noms des employés directeurs ou commerciaux, et travaillants dans le
département 10.
SELECT nom
FROM emp
WHERE fonction IN('directeur', 'commercial') AND ndept=10;
8. Donner tous les employés classés par fonction, et pour chaque fonction classés par
salaire décroissant.
SELECT *
FROM emp
GROUP BY fonction, salaire DESC;
9. Donner la liste des employés ayant une commission (non nulle), classée par
commission décroissante.
SELECT *
FROM emp
WHERE comm IS NOT NULL
ORDER BY comm DESC;
10. Donner les noms des personnes embauchées après janvier 1991.
SELECT nom
FROM emp
WHERE embauche>'31/01/1991';
11. Donner la liste des employés dont la commission est strictement inférieure à 10% du
salaire.
SELECT nom, salaire, comm
FROM emp
WHERE comm<salaire*.1;
12. Donner les noms des ingénieurs embauchés avant le 1 janvier 1990.
SELECT nom
FROM emp
WHERE fonction='ingenieur' AND embauche<'01/01/1990';
13. Quelles sont les fonctions ne donnant pas lieu à commission.
SELECT fonction
FROM emp
WHERE comm IS NULL;
14. Donner les noms et fonctions de chacun. Classer le résultat par fonction puis par nom.
SELECT nom, fonction
FROM emp
ORDER BY fonction, nom;
15. Donner pour chaque commercial son revenu (salaire + commission).
SELECT nom, salaire+comm "Salaire et commission"
FROM emp
WHERE fonction='commercial';
16. Donner le salaire annuel de chacun.
SELECT nom, salaire*12 "Salaire annuel"
FROM emp;
17. Donner la date d’embauche de chaque employé arrondie à l’année.
SELECT ROUND(embauche,'y') "Années d'embauche"
FROM emp;
18. Donner pour chaque employé le nombre de jours depuis son embauche.
SELECT ROUND(SYSDATE-embauche) "Nombre de jours depuis l'embauche"
FROM emp;
19. Donner la liste de tous les employés dont le nom ressemble à ‘DUPONT’.
SELECT nom
FROM emp
WHERE SOUNDEX(nom) = SOUNDEX('DUPONT');
20. Afficher tous les salaires avec un $ en tête et au moins trois chiffres (dont deux
décimales).
SELECT CONCAT('$',TO_CHAR(salaire,'99900.00'))
FROM emp;
21. Donner la liste de tous les noms des employés en ayant supprimé tous les 'L' et les 'E'
en tête des noms.
SELECT LTRIM(nom,'LE')
FROM emp;
Autre solution :
SELECT SUBSTR(nom,2)
FROM emp
WHERE nom LIKE 'L%' OR nom LIKE 'E%';
22. Donner la liste de tous les noms des employés en ayant remplacé les A et les M par
des * dans les noms.
SELECT TRANSLATE(nom,'AM','**')
FROM emp;
23. Donner la date du lundi suivant l'embauche de chaque employé.
SELECT NEXT_DAY(embauche,'LUNDI')
FROM emp;
24. Donner pour chaque employé son salaire journalier arrondi aux centimes et son salaire
journalier arrondi à la centaine. (Il y a environ 22 jours travaillés par mois).
SELECT nom, ROUND(salaire/22,2)
FROM emp;

 

retour Q43

 

 

 

 

 

  

R44

Le code SQL exécuté est le suivant :

SELECT tblVacances.NomEmployé, tblVacances.DébutVac, tblVacances.FinVac
FROM tblVacances
GROUP BY tblVacances.NomEmployé, tblVacances.DébutVac, tblVacances.FinVac
HAVING (((tblVacances.DébutVac)<#7/16/2001#) AND ((tblVacances.FinVac)<#8/16/2001# And (tblVacances.FinVac)>#7/14/2001#))
         OR (((tblVacances.DébutVac)<#7/16/2001#) AND ((tblVacances.FinVac)>#8/14/2001#))
         OR (((tblVacances.DébutVac)>#7/14/2001#) AND ((tblVacances.FinVac)<#8/16/2001#))
         OR (((tblVacances.DébutVac)>#7/14/2001# And (tblVacances.DébutVac)<#8/16/2001#) AND ((tblVacances.FinVac)>#8/14/2001#)))
ORDER BY tblVacances.DébutVac, tblVacances.FinVac;

Le lecteur notera la conversion en format américain des dates entrées en format européen...

Le lecteur notera également l'importance des parenthèses :
- chaque ligne qui comprend une condition OR est encadrée par des parenthèses de 3e niveau (notées en vert) ;
- chaque ligne (qui est une condition OR, comprend elle-même plusieurs conditions AND, chacune encadrée par des parenthèses de 2e niveau (notées en rouge) ; l'auteur de cette requête aurait cependant pu généraliser l'emploi de ces parenthèses rouges en 1re et 4e ligne ; de plus, le AND étant prioritaire par rapport au OR, il aurait pu supprimer ces parenthèses rouges...
- les parenthèses noires sont inutiles, mais facilite la lecture du champ encadré ;
- les OR s'effectuant après les AND, l'auteur de cette requête aurait pu négliger les parenthèses notées en vert.

Rappelons que :
Lorsque une condition HAVING comporte des groupes placés entre parenthèses, ces groupes sont évalués en premier.
Une fois ces groupes évalués, les règles suivantes sont appliquées lorsque ces opérateurs logiques sont utilisés dans les conditions de recherche de contenu :

* NOT est appliqué avant AND.
* NOT peut uniquement être utilisé après AND, comme dans AND NOT. L'opérateur OR NOT n'est pas autorisé. NOT ne peut pas être spécifié avant le premier terme.
* AND est appliqué avant OR.
* Les opérateurs booléens de même type (AND, OR) sont associatifs et peuvent donc être utilisés dans un ordre quelconque.

En résumé,
NOT
&&, AND
XOR
||, OR

De même, 1 + 2 * 3 = 7 et (1 + 2) * 3 = 9

Généralement une requête de ce type sera la source d'un état.

retour Q44

 

 

 

 

 

  

R45

SELECT Nom, Prénom, Fonction
FROM Employés;

Le lecteur attentif pourrait s'étonner qu'Access note d'office 'requête sélection', alors qu'il ne s'agit ici que d'une projection, puisqu'il n'y a aucun critère de sélection (where). Access ne fait pas cette différence théorique.

retour Q45

 

 

 

 

 

  

R46

 

Analyse préalable

Champs concernés droit_inscrip (à afficher : la moyenne),
prime_resp (à afficher : la moyenne),
tarif_hr (à afficher : la moyenne)
Tables concernées Cours
Conditions aucune
Regroupement aucun, mais moyenne des éléments
Filtre aucun
Classement aucun

SELECT nom, COUNT(*) AS [nombre de cours animé]
FROM animateurs, animer
WHERE animateurs.matricule_animateur = animer.matricule_animateur
AND nom = [Saisir le nom de l'animateur]
GROUP BY nom

 

 

Analyse préalable

Champs concernés droit_inscip (à afficher : la moyenne),
prime_resp (à afficher : la moyenne),
tarif_hr (à afficher : la moyenne)
Tables concernées Cours
Conditions aucune
Regroupement aucun, mais moyenne des éléments
Filtre aucun
Classement aucun

SELECT libellé
FROM catégories, thèmes, cours
WHERE catégories.code_catégorie = thèmes.code_catégorie
AND thèmes.code_thème = cours.code_thème
GROUP BY libellé
HAVING COUNT(*) >3

 

 

Analyse préalable

Champs concernés droit_inscip (à afficher : la moyenne),
prime_resp (à afficher : la moyenne),
tarif_hr (à afficher : la moyenne)
Tables concernées Cours
Conditions aucune
Regroupement aucun, mais moyenne des éléments
Filtre aucun
Classement aucun

SELECT nom
FROM animer, animateurs
WHERE animateurs.matricule_animateur = animer.matricule_animateur
GROUP BY nom
HAVING COUNT(*) > ( SELECT COUNT(*)
FROM animer, animateurs
WHERE animateurs.matricule_animateur =
animer.matricule_animateur
AND nom = [Saisir le nom de l'animateur]

retour Q46

 

 

 

 

  

R47

Clients (Codecli, Nom, Prenom, Adresse, CP, Ville, Tel)
Commande (Num, Date, #Codecli)
Produits (Codeprod, Designation, PU_HTVA)
Comporter (Codeprod, Num, Quantite)

Les requêtes suivantes ne donneront pas forcément la même réponse :

SELECT Nom, Date
FROM Clients, Commande
WHERE Clients.Codecli = Commande.Codecli ;

et

SELECT Nom, Date
FROM Clients, Commande
WHERE Clients.Codecli = Commande.Codecli
    AND Clients.Tel not null ;

car n'apparaîtront pas dans la seconde requête les clients dont le téléphone n'aura pas été encodé dans la table Clients...

Les pros d'Access parlent de jointure naturelle quand le lien entre les tables est fait par la clef primaire d'une table (Codecli) qui est une clef secondaire (ou étrangère) de l'autre table ; c'est le cas ici. On aurait dû préférer écrire :

SELECT Nom, Date
FROM Clients NATURAL JOIN Commande ;

ou, encore mieux :

SELECT Nom, Date
FROM Clients NATURAL JOIN Commande
USING Codecli ;

mais ce type de jointure exige que les champs qui servent à faire la jointure soit strictement identiques... y compris le nom du champ...

retour Q47

 

 

 

 

 

  

R48

Clients (Codecli, Nom, Prenom, Adresse, CP, Ville, Tel)
Commande (Num, Date, #Codecli)
Produits (Codeprod, Designation, PU_HTVA)
Comporter (Codeprod, Num, Quantite)

Expliquer pourquoi la requête suivante devient d'une plus grande utilité :

SELECT Nom, Date
FROM Clients, Commande
WHERE Clients.Codecli = Commande.Codecli

Notre but était d'afficher chaque nom de client avec le(s) date(s) de commande(s) qu'il a faite(s)...
Or, nous venons de dire explicitement que nous voulons les noms des clients [dont la reférence Codecli dans la base Clients soit la même que la référence Codecli des clients qui ont passé commande...] et les dates de ces commandes...

Le lecteur aura noter l'oubli du point-virgule qui doit achever toute requête SQL.

Signalons au lecteur qu'il était possible d'employer ici la technique du surnommage : on attribue un surnom à chacune des tables présente dans la partie FROM du SELECT ; ainsi, on aurait pu avoir la requête suivante :

SELECT Nom, Date
FROM Clients Cl, Commande Co
WHERE Cl.Codecli = Co.Codecli ;

retour Q48

 

 

 

 

 

  

R49

Clients (Codecli, Nom, Prenom, Adresse, CP, Ville, Tel)
Commande (Num, Date, #Codecli)
Produits (Codeprod, Designation, PU_HTVA)
Comporter (Codeprod, Num, Quantite)

Expliquer pourquoi la requête suivante n'est pas d'une plus grande utilité :

SELECT Nom, Date
FROM Clients, Commande
WHERE Codecli = Codecli ;

Nous n'avons pas fait mieux, car nous avons créé une clause toujours vraie, un peu à la manièreb de 1 = 1 !
En fait il nous manque une précision : il s'agit de déterminer de quelles tables proviennent les champs Codecli de droite et de gauche. Il aurait fallu préciser à l'aide d'une notation pointée en donnant le nom de la table (Clients.Codecli ou Commande.Codecli).

Il est donc nécessaire d'indiquer au compilateur la provenance de chacune des champs Codecli et donc d'opérer une distinction entre l'une et l'autre colonne (ou champ ou attribut).
Ainsi, chaque colonne (attribut ou champ) devra être précédée du nom de la table, suivi d'un point.

retour Q49

 

 

 

 

 

  

R50

Clients (Codecli, Nom, Prenom, Adresse, CP, Ville, Tel)
Commande (Num, Date, #Codecli)
Produits (Codeprod, Designation, PU_HTVA)
Comporter (Codeprod, Num, Quantite)

La requête suivante n'est d'aucune utilité :

SELECT Nom, Date
FROM Clients, Commande ;

Car cette requête ne possède pas de critère de jointure entre une table et l'autre (Clients et Commande). Même si notre intention était d'avoir la liste des clients et les dates de leur(s) commande(s).

Dans cette requête, le compilateur SQL calcule le produit cartésien des deux ensembles, c'est à dire qu'à chaque ligne de la première table (Clients), il accole l'ensemble des lignes de la seconde (Commande) à la manière d'une "multiplication des petits pains" !

Nous verrons qu'il existe une autre manière, normalisée cette fois, de générer ce produit cartésien. Mais cette requête est à proscrire. Dans notre exemple elle génère autant de lignes... que le nombre de clients multiplié par le nombre de commandes... Utile ?

Il faut donc définir absolument un critère de jointure.

retour Q50

 

 

 

 

 

  

R51

Pour chaque participant afficher le numéro matricule, le nom, le prénom ainsi que le nombre de cours auxquels il a participé.

Analyse préalable

Champs concernés matricule, nom, prénom (à afficher : total des cours suivis)
Tables concernées participants, participer
Conditions participants.matricule = participer.matricule
Regroupement par matricule, nom, prénom
Filtre aucun
Classement aucun

SELECT matricule, nom, prénom, COUNT(*) AS [nombre de cours]
FROM participants , participer
WHERE participants.matricule = participer.matricule
GROUP BY matricule, nom, prénom

 

Afficher le numéro matricule, le nom et le prénom ainsi que le nombre total d’heures prestées par chaque animateur.

Analyse préalable

Champs concernés animateurs.matricule_animateur, nom, prénom (à afficher : somme des heures prestées)
Tables concernées animateurs, animer
Conditions animateurs.matricule_animateur = animer.matricule_animateur
Regroupement par animateurs.matricule_animateur, nom, prénom
Filtre aucun
Classement aucun

 

SELECT animateurs.matricule_animateur, nom, prénom, SUM(nbre_heures)
AS [nombre total d'heures prestées]
FROM animateurs, animer
WHERE animateurs.matricule_animateur = animer.matricule_animateur
GROUP BY animateurs.matricule_animateur, nom, prénom

Ces deux exercices se ressemblent étrangement... mais pour le premier il faudra compter le nombre d'enregistrements par participant, tandis que pour le deuxième il faudra faire la somme du contenu de chaque champ nbre_heures par animateur.

retour Q51

 

 

 

 

  

R52

Afficher pour chaque entreprise (code et nom de l’entreprise) le nombre de participants triés suivant l’ordre croissant des noms d’entreprise.

Analyse préalable

Champs concernés

entreprises.code_entreprise,
entreprises.nom,
dénombrement de [nombre de participants]

Tables concernées entreprises, participants
Conditions entreprises.code_entreprise = participants.code_entreprise
Regroupement selon entreprises.code_entreprise, entreprises.nom
Filtre aucun
Classement selon entreprises.nom

SELECT entreprises.code_entreprise, entreprises.nom, COUNT(*)
AS [nombre de participants]
FROM entreprises, participants
WHERE entreprises.code_entreprise = participants.code_entreprise
GROUP BY entreprises.code_entreprise, entreprises.nom
ORDER BY entreprises.nom

retour Q52

 

 

 

 

 

  

R53

SELECT *
FROM Clients;

Le lecteur se rappellera que le joker '*' signifie 'toutes rubriques' ou 'tous les champs'.

retour Q53

 

 

 

 

 

  

R54

SELECT *
FROM Clients
WHERE Ville="Paris";

retour Q54

 

 

 

 

 

  

R55

SELECT Société, Adresse, [Code postal], Ville, Téléphone, Fax
FROM Clients
WHERE Ville="Stuttgart";

Le lecteur aura observé que les conventions informatiques relatives à la portabilité des fichiers ont été peu utilisées dans cet exercice : il aurait été profitable de ne pas utiliser de caractères accentués dans les noms de champs, de même, l'emploi d'espace dans les noms de champs est compensé par l'emploi des crochets.

Attention : La rubrique ou champ Nom n’existe pas dans Clients, et Adresse est insuffisant, il faut y ajouter les champs 'code postal' et 'ville'.

retour Q55

 

 

 

 

 

  

R56

 

.

retour Q56

 

 

  

R57

 

.

retour Q57

 

 

 

 

 

  

R58

 

.

retour Q58

 

 

 

 

 

  

R59

Analyse préalable

Champs à afficher Code Equipe, date de fabrication (en réponse à une question posée), nombre de brames
Tables concernées 1 seule table : Coulées
Conditions Clients.Codecli = Commande.Codecli
AND Clients.Nom LIKE "Dalors"
AND Clients.Prenom LIKE "Homère"
Regroupement oui, selon la réponse donnée au paramètre (date de fabrication)
Classement aucun

 

Il ne s'agit pas ici d'une requête de jointure, puisqu'il n'est fait appel qu'à une seule table... comme on travaille dans une base comportant plusieurs tables, il peut être prudent de rappeler le nom de cette table.

On a affaire à une requête paramétrée ; en effet, l'utilisateur devra répondre à une question [entrez la date (m/jj/aa)].

La traduction SQL de la requête du requêteur graphique est :

A)

SELECT Coulées.[Code Equipe], Coulées.[date de fabrication], Count(Coulées.[nombre de brames]) AS [CompteDenombre de brames]
FROM Coulées
GROUP BY Coulées.[Code Equipe], Coulées.[date de fabrication]
HAVING (((Coulées.[date de fabrication]) Like "*" & [entrez la date (m/jj/aa)] & "*"));

Mais, un lecteur attentif devrait nous faire remarquer que la requête ci-dessus ne compte pas le nombre de brames, mais le nombre de coulées, sans tenir compte de la valeur de l'argument [nombre de brames] de chaque coulée...

Count ne fait que compter le nombre d'enregistrements, Sum fait la somme du contenu d'une colonne...

Pour en tenir compte, il aurait fallu non pas les compter (le nombre de fois que l'argument apparaît), mais en faire leur somme... d'où, la réponse (non conforme à notre requête graphique, qui aurait dû mentionner 'somme' au lieu de 'compte')...

SELECT Coulées.[Code Equipe], Coulées.[date de fabrication], Sum(Coulées.[nombre de brames]) AS [CompteDenombre de brames]
FROM Coulées
GROUP BY Coulées.[Code Equipe], Coulées.[date de fabrication]
HAVING (((Coulées.[date de fabrication]) Like "*" & [entrez la date (m/jj/aa)] & "*"));

B)

Quelle est la production journalière du jour dont on entre la date ?

retour Q59

 

 

 

 

 

 

  

R60

Analyse préalable

Champs à afficher Commande.Num
Tables concernées 2 tables : Commande et Client
Conditions Clients.Codecli = Commande.Codecli
AND Clients.Nom LIKE "Dalors"
AND Clients.Prenom LIKE "Homère"
Classement ORDER BY Commande.Date DESC

 

Un seul champ à afficher (Num) de la table Commande, mais ce champ peut avoir différentes valeurs.

Requête de jointure puisqu'on travaille dans 2 tables unifiées par 'Clients.Codecli = Commande.Codecli'.
Relation de 1 à plusieurs, puisque une commande ne peut être passée que par un client, mais un client peut passer différentes commandes.

Un classement par ordre de date descendant, cela veut donc dire en commençant par les plus récentes commandes et en allant vers les plus anciennes.

A) Notre but est donc d'afficher le (ou les) numéro(s) de commande(s) qui ont été passées par un client (mais rien ne garantit qu'il soit unique) s'appelant 'Homère Dalors', en commençant par les commandes les plus récentes.

B) S'il s'agissait d'un OR, notre but aurait été d'afficher le (ou les) numéro(s) de commande(s) qui ont été passées par tous les clients prénommés 'Homère' ou dont le nom de famille est 'Dalors', en commençant par les commandes les plus récentes.

 

retour Q60

 

 

 

 

 

  

R61

Analyse préalable

Champs à afficher Nom, Prenom
Tables concernées Employes
Conditions Prenom = 'roger'
Classement aucun

SELECT Employes.Nom, Employes.Prenom
FROM Employes
WHERE Employes.Prenom="roger" ;

Dans cet exemple, le lecteur notera l’utilisation du point qui sépare le nom de la table (ou relation) et les attributs (ou champs).
Lorsqu'il n'y a aucun risque de confusion (homonymie, etc.), il est possible de supprimer le nom de la table (et le point qui sépare). On aurait alors :

SELECT Nom, Prenom
FROM Employes
WHERE Prenom="roger";

On notera qu'Access sous Windows ne nécessite pas l'emploi des guillemets... comme il s'agit d'un champ de type 'texte', Access notera ces guillemets d'office. De même, il marquerait d'un # les champs de type 'date' et rien pour les champs de type 'numérique' ou 'monétaire'.

$$$image req graph

retour Q61

 

 

 

  

R62

Afficher pour chaque participant son nom et son prénom, le nom de son entreprise ainsi que les thèmes (en toutes lettres) des cours auxquels il a participés (triés suivant les numéros matricules des participants et des thèmes)

Analyse préalable

Champs concernés participants.nom,
prénom, entreprises.nom,
thèmes.désignation
Tables concernées thèmes,
cours,
participants,
participer,
entreprises
Conditions participants.matricule = participer.matricule,
ET entreprises.code_entreprise = participants.code_entreprise,
ET cours.code_cours = participer.code_cours,
ET thèmes.code_thème = cours.code_thème
Regroupement aucun, mais moyenne des éléments
Filtre aucun
Classement

1re clef : participants.matricule,
2e clef : thèmes.code_thème

SELECT participants.nom, prénom, entreprises.nom, thèmes.désignation
FROM thèmes, cours, participants, participer, entreprises
WHERE participants.matricule = participer.matricule
AND entreprises.code_entreprise = participants.code_entreprise
AND cours.code_cours = participer.code_cours
AND thèmes.code_thème = cours.code_thème
ORDER BY participants.matricule, thèmes.code_thème

Excellente utilisation de jointures multiples. Elles ont été résolues ci-avant par des WHERE, méthode d'access pour les versions précédentes... l'avenir fera usage de l'insruction JOIN...

 

retour Q62

 

 

 

 

 

  

R63

 

Afficher pour chaque cours le code cours, le nom et le prénom de l’animateur responsable.

Analyse préalable

Champs concernés code_cours, nom, prénom
Tables concernées animateurs, cours
Conditions animateurs.matricule_animateur = cours.matricule_animateur
Regroupement aucun
Filtre aucun
Classement aucun

SELECT code_cours, nom, prénom
FROM animateurs, cours
WHERE animateurs.matricule_animateur = cours.matricule_animateur

 

Afficher pour chaque cours son code, le thème et le nom et le prénom de l’animateur responsable.

Analyse préalable

Champs concernés

code_cours, désignation
nom, prénom

Tables concernées animateurs, thèmes, cours
Conditions animateurs.matricule_animateur = cours.matricule_animateur ET
thèmes.code_thème = cours.code_thème
Regroupement aucun
Filtre aucun
Classement aucun

SELECT code_cours, désignation, nom, prénom
FROM animateurs , thèmes, cours
WHERE thèmes.code_thème = cours.code_thème
AND animateurs.matricule_animateur = cours.matricule_animateur

retour Q63

 

 

 

 

 

  

R64

Afficher le code entreprise et le nombre total de participants par entreprise.

Analyse préalable

Champs concernés code_entreprise, tous (à afficher : total)
Tables concernées Participants
Conditions aucune
Regroupement par code_entreprise
Filtre aucun
Classement aucun

SELECT code_entreprise, COUNT(*) AS [nombre de participants]
FROM participants
GROUP BY code_entreprise;

Afficher le numéro matricule et le nombre total d’heures prestées pour les animateurs ayant presté plus de 10 heures.

Analyse préalable

Champs concernés matricule_animateur, nbre_heures (à afficher : total)
Tables concernées Animer
Conditions aucune
Regroupement par matricule_animateur
Filtre somme(nbre_heures) > 10
Classement aucun

SELECT matricule_animateur, SUM(nbre_heures) AS [nombre d'heures prestées]
FROM animer
GROUP BY matricule_animateur
HAVING SUM(nbre_heures) >10;

Afficher le numéro matricule et le nombre total d’heures prestées pour les animateurs ayant presté plus de 10 heures et qui sont nés en 68.

Analyse préalable

Champs concernés matricule_animateur, nbre_heures (à afficher : total)
Tables concernées Animer
Conditions matricule_animateur like "1968*"
Regroupement par matricule_animateur
Filtre somme(nbre_heures) > 10
Classement aucun

SELECT matricule_animateur, SUM(nbre_heures) AS [nombre d'heures prestées]
FROM animer
WHERE matricule_animateur like "1968*"
GROUP BY matricule_animateur
HAVING SUM(nbre_heures) >10;

Le lecteur attentif pourrait se demander s'il n'était pas plus facile de considérer la condition (matricule_animateur like "1968*") comme filtre à la place de la considérer comme condition... l'ordinateur devrait alors faire les sommes pour tous les animateurs, calcul inutile si l'animateur n'a pas un matricule commençant par "1968"...

Le lecteur aura aussi remarqué que la condition sur un regroupement ne commence pas par un WHERE, mais bien par HAVING...

retour Q64

 

 

 

 

  

R65

 

Calculer le total des heures prestées par l’animateur ayant le numéro matricule 19800202222.

Analyse préalable

Champs concernés nbre_heures (à afficher : total)
Tables concernées Animer
Conditions matricule_animateur = “19800202222”
Regroupement aucun
Filtre aucun
Classement aucun

SELECT SUM(nbre_heures)
AS [total des heures prestées par l’animateur 19800202222]
FROM animer
WHERE matricule_animateur = “19800202222”

Afficher le numéro matricule et le nombre total d’heures prestées par chaque animateur tirés suivant l’ordre croissant des numéros matricule.

Analyse préalable

Champs concernés nbre_heures (à afficher : total), matricule_animateur
Tables concernées Animer
Conditions aucune
Regroupement par matricule_animateur
Filtre aucun
Classement par matricule_animateur

SELECT matricule_animateur, SUM(nbre_heures)
AS [nombre total d'heures prestées]
FROM animer
GROUP BY matricule_animateur
ORDER BY matricule_animateur

retour Q65

 

 

 

 

 

  

R66

Calculer le total des heures prestées par les animateurs pour tous les cours.

Analyse préalable

Champs concernés nbre_heures (à afficher : total)
Tables concernées Animer
Conditions aucune
Regroupement aucun
Filtre aucun
Classement aucun

SELECT SUM(nbre_heures) AS [total des heures prestées]
FROM animer

Calculer le total des heures prestées par les animateurs pour le cours no 005.

Analyse préalable

Champs concernés nbre_heures (à afficher : total)
Tables concernées Animer
Conditions code_cours='005'
Regroupement aucun
Filtre aucun
Classement aucun

SELECT SUM(nbre_heures) AS [total des heures prestées pour le cours 005]
FROM animer
WHERE code_cours = “005”

retour Q66

 

 

 

 

  

R67

Quel est le code du cours dont le droit d’inscription est le plus élevé ?

Analyse préalable

Champs concernés code_cours
Tables concernées Cours
Conditions droit_inscript est le maximum de droit_inscript (requête)
Regroupement aucun
Filtre aucun
Classement aucun

SELECT code_cours
FROM cours
WHERE droit_inscrip = (SELECT MAX(droit_inscrip)
FROM cours
);

Quel est le code du cours dont le droit d’inscription est le plus bas ?

Analyse préalable

Champs concernés code_cours
Tables concernées Cours
Conditions droit_inscript est le minimum de droit_inscript (requête)
Regroupement aucun
Filtre aucun
Classement aucun

SELECT code_cours
FROM cours
WHERE droit_inscrip = (SELECT MIN(droit_inscrip)
FROM cours
);

Ces deux exercices peuvent servir d'exemples pour ceux qui veulent introduire la notion de "requêtes imbriquées". Il s'agit en effet de requêtes qui font appel au(x) résultat(s) d'une autre requête (que nous avons notée en rouge ci-dessus.

Le lecteur sera attentif au jeu de parenthèses... celles encadrant la requête et celles nécessaires dans la requête.

retour Q67

 

 

 

 

 

  

R68

Calculer la moyenne des droits d’inscription, des primes de responsabilité et des tarifs heure.

Analyse préalable

Champs concernés droit_inscip (à afficher : la moyenne),
prime_resp (à afficher : la moyenne),
tarif_hr (à afficher : la moyenne)
Tables concernées Cours
Conditions aucune
Regroupement aucun, mais moyenne des éléments
Filtre aucun
Classement aucun

SELECT AVG(droit_inscip) AS [droit d’inscription moyen],
AVG(prime_resp) AS [prime de responsabilité moyenne],
AVG(tarif_hr) AS [tarif heur moyen]
FROM cours;

Combien de cours organise-t-on pour chaque niveau ?

Analyse préalable

Champs concernés tous (à afficher : le comptage)
Tables concernées Cours
Conditions aucune
Regroupement selon niveau (à afficher : le comptage)
Filtre aucun
Classement aucun

SELECT niveau, COUNT(*) AS [nombre de cours]
FROM cours
GROUP BY niveau;

retour Q68

 

 

 

 

 

  

R69


1. Quel est le nombre de cours organisés ?

Analyse préalable

Champs concernés tous (à afficher : le comptage)
Tables concernées Cours
Conditions aucune
Regroupement aucun, mais comptage des éléments
Filtre aucun
Classement aucun

 

SELECT COUNT(*) AS [nombre total de cours]
FROM cours;

2 . Combien de participants a-t-on eus dans tous les cours ?

Analyse préalable

Champs concernés tous (à afficher : le comptage)
Tables concernées Participer
Conditions aucun
Regroupement aucun, mais comptage des éléments
Filtre aucun
Classement aucun

 

SELECT COUNT(*) AS [nombre total de participants]
FROM participer;

3 . Combien de participants a-t-on eus pour le cours no 026 ?

Analyse préalable

Champs concernés tous (à afficher : le comptage)
Tables concernées participer
Conditions code_cours='026'
Regroupement aucun, mais comptage des éléments
Filtre aucun
Classement aucun

 

SELECT COUNT(*) AS [nombre participants au cours 026]
FROM participer
WHERE code_cours = “026”;

 

retour Q69

 

 

 

 

 

  

R70

Avec le requêteur graphique : 

En langage SQL : 

SELECT Count(Leçon.Id_moniteur) AS NB
FROM Moniteur INNER JOIN Leçon ON Moniteur.Id_Moniteur = Leçon.Id_moniteur
GROUP BY Moniteur.Id_Moniteur, Moniteur.Nom_moniteur
HAVING (((Moniteur.Nom_moniteur)="suzuki"));

Le lecteur...

retour Q70

 

 

 

 

 

  

R71

Avec le requêteur graphique : 

En langage SQL, variante préférée avec JOIN : 

SELECT Count(Leçon.Id_moniteur) AS NB
FROM Moniteur INNER JOIN Leçon ON Moniteur.Id_Moniteur = Leçon.Id_moniteur
GROUP BY Moniteur.Id_Moniteur, Moniteur.Nom_moniteur
HAVING (((Moniteur.Nom_moniteur)="suzuki"));

En langage SQL, variante possible avec WHERE : 

SELECT Count(Leçon.Id_moniteur) AS NB
FROM Moniteur, Leçon
WHERE Moniteur.Id_Moniteur = Leçon.Id_moniteur
GROUP BY Moniteur.Id_Moniteur, Moniteur.Nom_moniteur
HAVING (((Moniteur.Nom_moniteur)="suzuki"));

Le lecteur attentif aura remarqué la redondance de parenthèses inutiles dans la dernière ligne des deux variantes :

HAVING (((Moniteur.Nom_moniteur)="suzuki"));

les bleues n'auraient dû être employées que si un nom de table ou de champ comportaient des espaces ;
les rouges sont aussi inutiles car elles encadrent exactement les vertes ;
les vertes sont inutiles, car la condition est simple (sans OR ou AND).

retour Q71

 

 

 

 

  

R72

SELECT COUNT(*) AS [nombre de participants nés en 68]
FROM participants
WHERE matricule LIKE “1968*”          ou bien matricule LIKE “1968???????”

Cette requête comptera le nombre d'enregistrements qui répondent au critère défini dans le 'where'.
Elle recherchera tous les membres dont le matricule commence par 1968 (et se termine par 7 autres caractères [car il y a 7 points d'interrogations dans la seconde solution).

retour Q72

 

 

 

 

 

  

R73

SELECT nom, prénom
FROM participants
WHERE matricule LIKE “1968*” ou bien matricule LIKE “1968???????”;

Cet exemple illustre bien la différence entre
le '*' qui peut remplacer n'importe quelle chaîne de caractères,
et le '?' qui ne peut remplacer qu'un seul caractère, et doit donc être placé autant de fois qu'il n'y a de caractères manquant.

retour Q73

 

 

 

 

 

  

R74

SELECT nom, prénom
FROM participants
WHERE nom LIKE "?C??H*"

Cet autre exemple illustre bien la différence entre les caractères '*' et '?' dans un LIKE.
'?' ne peut être remplacé que par un unique caractère autre ;
'*' peut être remplacé par un ou plusieurs caractères quelconques.

retour Q74

 

 

 

 

 

 

  

R75

SELECT nom, prenom
FROM participants
WHERE nom LIKE “*N”
ORDER BY nom, prénom;

retour Q75

 

 

 

 

 

  

R76

Afficher tous les noms et prénoms des participants dont le nom commence avec la lettre N

retour Q76

 

 

 

 

  

R77

SELECT code_cours, droit_inscrip, prime_resp
FROM cours
WHERE droit_inscrip < 600 AND prime_resp >100;

retour Q77

 

 

 

 

 

  

R78

Les requêtes (1) et (3) donneront le même résultat [Afficher les codes des cours et les dates des cours qui ont eu lieu 8 mars 2007 et 10 septembre 2007] ; attention au sens français des ET et OU et des traductions rigoureuses en logique de AND et OR :
Si quelqu'un demande la liste des personnes belges qui ont leur anniversaire le 8 mars et le 10 septembre... il devrait recevoir une liste vide, car personne n'a d'anniversaire à deux dates différentes... le sens généralement admis par cette demande serait de demander "la liste des personnes belges qui ont leur anniversaire le 8 mars et le 10 septembre..."
la requête (2) engendrera une erreur, car le BETWEEN doit être suivi de 2 valeurs séparées par un AND [= ENTRE xxx ET yyy]
et la requête (4) affichera en plus les codes des cours et les dates des cours qui ont eu lieu 9 mars 2007 et 9 septembre 2007
enfin, la requête (5) n'affichera rien, puisqu'aucun cours ne peut avoir lieu à deux dates différentes... à moins que le code_cours n'indique un cours qui puisse avoir lieu à des dates différentes, auquel cas, on aurait la liste des cours qui ont pu avoir lieu à ces deux dates différentes... un cours à 200 heures/année, par exemple ;o) .

(1)
SELECT code_cours, date
FROM cours
WHERE date = #08/03/07# OR date = #10/09/07#

(2)
SELECT code_cours, date
FROM cours
WHERE date BETWEEN #08/03/07# OR #10/09/07#

(3)
WHERE date IN (#08/03/07#, #10/09/07#)

(4)
WHERE date BETWEEN #08/03/07# and #10/09/07#

(5)
WHERE date = #08/03/07# AND date = #10/09/07#

retour Q78

 

 

 

 

 

  

R79

Afficher les matricules des animateurs responsables et la date des cours qui ont eu lieu entre le 1er janvier et 31 janvier 2007.

retour Q79

 

 

 

 

 

  

R80

SELECT code_cours, date, code_thème
FROM cours
WHERE date = #22/01/2007#;

Cet exemple rappellera au lecteur la nécessité d'entourer une date des signes 'dièze' dans toute requête SQL, et de terminer sa requête par un point-virgule...

retour Q80

 

 

 

 

 

  

R81

SELECT code_entreprise, nom, prénom
FROM participants
WHERE code_entreprise = “33336”;

retour Q81

 

 

 

 

  

R82

1.-

5 champs seront affichés : matricule, nom, prénom, localité et code_entreprise.

2.-

la question ne précise pas le nombre d'enregistrements (= de données) que compte cette table de la base, donc impossible de répondre.

Le lecteur attentif aura remarqué qu'un effort a été fait pour éviter les espaces dans le nom des champs (usage du signe 'underscore _ '), mais que des caractères accentués ont malheureusement été employés...

retour Q82

 

 

 

 

 

  

R83

SELECT DISTINCT date
FROM cours
ORDER BY date;

Le lecteur aura remarqué que, par défaut, l'odre est ascendant ; il est donc inutile de préciser la ASC... si l'on veut l'ordre inverse, il faut préciser DESC en fin de ligne ORDER BY.

retour Q83

 

 

 

 

 

  

R84

SELECT nom, prénom
FROM animateurs

Rappelons au lecteur que dans l'exercice présent et dans celui-ci, il aurait été favorable de ne pas employer de caractères accentués pour les noms des champs.

De même, le lecteur attentif aura noté qu'il manque le point-virgule obligatoire en fin de toute instruction SQL.

retour Q84

 

 

 

 

 

  

R85

 

.

retour Q85

 

Analyse préalable

Champs concernés PU_HTVA (champ à corriger)
Tables concernées Produits
Conditions aucune
Regroupement aucun
Filtre aucun
Classement aucun