Corrigé du TP 13 — requêtes sur une base de données
III Écrire des requêtes
A Requêtes sans jointure
1. Afficher toutes les informations disponibles sur les cinémas.
SELECT * FROM cinema
2. (a) Afficher la liste des lignes du réseau RATP.
SELECT ligne FROM stop
(b) Afficher la liste des lignes du réseau RATP en éliminant les doublons.
SELECT DISTINCT ligne FROM stop
3. Afficher les couples formés d’une station RATP et de la ligne desservie, en éliminant les doublons et en triant par ordre alphabétique du nom de la station.
SELECT DISTINCT nom_station, ligne FROM stop ORDER BY nom_station
4. Afficher toutes les informations sur la station RATP que vous utilisez le plus souvent (imaginons qu’il s’agit de la station "ORSAY VILLE")
SELECT * FROM stop WHERE nom_station = "ORSAY VILLE"
5. Afficher les noms des cinémas de la ville de Rueil Malmaison, accompagnés de leurs adresses.
SELECT enseigne, adresse FROM cinema WHERE commune = "RUEIL MALMAISON"
6. Afficher les arrêts RATP de Paris intra-muros qui ne sont pas accessibles aux personnes à mobilité réduite.
On peut utiliser LIKE pour détecter les communes qui commencent par PARIS suivi de n’importe quoi.
SELECT * FROM stop WHERE commune LIKE "PARIS%" AND acces_quai = 0
On peut aussi utiliser la congruence pour détecter les codes postaux qui commencent par 75.
SELECT * FROM stop WHERE code_postal-code_postal%1000 = 75000 AND acces_quai = 0 7. Afficher la liste des stations de la partie RATP du RER B.
SELECT DISTINCT nom_station FROM stop WHERE ligne = "B"
8. Afficher la liste des stations du RER A, classées de l’ouest vers l’est.
SELECT DISTINCT nom_station FROM stop WHERE ligne="A" ORDER BY lon 12
9. Calculer le trafic total en 2016, en millions de voyages (notez qu’on met un point à la fin du nombre 1 000 000 afin de forcer l’utilisation de flottants et non pas d’entiers).
SELECT SUM(trafic)/1000000. FROM freq16
10. Déterminer la longitude maximale d’une station RATP.
SELECT MAX(lon) FROM stop
11. On cherche à déterminer l’arrêt RATP le plus au sud du réseau.
(a) Trouver cette réponse en ordonnant les enregistrements de la table.
SELECT DISTINCT nom_station, lat FROM stop ORDER BY lat
Ici, on a affiché toutes les stations RATP par latitude croissante. La première affichée est donc celle qui a la plus petite latitude : c’est la plus au sud. Cette méthode est simple mais elle ne répond pas formellement à la réponse car on aimerait obtenir une réponse avec une seule station : celle qui est le plus au sud.
(b) Écrire une requête SQL utilisant la fonction MIN affichant uniquement l’arrêt RATP le plus au sud du réseau.
SELECT DISTINCT nom_station, lat FROM stop WHERE lat = (SELECT MIN(lat) FROM stop)
12. Afficher la liste des numéros de département avec le nombre de cinémas dans chaque département.
SELECT dep, COUNT() AS nbCine FROM cinema GROUP BY dep
Cette requête fusionne les lignes de la table qui partagent la même valeur de l’attribut dep : la réponse contient donc une seule ligne par département. Lors de la fusion, la fonction COUNT(), qui n’a pas d’argument, compte le nombre de lignes dans chaque paquet. Par conséquent, chaque département est associé au nombre de lignes du paquet correspondant, c’est-à-dire au nombre de cinémas dans ce département.
13. (c) Afficher la liste des stations n’ayant qu’un seul arrêt.
SELECT nom_station, ligne, COUNT() AS nbArrets FROM stop
GROUP BY id_station HAVING nbArrets = 1
(d) Afficher la liste des stations dont tous les arrêts sont accessibles aux personnes à mobilité réduite.
SELECT nom_station, MIN(acces_quai) AS tousAccessibles FROM stop
GROUP BY id_station
HAVING tousAccessibles = 1
Pour chaque station, on a calculé le minimum de la colonne acces_quai. Ce minimum vaut 1 si tous les arrêts de la station sont accessibles aux personnes à mobilité réduite.
B Jointures
1. Afficher la liste des stations associées avec leur fréquentation en 2016. Classer cette liste par ordre décroissant de fréquentation.
SELECT DISTINCT stop.nom_station, trafic FROM stop JOIN freq16
ON freq16.id_station = stop.id_station ORDER BY trafic DESC
2. On considère que la fréquentation totale d’une ligne est la somme des fréquentations de toutes les stations qu’elle dessert. Afficher les lignes et leurs fréquentations totales.
SELECT ligne, SUM(trafic) AS freqTotale FROM stop JOIN freq16
ON stop.id_station = freq16.id_station GROUP BY ligne
3. Afficher la liste des stations dont la fréquentation a augmenté de plus de 10% entre 2015 et 2016.
SELECT DISTINCT nom_station
FROM stop JOIN freq15 JOIN freq16
ON stop.id_station = freq15.id_station
AND freq15.id_station = freq16.id_station WHERE freq16.trafic>1.1*freq15.trafic
(notez qu’il est possible de faire deux jointures en mettant deux fois la clause JOIN, une seule fois la clause ON et un AND)
4. Afficher la liste des paires de communes ayant des cinémas qui portent le même nom (avec le nom commun aux deux cinémas).
SELECT c1.commune, c2.commune, c1.enseigne FROM cinema AS c1 JOIN cinema AS c2
ON c1.enseigne = c2.enseigne WHERE c1.numero<c2.numero
ORDER BY c1.enseigne
Ici on doit faire la jointure de la table cinema avec elle-même : le plus simple est de la renom- mer (en c1 et c2) pour distinguer les deux occurrences de la même table. Avec la condition c1.numero<c2.numero, on s’assure que les deux cinémas sont différents et que chaque paire ap- paraît une seule fois.
C Opérateurs ensemblistes
1. Afficher la liste des communes ayant un cinéma mais pas de station RATP.
SELECT commune FROM cinema EXCEPT
SELECT commune FROM stop
2. Afficher la liste des correspondances entre les lignes 4 et 7 du métro.
SELECT nom_station FROM stop WHERE ligne = "4"
INTERSECT
SELECT nom_station FROM stop WHERE ligne = "7"
IV Requêtes plus évoluées
1. Déterminer la liste des cinémas d’Île-de-France strictement à l’ouest de tout le réseau RATP.
SELECT * FROM cinema WHERE long < (SELECT MIN(lon) FROM stop) 2. Afficher le numéro du département qui a le moins de cinémas.
La requête suivante fournit le nombre de cinémas dans chaque département : SELECT dep, COUNT() AS nbCine FROM cinema GROUP BY dep
La requête suivante fournit le nombre minimal qu’il y a dans un département : SELECT MIN(nbCine) AS nbMinimal
FROM (SELECT dep, COUNT() AS nbCine FROM cinema GROUP BY dep)
La requête suivante compte le nombre de cinémas dans chaque département et ne garde que ceux dont le nombre de cinémas est égal à nbMinimal.
SELECT dep, COUNT() AS nbCinemas FROM cinema GROUP BY dep
HAVING nbCinemas = (
SELECT MIN(nbCine) AS nbMinimal
FROM (SELECT dep, COUNT() AS nbCine FROM cinema GROUP BY dep) )
3. L’étendue d’une station est définie par
etendue=(longitude maxi−longitude mini)×(latitude maxi−latitude mini) Trier les stations par étendue décroissante.
SELECT nom_station, (MAX(lat)-MIN(lat))*(MAX(lon)-MIN(lon)) AS etendue FROM stop
GROUP BY id_station ORDER BY etendue DESC
4. Trier les cinémas par ordre décroissant de distance au réseau RATP. (noter la ligne FROM cinema, stopqui fait apparaître le produit cartésien des deux tables).
SELECT enseigne, cinema.commune,
MIN((lon-long)*(lon-long)+(lat-lati)*(lat-lati)) AS distance FROM cinema, stop
GROUP BY numero
ORDER BY distance DESC
5. Étant données deux stations dont vous choisissez les noms, donner la liste des trajets à une seule correspondance permettant d’aller de l’une à l’autre.
SELECT DISTINCT depart.nom_station, corr1.ligne,
corr1.nom_station, corr2.ligne, arrivee.nom_station
FROM stop AS depart JOIN stop AS corr1 JOIN stop AS corr2 JOIN stop AS arrivee ON depart.ligne=corr1.ligne AND corr1.id_station=corr2.id_station
AND corr2.ligne=arrivee.ligne AND corr1.ligne!=corr2.ligne
WHERE depart.nom_station="MONTGALLET" AND arrivee.nom_station="SAINT MAUR"
Le schéma suivant explique les jointures utilisées ci-dessus : stop
renommée depart
jointure
←−−−−→
surligne
stop renommée
corr1
jointure
←−−−−−→
surstation
stop renommée
corr2
jointure
←−−−−→
surligne
stop renommée
arrivee 6. Calculer les coordonnées (longitude, latitude) du barycentre du réseau RATP.
SELECT AVG(lat) AS latBar, AVG(lon) AS lonBar FROM stop 7. Déterminer la station la plus proche du barycentre du réseau.
On fait le produit cartésien des tables stop et la table créée ci-dessus pour calculer le carré de la distance de chaque arrêt au barycentre.
SELECT *, (lat-latBar)*(lat-latBar)+(lon-lonBar)*(lon-lonBar) AS distArret FROM stop, (SELECT AVG(lat) AS latBar, AVG(lon) AS lonBar FROM stop) On adapte maintenant cette requête pour obtenir la distance minimal au barycentre
SELECT MIN((lat-latBar)*(lat-latBar)+(lon-lonBar)*(lon-lonBar)) AS distMini FROM stop, (SELECT AVG(lat) AS latBar, AVG(lon) AS lonBar FROM stop)
On fait une autre adaptation de la première requête pour calculer le minimum des distArret au sein de chaque station, ce qui définira distStation
SELECT nom_station,
MIN((lat-latBar)*(lat-latBar)+(lon-lonBar)*(lon-lonBar)) AS distStation FROM stop, (SELECT AVG(lat) AS latBar, AVG(lon) AS lonBar FROM stop)
GROUP BY nom_station
Enfin, on recherche la station dont ledistStation est égal à distMini : SELECT nom_station,
MIN((lat-latBar)*(lat-latBar)+(lon-lonBar)*(lon-lonBar)) AS distStation FROM stop, (SELECT AVG(lat) AS latBar, AVG(lon) AS lonBar FROM stop)
GROUP BY nom_station HAVING distStation = (
SELECT MIN((lat-latBar)*(lat-latBar)+(lon-lonBar)*(lon-lonBar)) AS distMini FROM stop, (SELECT AVG(lat) AS latBar, AVG(lon) AS lonBar FROM stop)
)