Un produit est identifié par son numéro NPRO, son libellé LIBELLE, son prix unitaire PRIX_U et son poids unitaire POIDS_U.
La relation COMPOSITION décrit la composition des produits : Chaque ligne de la relation COMPOSITION indique que le produit identifié par COMPOSE est composé du produit identifié par COMPOSANT en quantité QTE.
Seuls les produits composés ont une entrée dans la relation COMPOSITION.
Un produit peut être composé de plusieurs produits, et un produit peut être le composant de plusieurs produits.
La relation COMPOSITION est une relation réflexive : un produit peut être composé de lui-même.
La relation COMPOSITION est une relation symétrique : si le produit A est composé du produit B, alors le produit B est le composant du produit A.
Seuls les composants finaux ont un prix et un poids unitaires.
Données
PRODUIT
NPRO
LIBELLE
PRIX_U
POIDS_U
p1
A-200
p2
A-056
p3
B-661
p4
B-122
p5
B-326
p6
D-822
3.5
0.7
p7
D-507
8
0.25
p8
G-993
5
1.15
p9
F-016
p10
J-500
p11
J-544
0.5
0.9
p12
L-009
1.7
2.3
COMPOSITION
COMPOSE
COMPOSANT
QTE
p1
p2
2
p1
p3
1
p1
p4
2
p2
p7
8
p2
p8
2
p3
p8
5
p4
p8
4
p4
p9
5
p4
p10
5
p5
p4
2
p5
p6
7
p9
p11
2
p10
p11
4
p10
p12
3
Exprimer en SQL les requêtes suivantes :
1. les matières premières (produits qui n’ont pas de composants) ;
1
SELECT*FROM PRODUIT
2
WHERE NPRO
3
NOTIN ( SELECT COMPOSE FROM COMPOSITION);
Résultat :
Produits
NPRO
LIBELLE
PRIX_U
POIDS_U
p6
D-822
3.5
0.7
p7
D-507
8
0.25
p8
G-993
5
1.15
p11
J-544
0.5
0.9
p12
L-009
1.7
2.3
2. les produits finis (qui n’entrent dans la composition d’aucun autre) ;
1
SELECT NPRO
2
FROM PRODUIT
3
WHERE NPRO NOTIN (SELECT COMPOSANT FROM COMPOSITION) ;
Résultat :
Produits
NPRO
p1
p5
3. les produits semi-finis (tous les autres) ;
1
SELECT NPRO
2
FROM PRODUIT
3
WHERE NPRO IN (SELECT COMPOSE FROM COMPOSITION)
4
AND NPRO IN (SELECT COMPOSANT FROM COMPOSITION) ;
Résultat :
Produits
NPRO
p10
p2
p3
p4
p9
Alternative avec des jointures :
1
SELECT DISTINCT NPRO
2
FROM PRODUIT P, COMPOSITION C1, COMPOSITION C2
3
WHEREP.NPRO=C1.COMPOSE
4
ANDP.NPRO=C2.COMPOSANT;
Résultat :
Produits
NPRO
p10
p2
p3
p4
p9
4. le prix et poids unitaires d’un produit fini ou semi-fini dont tous les composants ont un poids et un prix unitaires.
1
SELECT
2
3
PH.NPRO,
4
SUM(QTE*PB.PRIX_U),
5
SUM(QTE*PB.POIDS_U)
6
7
FROM PRODUIT PH, COMPOSITION C, PRODUIT PB
8
9
WHERE
10
PH.NPRO=C.COMPOSE
11
ANDC.COMPOSANT=PB.NPRO
12
ANDNOTEXISTS (
13
SELECT*
14
FROM COMPOSITION CC, PRODUIT BB
15
WHERE
16
CC.COMPOSANT=BB.NPRO
17
ANDCC.COMPOSE=PH.NPRO
18
AND (BB.PRIX_UisnullORBB.POIDS_Uisnull)
19
)
20
GROUP BYPH.NPRO
21
;
Résultat :
Produits
NPRO
SUM(QTE*PB.PRIX_U)
SUM(QTE*PB.POIDS_U)
p10
7.1
10.5
p2
74
4.3
p3
25
5.75
p9
1
1.8
Exercice 2
Soit le schéma relationnel suivant :
1
Personnes (numero, nom, prenom, responsable*)
Données
Personnes
numero
nom
responsable
p1
Mercier
p2
Durant
p3
Noirons
p1
p4
Dupont
p1
p5
Verger
p4
p6
Dupond
p4
p7
Dermiez
p6
p8
Anciers
p2
Quels sont les personnes qui ont le même responsable que p4 ?
1
SELECT*FROM Personnes
2
WHERE responsable IN (SELECT responsable FROM Personnes WHERE numero ='p4');
Résultat :
Personnes
numero
nom
responsable
p3
Noirons
p1
p4
Dupont
p1
Si on veut exclure la personne p4 du résultat :
1
SELECT*
2
FROM Personnes
3
WHERE
4
responsable IN ( SELECT responsable FROM Personnes WHERE numero ='p4' )
5
AND numero <>'p4';
Résultat :
Personnes
numero
nom
responsable
p3
Noirons
p1
Version alternative :
1
SELECT P2.*
2
FROM Personnes P1, Personnes P2
3
WHERE
4
P1.responsable=P2.responsable
5
ANDP1.numero='p4'
6
ANDP2.numero<>'p4';
Résultat :
Personnes
numero
nom
responsable
p3
Noirons
p1
Exercice 3
En reprendant le schéma relationnel de la base de données fil rouge :
FROM Details D, Produits P, Clients C, Commandes CO
3
WHERED.numeroProduit=P.numero
4
ANDC.numero=CO.numeroClient
5
ANDCO.numero=D.numeroCommande
6
GROUP BY categorie, numeroProduit;
Résultat :
Produits commandés par catégories
categorie
numeroProduit
SUM(quantite*prix)
A1
1
75
A1
2
60
A1
3
120
A1
4
15
A1
5
80
B1
1
200
B1
2
60
B2
1
300
B2
2
60
B2
3
120
C3
1
100
C3
2
60
C3
3
240
C3
4
15
C3
5
80
Calculer le montant dû par chaque client. Dans ce calcul, on ne prend en compte que le montant des commandes. Attention aux clients qui n’ont pas passé de commandes, ils devraient apparaître avec un montant nul.
1
SELECTC.numero, C.nom, SUM(quantite*prix) as Montant
2
FROM Clients C
3
LEFT JOIN Commandes CO ONC.numero=CO.numeroClient
4
LEFT JOIN Details D ONCO.numero=D.numeroCommande
5
LEFT JOIN Produits P OND.numeroProduit=P.numero
6
GROUP BYC.numero;
Résultat :
Montant dû par chaque client
numero
nom
Montant
1
Lebreton
350
2
Vasseur
3
Da Costa
495
4
Rey
260
5
Weiss
480
6
Berlioz
7
Lefevre
8
Jacques
9
Barda
Version alternative avec une UNION :
1
SELECTC.numero, C.nom, SUM(quantite*prix) as Montant
2
FROM Clients C, Commandes CO, Details D, Produits P
3
WHEREC.numero=CO.numeroClient
4
ANDCO.numero=D.numeroCommande
5
ANDD.numeroProduit=P.numero
6
GROUP BYC.numero
7
UNION
8
SELECTC.numero, C.nom, 0as Montant
9
FROM Clients C
10
WHEREC.numeroNOTIN (SELECT numeroClient FROM Commandes);
Résultat :
Montant dû par chaque client
numero
nom
Montant
1
Lebreton
350
2
Vasseur
0
3
Da Costa
495
4
Rey
260
5
Weiss
480
6
Berlioz
0
7
Lefevre
0
8
Jacques
0
9
Barda
0
Calculer le montant dû par les clients de chaque ville. Dans ce calcul, on ne prend en compte que le montant des commandes. Attention aux villes dans lesquelles aucun client n’a passé de commandes.
1
SELECTC.ville, SUM(quantite*prix) as Montant
2
FROM Clients C
3
LEFT JOIN Commandes CO ONC.numero=CO.numeroClient
4
LEFT JOIN Details D ONCO.numero=D.numeroCommande
5
LEFT JOIN Produits P OND.numeroProduit=P.numero
6
GROUP BYC.ville;
Résultat :
Montant dû par les clients de chaque ville
ville
Montant
Grenoble
Lille
480
Lyon
Meylan
350
Paris
495
Vizille
260
Calculer, par jour, le total des montants des commandes. Suggestion : Regroupement par date
1
SELECT dateCommande, SUM(quantite*prix) as Montant
2
FROM Commandes CO, Details D, Produits P
3
WHERECO.numero=D.numeroCommande
4
ANDD.numeroProduit=P.numero
5
GROUP BY dateCommande;
Résultat :
Total des montants des commandes par jour
dateCommande
Montant
2024-02-01
255
2024-03-15
95
2024-04-28
495
2024-06-24
235
2024-06-30
230
2024-07-12
250
2024-08-19
25
On suppose que le concepteur de la base de données n’a pas trouvé utile d’imposer un identifiant primaire sur la table Produits
Il se pourrait donc que plusieurs lignes de la table Produits aient la même valeur pour le numéro de produit (ce qui déroge au principe d’unicité des bases de données relationnelles…)
(a) Ecrire une requête qui recherche les valeurs de numero présentes en plus d’un exemplaire.
1
SELECT numero
2
FROM Produits
3
GROUP BY numero
4
HAVINGCOUNT(numero) >1;
Résultat :
Recherche des doublons de numero de Produits
(b) Ecrire une requête qui indique combien de valeurs de numero sont présentes en plus d’un exemplaire.
1
SELECTCOUNT(numero)
2
FROM (
3
SELECT numero
4
FROM Produits
5
GROUP BY numero
6
HAVINGCOUNT(numero) >1
7
);
Résultat :
Combien de valeurs de `numero` sont présentes en plus d’un exemplaire
COUNT(numero)
0
Afficher pour chaque ville, les noms des produits qui y sont commandés.
1
SELECTC.ville, P.nom
2
FROM Clients C, Commandes CO, Details D, Produits P
3
WHEREC.numero=CO.numeroClient
4
ANDCO.numero=D.numeroCommande
5
ANDD.numeroProduit=P.numero
6
GROUP BYC.ville, P.nom;
Résultat :
Noms des produits commandés par ville
ville
nom
Lille
Chaussures
Lille
Pantalon
Lille
T-shirt
Meylan
Casquette
Meylan
Chaussures
Meylan
Pantalon
Meylan
Sac à dos
Meylan
T-shirt
Paris
Casquette
Paris
Chaussures
Paris
Pantalon
Paris
Sac à dos
Paris
T-shirt
Vizille
Pantalon
Vizille
T-shirt
Afficher par ville, et pour chaque catégorie dans celle-ci, le total des montants des commandes.
1
SELECTC.ville, C.categorie, SUM(quantite*prix) as Montant
2
FROM Clients C, Commandes CO, Details D, Produits P
3
WHEREC.numero=CO.numeroClient
4
ANDCO.numero=D.numeroCommande
5
ANDD.numeroProduit=P.numero
6
GROUP BYC.ville, C.categorie;
Résultat :
Total des montants des commandes par ville et par catégorie
ville
categorie
Montant
Lille
B2
480
Meylan
A1
350
Paris
C3
495
Vizille
B1
260
Indiquer, pour chaque ville, les catégories de clients qui n’y sont pas représentées
Suggestion: Construire l’ensemble de tous les couples (ville, categorie), possibles et en retirer ceux qui existent dans la base. Attention aux valeurs null, qui ne doivent pas être prises en compte.
1
SELECTC.ville, CC.categorie
2
FROM Clients C, (SELECT DISTINCT categorie FROM Clients) CC
3
WHERE (C.ville, CC.categorie) NOTIN (
4
SELECT ville, categorie
5
FROM Clients
6
)
7
ORDER BYC.ville;
Résultat :
Catégories de clients non représentées par ville
ville
categorie
Grenoble
A1
Grenoble
C3
Grenoble
B1
Grenoble
C1
Lille
A1
Lille
C3
Lille
B1
Lille
C1
Lyon
A1
Lyon
B2
Lyon
C3
Lyon
B1
Meylan
B2
Meylan
C3
Meylan
B1
Meylan
C1
Vizille
A1
Vizille
B2
Vizille
C3
Vizille
C1
Explications :
On commence par construire l’ensemble de tous les couples (ville, categorie) possibles :
C’est un produit relationnel, car on sélectionne 2 tables sans condition de jointure
La première table est la table Clients renommée C
La seconde table est une table temporaire, exprimée par la sous-requête SELECT DISTINCT categorie FROM Clients, qui renvoie les catégories distinctes de clients
Enfin, on utilise une clause WHERE pour filtrer les couples (C.ville, CC.categorie) qui n’existent pas dans la table Clients
Produire (à l’écran) une table de couples < X, Y > de clients tels que X et Y habitent dans la même ville.
On évitera de renseigner < X,X >, mais aussi < Y,X > si < X,Y > est déjà repris.
Suggestion. Auto-jointure de CLIENT. On évitera les couples inverse en imposant un ordre sur les valeurs de NOM (p.ex. X < Y ).
1
SELECTC1.nomAS C1, C2.nomAS C2
2
FROM Clients C1, Clients C2
3
WHEREC1.ville=C2.ville
4
ANDC1.nom<C2.nom;
Résultat :
Couples de clients habitant dans la même ville
C1
C2
Da Costa
Jacques
Berlioz
Da Costa
Berlioz
Jacques
Barda
Berlioz
Barda
Da Costa
Barda
Jacques
Afficher pour chaque client, le nombre de commandes, le nombre de produits commandés et le nombre de détails.
On se limite aux clients qui ont passé au moins une commande.
Suggestion : il s’agit d’une requête basée sur des groupements multi-niveaux.
1
SELECTC.numero, C.nom, COUNT(DISTINCTCO.numero) as NbCommandes, COUNT(DISTINCTD.numeroProduit) as NbProduits, COUNT(*) as NbDetails
2
FROM Clients C, Commandes CO, Details D
3
WHEREC.numero=CO.numeroClient
4
ANDCO.numero=D.numeroCommande
5
GROUP BYC.numero
6
HAVINGCOUNT(DISTINCTCO.numero) >0;
Résultat :
Nombre de commandes, produits commandés et détails par client
numero
nom
NbCommandes
NbProduits
NbDetails
1
Lebreton
2
5
5
3
Da Costa
1
5
5
4
Rey
2
2
3
5
Weiss
2
3
4
Afficher, pour chaque ville et pour chaque catégorie :
(a) le nombre de commandes passées par les clients de cette ville et de cette catégorie
1
SELECTC.ville, C.categorie, COUNT(DISTINCTCO.numero) as NbCommandes
2
FROM Clients C, Commandes CO
3
WHEREC.numero=CO.numeroClient
4
GROUP BYC.ville, C.categorie;
Résultat :
Nombre de commandes, produits commandés et détails par client
ville
categorie
NbCommandes
Lille
B2
2
Meylan
A1
2
Paris
C3
1
Vizille
B1
2
(b) le montant total de ces commandes.
1
SELECTC.ville, C.categorie, SUM(quantite*prix) as Montant
2
FROM Clients C, Commandes CO, Details D, Produits P
3
WHEREC.numero=CO.numeroClient
4
ANDCO.numero=D.numeroCommande
5
ANDD.numeroProduit=P.numero
6
GROUP BYC.ville, C.categorie;
Résultat :
Nombre de commandes, produits commandés et détails par client
ville
categorie
Montant
Lille
B2
480
Meylan
A1
350
Paris
C3
495
Vizille
B1
260
Calculer le nombre moyen de produits par commande. De même le nombre moyen de commandes par client, par ville ou par catégorie.
Remarque: Il n’est pas possible de demander directement la moyenne d’une somme. Suggestion : Construction et interrogation d’une vue ou calcul de la moyenne dans le FROM.
1
SELECTAVG(NbProduits)
2
FROM (
3
SELECTCO.numero, COUNT(DISTINCTD.numeroProduit) as NbProduits
4
FROM Commandes CO, Details D
5
WHERECO.numero=D.numeroCommande
6
GROUP BYCO.numero
7
);
Résultat :
Nombre moyen de produits par commande
AVG(NbProduits)
2.4285714285714284
Quel est, pour chaque ville, le nombre moyen de commandes par client.
1
SELECTT.ville, AVG(T.NbCommandes)
2
FROM (
3
SELECTC.numero, C.ville, COUNT(DISTINCTCO.numero) as NbCommandes
4
FROM Clients C, Commandes CO
5
WHEREC.numero=CO.numeroClient
6
GROUP BYC.numero
7
) as T
8
GROUP BYT.ville;
Résultat :
Nombre moyen de commandes par client par ville
ville
AVG(T.NbCommandes)
Lille
2
Meylan
2
Paris
1
Vizille
2
Ecrire une requête SQL qui donne, pour chaque produit, le nombre de produits qui ont été commandés le 30/06/2024.
1
SELECT numeroProduit, SUM(quantite) as NbProduits
2
FROM Details D, Commandes CO
3
WHERED.numeroCommande=CO.numero
4
ANDCO.dateCommande='2024-06-30'
5
GROUP BY numeroProduit;
Résultat :
Nombre de produits commandés le 30/06/2024
numeroProduit
NbProduits
1
2
2
1
3
1
Donner pour chaque ville dans laquelle se trouve au moins un client de catégorie C1 la liste des produits Pantalon qu’on y a commandés.
1
SELECTC.ville, P.nom
2
FROM Clients C, Commandes CO, Details D, Produits P
3
WHEREC.numero=CO.numeroClient
4
ANDCO.numero=D.numeroCommande
5
ANDD.numeroProduit=P.numero
6
ANDC.categorie='C1'
7
ANDP.nomLIKE'Pantalon'
8
GROUP BYC.ville, P.nom;
Résultat :
Produits Pantalon commandés par ville
Donner pour chaque produit la liste des villes dans lesquelles ce produit est commandé en plus de 2 unités au total pour la ville.
Suggestion : Un produit est intéressant si le nombre de villes dans lesquelles il est commandé est supérieur ou égal à 2.
1
SELECTP.nom, C.ville
2
FROM Clients C, Commandes CO, Details D, Produits P
3
WHEREC.numero=CO.numeroClient
4
ANDCO.numero=D.numeroCommande
5
ANDD.numeroProduit=P.numero
6
GROUP BYP.nom, C.ville
7
HAVINGSUM(D.quantite) >2;
Résultat :
Villes où un produit est commandé en plus de 2 unités
nom
ville
T-shirt
Lille
T-shirt
Meylan
T-shirt
Paris
T-shirt
Vizille
Afficher, pour chaque ville, les produits qu’on y commande et qui sont aussi commandés dans au moins une autre ville.
1
SELECTC.ville, P.nom
2
FROM Clients C, Commandes CO, Details D, Produits P
3
WHEREC.numero=CO.numeroClient
4
ANDCO.numero=D.numeroCommande
5
ANDD.numeroProduit=P.numero
6
ANDP.nomIN (
7
SELECTP2.nom
8
FROM Clients C2, Commandes CO2, Details D2, Produits P2
9
WHEREC2.numero=CO2.numeroClient
10
ANDCO2.numero=D2.numeroCommande
11
ANDD2.numeroProduit=P2.numero
12
ANDC2.ville<>C.ville
13
)
14
GROUP BYC.ville, P.nom;
Résultat :
Produits commandés dans au moins une autre ville
ville
nom
Lille
Chaussures
Lille
Pantalon
Lille
T-shirt
Meylan
Casquette
Meylan
Chaussures
Meylan
Pantalon
Meylan
Sac à dos
Meylan
T-shirt
Paris
Casquette
Paris
Chaussures
Paris
Pantalon
Paris
Sac à dos
Paris
T-shirt
Vizille
Pantalon
Vizille
T-shirt
Calculer, pour chaque ville, le nombre de catégories distinctes.
1
SELECTC.ville, COUNT(DISTINCTC.categorie) as NbCategories
2
FROM Clients C, Commandes CO, Details D, Produits P