Aller au contenu

UGA - MIASHS - S7 - BDD - Pierre Blarre

TD4 - SQL DML 2 - Corrigé

Icône Présentation
1 / 1

Exercice 1

Soit le schéma relationnel suivant :

PRODUIT (NPRO, LIBELLE, PRIX_U, POIDS_U)
COMPOSITION (COMPOSE, COMPOSANT, QTE)
Remarques
  • 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
NPROLIBELLEPRIX_UPOIDS_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
COMPOSECOMPOSANTQTE
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) ;
SELECT * FROM PRODUIT
WHERE NPRO
NOT IN ( SELECT COMPOSE FROM COMPOSITION);
Résultat :
Produits
NPROLIBELLEPRIX_UPOIDS_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) ;
SELECT NPRO
FROM PRODUIT
WHERE NPRO NOT IN (SELECT COMPOSANT FROM COMPOSITION) ;
Résultat :
Produits
NPRO
p1
p5
3. les produits semi-finis (tous les autres) ;
SELECT NPRO
FROM PRODUIT
WHERE NPRO IN (SELECT COMPOSE FROM COMPOSITION)
AND NPRO IN (SELECT COMPOSANT FROM COMPOSITION) ;
Résultat :
Produits
NPRO
p10
p2
p3
p4
p9

Alternative avec des jointures :

