Vous êtes sur la page 1sur 5

Informatique générale - 2eme semestre - Spécialité AGRAL3/MTX3

TP4 : correction
Le but de ce TP est d’écrire des requêtes SQL d’interrogation, de type SELECT FROM
WHERE en utilisant des constructions plus compliquées tel group by, having, et les
requêtes imbriquées.

Téléchargement :
Nous utiliserons la même base que pour le TP3 aussi vous n'avez pas à faire d'importation dans
phpMyAdmin. Si vous avez supprimé les tables à la fin du TP3, suivez à nouveau la procédure
d'importation. Sinon, vous pouvez l'ignorer. Téléchargez le fichier
http://webia.lip6.fr/~lepape/ens/infogen2/tourdefrance_mysql.sql Créer un nouveau fichier
texte tp4_partie1_nom1_nom2.sql, où nom1 et nom2 sont les logins du binôme.
Ouvrez-le avec un éditeur de texte.

Connexion :
Connectez-vous à l’interface phpMyAdmin en tapant l’url suivante dans un navigateur :
https://pc69.polytech.upmc.fr/phpMyAdmin/
Votre login est le même que sous linux et votre mot de passe, c’est votre login.

Importation :
Nous allons importer dans phpMyAdmin une bases de données à partir du fichier sql téléchargé.
A partir de phpMyAdmin, cliquez sur votre unique base dans le menu de gauche puis dans le
menu de droite, cliquez sur l’onglet « Importer ». Dans l’encart « Fichier à importer », cliquer sur
« Parcourir » et sélectionner le fichier tourdefrance.sql. Cliquez sur « Exécuter ».

Le schéma de la base que vous venez d’importer est :

• EQUIPE(code,nom,directeur)
• PAYS(code,nom)
• COUREUR(num-dossart,code-equipe*,nom,code-pays*)
• ETAPE(num,date,kms,ville-depart,ville-arrivee)
• TEMPS(num-dossart*,num-etape*,temps-realise)

Remarque : la table TEMPS ne stocke que les temps des joueurs qui ont participé à l’étape. Si un
coureur déclare forfait pour une étape, son temps n’apparait pas.

Vérifier que l’importation s’est bien déroulée en visualisant la base de données puis le contenu de
chaque table.

Partie 1 : Tour de France suite (exercice corrigés, 2h)

Les requêtes qui portent sur plusieurs tables doivent être éditées à partir du menu de la
base elle-même.
Sélectionnez la base dans le menu de gauche et cliquez dans l’onglet « SQL » dans les
onglet en haut.

1. Group by, having

1
Informatique générale - 2eme semestre - Spécialité AGRAL3/MTX3

a. Le nombre d’étapes effectuées pour chaque coureur. Compléter la requête en


ordonnant les résultats par ordre croissant du nom des coureurs. Compléter la
requête en ne gardant que les coureurs dont le temps effectué pour chaque
étape est supérieur à 2h. Compléter la requête en ne gardant que les coureurs
qui ont effectués au moins une étape. Quelle est la différence entre la clause
WHERE et la clause HAVING ?

SELECT t.num_dossart, count(t/num_etape) AS nb_total_etape


FROM Temps t
WHERE t.temps_effectue > ’02:00:00’
GROUP BY t.num_dossart
HAVING nb_total_etape >= 2

La clause WHERE permet de sélectionner les tuples AVANT regroupement,


tandis que la clause HAVING permet de sélectionner les tuples APRES le
regroupement, en sélectionnant certaines sous tables parmi celles qui ont été
regroupées.

b. Récupérez le code et le nom des pays ayant plus d'un coureur, classé par ordre
alphabétique croissant des noms de pays

SELECT p.code, p.nom


FROM pays p, coureur c
WHERE c.code_pays = p.code
GROUP BY c.code_pays
HAVING COUNT(c.code_pays) > 1
ORDER BY p.nom

c. Récupérez le nom des coureurs dont le temps total (somme du temps mis pour
chaque étape) est inférieur à 3h30, classé par temps total croissant

SELECT c.nom, SEC_TO_TIME(SUM(TIME_TO_SEC(t.temps_realise))) AS


temps_total
FROM coureur c, temps t
WHERE c.num_dossart = t.num_dossart
GROUP BY c.num_dossart
HAVING temps_total < '03:30:00'
ORDER BY temps_total

2. Requêtes imbriquées
a. Récupérez le nom des joueurs qui n'ont pas couru l'étape 2 ? Que signifie la
réponse ?

SELECT c.nom
FROM coureur c
WHERE c.num_dossart NOT IN (SELECT t.num_dossart
FROM temps t
WHERE t.num_etape = 2)

Tous les joueurs ont courru l'étape 2

2
Informatique générale - 2eme semestre - Spécialité AGRAL3/MTX3

b. Récupérez le nom des coureurs dont la première lettre de leur nom est
identique à celle d'un autre joueur (exemple : REICHL et ROUS) en utilisant
EXISTS

SELECT c.nom
FROM coureur c
WHERE EXISTS (SELECT d.nom
FROM coureur d
WHERE SUBSTRING(c.nom, 1, 1) = SUBSTRING(d.nom, 1, 1)
AND c.num_dossart <> d.num_dossart)
ORDER BY c.nom

c. Récupérez le nom et le temps du dernier coureur arrivé pour chaque étape

SELECT t.num_etape, c.nom, t.temps_realise


FROM coureur c, temps t
WHERE c.num_dossart = t.num_dossart
AND t.temps_realise >= ALL (SELECT temps_realise
FROM temps
WHERE t.num_etape = num_etape)
ORDER BY t.num_etape

d. Récupérez les coureurs qui n'ont pas gagné (autrement dit tous les coureurs
sauf le premier) pour chaque étape ?

SELECT t.num_etape, c.nom, t.temps_realise


FROM coureur c, temps t
WHERE c.num_dossart = t.num_dossart
AND t.temps_realise > ANY (SELECT temps_realise
FROM temps
WHERE t.num_etape = num_etape)
ORDER BY t.num_etape, t.temps_realise

e. Récupérez le 2ème meilleur temps pour l'étape 1 en utilisant le fait qu'il n'y a
aucun ex aequo (les temps sont tous uniques)

SELECT c.nom, t.temps_realise


FROM temps t, coureur c
WHERE t.num_dossart = c.num_dossart
AND t.num_etape = 1
AND (SELECT COUNT(u.temps_realise)
FROM temps u
WHERE TIME_TO_SEC(t.temps_realise) >= TIME_TO_SEC(u.temps_realise)
AND t.num_etape = u.num_etape) = 2

f. Même question en ne présumant d'aucune unicité sur les temps

On ajoute DISTINCT dans le COUNT de la requête imbriqué

3. Question bonus
Quel est l'intérêt d'utiliser une base de données ?

3
Informatique générale - 2eme semestre - Spécialité AGRAL3/MTX3

Note : Imaginez devoir répondre aux mêmes questions en utilisant des tableaux dans
votre tableur préféré

Cela permet d'automatiser un traitement (recoupement d'information + sélection +


projection). C'est indispensable pour pouvoir traiter de gros volumes de données

Partie 2 : (exercice à rendre, 1h)

Importation :
Téléchargez les fichiers
http://webia.lip6.fr/~lepape/ens/infogen2/geographie_mysql1.sql.bz2
http://webia.lip6.fr/~lepape/ens/infogen2/geographie_mysql2.sql.bz2 et
http://webia.lip6.fr/~lepape/ens/infogen2/geographie_mysql3.sql.bz2 et importez les dans
l'ordre en suivant la procédure donnée dans la première partie. Le schéma de la base que
vous venez d’importer est :

• REGIONS (id_region, nom_reg, nb-hab_reg, superficie_reg, metrop)


• DEPARTEMENTS (id_dep, num_dep, nom_dep, prefecture*, region*, nb-
hab_dep, superficie_dep)
• CANTONS (num_can, nom_can, nb-hab_can)
• COMMUNES (id_insee, postal, nom_com, id_dep*, nb-hab_com,
superficie_com)
• REPART (num_can*, num_com*)

où :
¾ num_com est une clé étrangère qui référence id_insee dans la table communes
¾ prefecture est une clé étrangère qui référence id_insee dans la table communes
¾ region est une clé étrangère qui référence id_region dans la table regions

Vous placerez vos requêtes SQL dans le fichier texte suivant tp4partie2_nom1_nom2.sql,
où nom1 et nom2 sont les logins du binôme.

Écrivez les requêtes vous permettant d'obtenir les informations suivantes :

1. Les cantons ayant le même nom


SELECT DISTINCT c1.nom_can
FROM cantons c1, cantons c2
WHERE c1.nom_can = c2.nom_can
AND c1.num_can <> c2.num_can

2. Le nombre de département par canton, pour les régions ayant une densité de
population supérieure à 300, ordonné par le nom des régions
SELECT count( * ) AS 'nb_departement', r.nom_reg
FROM departements d, regions r
WHERE d.region = r.id_region
AND r.`nb-hab_reg` / r.superficie_reg >50
GROUP BY d.region
ORDER BY r.nom_reg

4
Informatique générale - 2eme semestre - Spécialité AGRAL3/MTX3

3. Les départements dont la densité de population est plus grande que celle de leur
région (en utilisant IN)

SELECT d1.nom_dep
FROM departements d1
WHERE d1.id_dep IN (SELECT d2.id_dep
FROM departements d2, regions r
WHERE d1.region = r.id_region
AND d2.region = r.id_region
AND d2.`nb-hab_dep` / d2.superficie_dep > r.`nb-hab_reg` / r.superficie_reg)

4. Les communes ayant une population plus importante qu'un département (en
utilisant ANY)

SELECT c.nom_com
FROM communes c
WHERE c.nb-hab_com >= ANY (SELECT d.nb-hab_dep
FROM departements d)

5. Les cantons dont le nom est également le nom du département (en utilisant
EXISTS)

SELECT c.nom_can
FROM cantons c
WHERE EXISTS (SELECT ca.nom_dep
FROM departements d
WHERE d.nom_dep = ca.nom_can)

6. Le département ayant la plus faible densité

SELECT d.nom_dep
FROM departements d
WHERE d.nb-hab_dep / d.superficie_dep <= ALL
(SELECT dep.nb-hab_dep / dep.superficie_dep
FROM departements dep)

7. Les tables utilisées dans la 2e partie de ce TP sont volumineuses. Vous devez les
supprimer. Pour cela, commencez par supprimer les clés étrangères (lien gestion
des relations sur l'onglet structure de la table dont vous voulez supprimer les clés),
et ensuite les tables.