SELECT DISTINCT NPRO
FROM PRODUIT P, COMPOSITION C1, COMPOSITION C2
WHERE P.NPRO=C1.COMPOSE
AND P.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.
SELECT
PH.NPRO,
SUM(QTE*PB.PRIX_U),
SUM(QTE*PB.POIDS_U)
FROM PRODUIT PH, COMPOSITION C, PRODUIT PB
WHERE
PH.NPRO = C.COMPOSE
AND C.COMPOSANT = PB.NPRO
AND NOT EXISTS (
SELECT *
FROM COMPOSITION CC, PRODUIT BB
WHERE
CC.COMPOSANT = BB.NPRO
AND CC.COMPOSE = PH.NPRO
AND (BB.PRIX_U is null OR BB.POIDS_U is null)
)
GROUP BY PH.NPRO
;
Résultat :
Produits
NPROSUM(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 :

Personnes (numero, nom, prenom, responsable*)
Données
Personnes
numeronomresponsable
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 ?
SELECT * FROM Personnes
WHERE responsable IN (SELECT responsable FROM Personnes WHERE numero = 'p4');
Résultat :
Personnes
numeronomresponsable
p3 Noirons p1
p4 Dupont p1

Si on veut exclure la personne p4 du résultat :

SELECT *
FROM Personnes
WHERE
responsable IN ( SELECT responsable FROM Personnes WHERE numero = 'p4' )
AND numero <> 'p4';
Résultat :
Personnes
numeronomresponsable
p3 Noirons p1

Version alternative :

SELECT P2.*
FROM Personnes P1, Personnes P2
WHERE
P1.responsable = P2.responsable
AND P1.numero = 'p4'
AND P2.numero <>'p4';
Résultat :
Personnes
numeronomresponsable
p3 Noirons p1

Exercice 3

En reprendant le schéma relationnel de la base de données fil rouge :

Clients (numero, nom, prenom, rue, codePostal, ville, telephone, categorie, compte)
Commandes (numero, numeroClient*, dateCommande, statut)
Produits (numero, nom, prix, stock)
Details (numeroCommande*, numeroProduit*, quantite)
Données de la base
Clients
numeronomprenomruecodePostalvilletelephonecategoriecompte
1 Lebreton Éléonore 6 avenue Françoise Olivier 38240 Meylan 0776059929 A1 10000
2 Vasseur Georges 54, avenue Jean 38000 Grenoble +33 1 44 68 49 74 B2 1903
3 Da Costa Léon 18, boulevard Brigitte Faivre 75000 Paris 0568740044 C3 -1500
4 Rey Michel 49, avenue de Adam 38220 Vizille B1 3251
5 Weiss Dominique 98, boulevard Remy 59000 Lille B2 0
6 Berlioz Diane 27 avenue de la Chartreuse 75000 Paris 123094
7 Lefevre Jean 12, rue de la République 69000 Lyon C1 -1000
9 Barda Jérôme 128 rue de la Paix 75000 Paris C1 -2000
8 Jacques Chaoui 1240 rue des Ateliers 75001 Paris C1 -1750
Produits
numeronomprixstock
1 T-shirt 25 30
2 Pantalon 60 50
3 Chaussures 120 100
4 Casquette 15 10
5 Sac à dos 80 5
Commandes
numeronumeroClientdateCommandestatut
1 1 2024-02-01 livrée
2 1 2024-03-15 livrée
3 3 2024-04-28 livrée
4 4 2024-06-24 annulée
5 5 2024-06-30 en cours
6 5 2024-07-12 en cours
7 4 2024-08-19 annulée
Details
numeroCommandenumeroProduitquantite
1 1 3
1 2 1
1 3 1
2 4 1
2 5 1
3 1 4
3 2 1
3 3 2
3 4 1
3 5 1
4 1 7
4 2 1
5 1 2
5 2 1
5 3 1
6 1 10
7 1 1

Répondez aux questions suivantes :

1. Calculer le montant de chaque détail de commande du client numéro 1
SELECT numeroProduit, quantite, prix, quantite*prix as montant
FROM Clients C, Commandes CO, Details D, Produits P
WHERE C.numero = CO.numeroClient
AND CO.numero = D.numeroCommande
AND D.numeroProduit = P.numero
AND C.numero = 1;
Résultat :
Montant de chaque détail de commande du client numéro 1
numeroProduitquantiteprixmontant
1 3 25 75
2 1 60 60
3 1 120 120
4 1 15 15
5 1 80 80
  1. Calculer le montant commandé des produits Pantalon
SELECT nom, SUM(quantite), prix, SUM(quantite*prix) as Montant
FROM Details D, Produits P
WHERE D.numeroProduit = P.numero
AND P.nom LIKE 'Pantalon';
Résultat :
Montant commandé des produits Pantalon
nomSUM(quantite)prixMontant
Pantalon 4 60 240
  1. Afficher le total et la moyenne des comptes des clients, ainsi que le nombre de clients, selon chacune des classifications suivantes :

    (a) par catégorie

SELECT categorie, SUM(compte), AVG(compte), COUNT(*)
FROM Clients
GROUP BY categorie;
Résultat :
Total et la moyenne des comptes des clients par catégorie
categorieSUM(compte)AVG(compte)COUNT(*)
123094 123094 1
A1 10000 10000 1
B1 3251 3251 1
B2 1903 951.5 2
C1 -4750 -1583.3333333333333 3
C3 -1500 -1500 1

(b) par ville

SELECT ville, SUM(compte), AVG(compte), COUNT(*)
FROM Clients
GROUP BY ville;
Résultat :
Total et la moyenne des comptes des clients par ville
villeSUM(compte)AVG(compte)COUNT(*)
Grenoble 1903 1903 1
Lille 0 0 1
Lyon -1000 -1000 1
Meylan 10000 10000 1
Paris 117844 29461 4
Vizille 3251 3251 1

(c) par catégorie dans chaque ville

SELECT categorie, ville, SUM(compte), AVG(compte), COUNT(*)
FROM Clients
GROUP BY categorie, ville;
Résultat :
Total et la moyenne des comptes des clients par catégorie et par ville
categorievilleSUM(compte)AVG(compte)COUNT(*)
Paris 123094 123094 1
A1 Meylan 10000 10000 1
B1 Vizille 3251 3251 1
B2 Grenoble 1903 1903 1
B2 Lille 0 0 1
C1 Lyon -1000 -1000 1
C1 Paris -3750 -1875 2
C3 Paris -1500 -1500 1
  1. Combien y a-t-il de commandes spécifiant un (ou plusieurs) produit(s) Casquette ?
SELECT COUNT(DISTINCT numeroCommande)
FROM Details D, Produits P
WHERE D.numeroProduit = P.numero
AND P.nom LIKE 'Casquette';
Résultat :
Nombre de commandes spécifiant un (ou plusieurs) produit(s) Casquette
COUNT(DISTINCT numeroCommande)
2
  1. Compléter le fragment suivant de manière à former une requête valide :
SELECT categorie, numeroProduit, SUM(quantite*prix)
FROM ...
SELECT categorie, numeroProduit, SUM(quantite*prix)
FROM Details D, Produits P, Clients C, Commandes CO
WHERE D.numeroProduit = P.numero
AND C.numero = CO.numeroClient
AND CO.numero = D.numeroCommande
GROUP BY categorie, numeroProduit;
Résultat :
Produits commandés par catégories
categorienumeroProduitSUM(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
  1. 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.
SELECT C.numero, C.nom, SUM(quantite*prix) as Montant
FROM Clients C
LEFT JOIN Commandes CO ON C.numero = CO.numeroClient
LEFT JOIN Details D ON CO.numero = D.numeroCommande
LEFT JOIN Produits P ON D.numeroProduit = P.numero
GROUP BY C.numero;
Résultat :
Montant dû par chaque client
numeronomMontant
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 :

SELECT C.numero, C.nom, SUM(quantite*prix) as Montant
FROM Clients C, Commandes CO, Details D, Produits P
WHERE C.numero = CO.numeroClient
AND CO.numero = D.numeroCommande
AND D.numeroProduit = P.numero
GROUP BY C.numero
UNION
SELECT C.numero, C.nom, 0 as Montant
FROM Clients C
WHERE C.numero NOT IN (SELECT numeroClient FROM Commandes);
Résultat :
Montant dû par chaque client
numeronomMontant
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
  1. 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.
SELECT C.ville, SUM(quantite*prix) as Montant
FROM Clients C
LEFT JOIN Commandes CO ON C.numero = CO.numeroClient
LEFT JOIN Details D ON CO.numero = D.numeroCommande
LEFT JOIN Produits P ON D.numeroProduit = P.numero
GROUP BY C.ville;
Résultat :
Montant dû par les clients de chaque ville
villeMontant
Grenoble
Lille 480
Lyon
Meylan 350
Paris 495
Vizille 260
  1. Calculer, par jour, le total des montants des commandes. Suggestion : Regroupement par date
SELECT dateCommande, SUM(quantite*prix) as Montant
FROM Commandes CO, Details D, Produits P
WHERE CO.numero = D.numeroCommande
AND D.numeroProduit = P.numero
GROUP BY dateCommande;
Résultat :
Total des montants des commandes par jour
dateCommandeMontant
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
  1. 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.

SELECT numero
FROM Produits
GROUP BY numero
HAVING COUNT(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.

SELECT COUNT(numero)
FROM (
SELECT numero
FROM Produits
GROUP BY numero
HAVING COUNT(numero) > 1
);
Résultat :
Combien de valeurs de `numero` sont présentes en plus d’un exemplaire
COUNT(numero)
0
  1. Afficher pour chaque ville, les noms des produits qui y sont commandés.
SELECT C.ville, P.nom
FROM Clients C, Commandes CO, Details D, Produits P
WHERE C.numero = CO.numeroClient
AND CO.numero = D.numeroCommande
AND D.numeroProduit = P.numero
GROUP BY C.ville, P.nom;
Résultat :
Noms des produits commandés par ville
villenom
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
  1. Afficher par ville, et pour chaque catégorie dans celle-ci, le total des montants des commandes.
SELECT C.ville, C.categorie, SUM(quantite*prix) as Montant
FROM Clients C, Commandes CO, Details D, Produits P
WHERE C.numero = CO.numeroClient
AND CO.numero = D.numeroCommande
AND D.numeroProduit = P.numero
GROUP BY C.ville, C.categorie;
Résultat :
Total des montants des commandes par ville et par catégorie
villecategorieMontant
Lille B2 480
Meylan A1 350
Paris C3 495
Vizille B1 260
  1. 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.
SELECT C.ville, CC.categorie
FROM Clients C, (SELECT DISTINCT categorie FROM Clients) CC
WHERE (C.ville, CC.categorie) NOT IN (
SELECT ville, categorie
FROM Clients
)
ORDER BY C.ville;
Résultat :
Catégories de clients non représentées par ville
villecategorie
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

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

SELECT C1.nom AS C1, C2.nom AS C2
FROM Clients C1, Clients C2
WHERE C1.ville = C2.ville
AND C1.nom < C2.nom;
Résultat :
Couples de clients habitant dans la même ville
C1C2
Da Costa Jacques
Berlioz Da Costa
Berlioz Jacques
Barda Berlioz
Barda Da Costa
Barda Jacques
  1. 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.

SELECT C.numero, C.nom, COUNT(DISTINCT CO.numero) as NbCommandes, COUNT(DISTINCT D.numeroProduit) as NbProduits, COUNT(*) as NbDetails
FROM Clients C, Commandes CO, Details D
WHERE C.numero = CO.numeroClient
AND CO.numero = D.numeroCommande
GROUP BY C.numero
HAVING COUNT(DISTINCT CO.numero) > 0;
Résultat :
Nombre de commandes, produits commandés et détails par client
numeronomNbCommandesNbProduitsNbDetails
1 Lebreton 2 5 5
3 Da Costa 1 5 5
4 Rey 2 2 3
5 Weiss 2 3 4
  1. 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

SELECT C.ville, C.categorie, COUNT(DISTINCT CO.numero) as NbCommandes
FROM Clients C, Commandes CO
WHERE C.numero = CO.numeroClient
GROUP BY C.ville, C.categorie;
Résultat :
Nombre de commandes, produits commandés et détails par client
villecategorieNbCommandes
Lille B2 2
Meylan A1 2
Paris C3 1
Vizille B1 2

(b) le montant total de ces commandes.

SELECT C.ville, C.categorie, SUM(quantite*prix) as Montant
FROM Clients C, Commandes CO, Details D, Produits P
WHERE C.numero = CO.numeroClient
AND CO.numero = D.numeroCommande
AND D.numeroProduit = P.numero
GROUP BY C.ville, C.categorie;
Résultat :
Nombre de commandes, produits commandés et détails par client
villecategorieMontant
Lille B2 480
Meylan A1 350
Paris C3 495
Vizille B1 260
  1. 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.

SELECT AVG(NbProduits)
FROM (
SELECT CO.numero, COUNT(DISTINCT D.numeroProduit) as NbProduits
FROM Commandes CO, Details D
WHERE CO.numero = D.numeroCommande
GROUP BY CO.numero
);
Résultat :
Nombre moyen de produits par commande
AVG(NbProduits)
2.4285714285714284
  1. Quel est, pour chaque ville, le nombre moyen de commandes par client.
SELECT T.ville, AVG(T.NbCommandes)
FROM (
SELECT C.numero, C.ville, COUNT(DISTINCT CO.numero) as NbCommandes
FROM Clients C, Commandes CO
WHERE C.numero = CO.numeroClient
GROUP BY C.numero
) as T
GROUP BY T.ville;
Résultat :
Nombre moyen de commandes par client par ville
villeAVG(T.NbCommandes)
Lille 2
Meylan 2
Paris 1
Vizille 2
  1. Ecrire une requête SQL qui donne, pour chaque produit, le nombre de produits qui ont été commandés le 30/06/2024.
SELECT numeroProduit, SUM(quantite) as NbProduits
FROM Details D, Commandes CO
WHERE D.numeroCommande = CO.numero
AND CO.dateCommande = '2024-06-30'
GROUP BY numeroProduit;
Résultat :
Nombre de produits commandés le 30/06/2024
numeroProduitNbProduits
1 2
2 1
3 1
  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.
SELECT C.ville, P.nom
FROM Clients C, Commandes CO, Details D, Produits P
WHERE C.numero = CO.numeroClient
AND CO.numero = D.numeroCommande
AND D.numeroProduit = P.numero
AND C.categorie = 'C1'
AND P.nom LIKE 'Pantalon'
GROUP BY C.ville, P.nom;
Résultat :
Produits Pantalon commandés par ville
  1. 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.
SELECT P.nom, C.ville
FROM Clients C, Commandes CO, Details D, Produits P
WHERE C.numero = CO.numeroClient
AND CO.numero = D.numeroCommande
AND D.numeroProduit = P.numero
GROUP BY P.nom, C.ville
HAVING SUM(D.quantite) > 2;
Résultat :
Villes où un produit est commandé en plus de 2 unités
nomville
T-shirt Lille
T-shirt Meylan
T-shirt Paris
T-shirt Vizille
  1. Afficher, pour chaque ville, les produits qu’on y commande et qui sont aussi commandés dans au moins une autre ville.
SELECT C.ville, P.nom
FROM Clients C, Commandes CO, Details D, Produits P
WHERE C.numero = CO.numeroClient
AND CO.numero = D.numeroCommande
AND D.numeroProduit = P.numero
AND P.nom IN (
SELECT P2.nom
FROM Clients C2, Commandes CO2, Details D2, Produits P2
WHERE C2.numero = CO2.numeroClient
AND CO2.numero = D2.numeroCommande
AND D2.numeroProduit = P2.numero
AND C2.ville <> C.ville
)
GROUP BY C.ville, P.nom;
Résultat :
Produits commandés dans au moins une autre ville
villenom
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
  1. Calculer, pour chaque ville, le nombre de catégories distinctes.
SELECT C.ville, COUNT(DISTINCT C.categorie) as NbCategories
FROM Clients C, Commandes CO, Details D, Produits P
WHERE C.numero = CO.numeroClient
AND CO.numero = D.numeroCommande
AND D.numeroProduit = P.numero
GROUP BY C.ville;
Résultat :
Nombre de catégories distinctes par ville
villeNbCategories
Lille 1
Meylan 1
Paris 1
Vizille 1