Les figures de ce chapitre utilisent toutes la même table \(T\), d'attributs
a, b et c, où les valeurs de c sont représentées par des couleurs.
SELECT¶
Produit cartésien et jointures¶
Fonctions et requêtes imbriquées¶
Agrégation¶
TP¶
Allez sur le site http://sql.classeprepa.net et identifiez-vous avec le couple utilisateur/mot de passe suivant : mp2i/mp2i.
Musique¶
- Sélectionnez
tp26_musiquedans la barre de navigation à gauche de l'écran. - Cliquez sur l'onglet
SQL. On vous demande dans la suite de taper des requêtes et d'appuyer surExécuterpour les voir s'exécuter. Après la première requête, on peut faireÉditer en lignepour aller plus vite. - On vous recommande de copier les réponses dans un fichier
tp26.sqlpour en garder une trace.
La base de données tp26_musique comporte quatre tables dont le schéma est
donné dans la figure suivante :
Premières requêtes¶
L'attribut asin de album est la clé primaire qui sert de clé étrangère
album dans track et style.
Question 1
Cherchez tous les albums de 'U2'.
Ici, les dates sont au format texte 'yyyy-mm-dd' qui permet d'effectuer des
comparaisons directement avec <, <=, >, >=.
Par exemple, '1981-08-05' est le 5 août 1981.
Question 2
Cherchez tous les albums parus pendant l'année 1991.
Les données sont issues d'un célèbre vendeur en ligne, à un instant précis dans
le passé, c'est en ce sens qu'il faut interpréter l'attribut price (c'est le
prix en dollars) et l'attribut rank (c'est le rang dans les ventes de
disques).
L'attribut price n'est pas toujours renseigné. Dans ce cas-là, il prend la
valeur spéciale NULL. Pour tester si une valeur est NULL on utilise
l'opérateur spécial IS NULL (et IS NOT NULL pour le test contraire) : une
comparaison price = NULL n'est jamais vraie.
Question 3
Cherchez tous les albums dont le prix est renseigné.
Question 4
Trouvez le titre du 5e album le plus cher et uniquement de celui-ci.
Question 5
Affichez une table contenant pour chaque chanson, son nom et le nom de l'album qui la contient.
L'attribut disk indique le numéro du disque sur l'album, la plupart
en contiennent un seul, et posn le numéro de la piste sur ce disque.
Question 6
Affichez une table contenant les titres des albums ayant au moins deux disques.
On fera en sorte qu'il n'y ait pas de titres répétés.
La table totp contient des chansons ayant apparu dans le classement mensuel
des meilleures ventes. Apparemment, les tables track et totp ne sont pas
associées.
Question 7
À l'aide de LEFT JOIN déterminez s'il y a des éléments de totp dont
l'attribut song n'est pas présent dans track. Même question en inversant
les tables.
Est-il pour autant possible de considérer que song est une clé primaire
d'une de ces deux tables et que l'autre est une clé étrangère ?
Fonctions¶
On peut appliquer des fonctions sur un ou plusieurs attributs, ou expressions, pour obtenir des valeurs. Ce faisant, on va déduire une table à une ligne contenant les résultats.
Par exemple :
SELECT COUNT(*) FROM album
va renvoyer le nombre de lignes de la table album.
Les fonctions au programme sont :
COUNTqui permet de trouver la taille des résultats. Attention,COUNT(attr)ne compte pas les valeurs distinctes : il compte les lignes oùattrn'est pasNULL(pour les valeurs distinctes, on écritCOUNT(DISTINCT attr)). Pour compter les lignes, on utiliseraCOUNT(*).MAXetMINqui renvoient le maximum ou le minimum d'un attribut ou d'une expression.SUMqui fait la somme des valeurs d'un attribut ou d'une expression sur les lignes.AVGqui calcule la moyenne.
Les valeurs NULL sont ignorées par toutes ces fonctions, sauf COUNT(*).
Question 8
En une seule requête, calculer le prix moyen d'un album et le plus petit rang.
Requêtes imbriquées¶
Attention, la requête
SELECT title, MIN(rank) FROM album
n'a aucune raison de renvoyer le titre de l'album de plus petit rang. En fait, avec un gestionnaire peu permissif, la requête précédente est invalide. (SQLite l'accepte et renvoie, par exception, une ligne réalisant le minimum, mais ce comportement n'est pas standard.)
Une manière de réaliser cela est d'utiliser une requête imbriquée comme :
SELECT title, rank FROM album WHERE rank = (SELECT MIN(rank) FROM album)
Ici, comme la sous-requête SELECT MIN(rank) FROM album renvoie un nombre, on
peut tester cela dans la première requête.
On peut noter qu'il est possible de réaliser une telle requête avec une jointure externe à gauche comme
SELECT A1.title, A1.rank
FROM album AS A1 LEFT JOIN album AS A2
ON A2.rank < A1.rank
WHERE A2.rank IS NULL
mais cette requête n'est pas très naturelle.
Question 9
Expliquez cette requête et pourquoi elle répond à la question.
Que se passe-t-il pour les albums dont le rang n'est pas renseigné
(rank à NULL) ? Comment corriger la requête ?
Question 10
Déterminer en une requête les albums ayant le plus de pistes sur un de leurs disques.
Agrégation¶
Pour grouper les chansons dans la table track selon l'album qui les contient
on peut utiliser la requête :
SELECT album FROM track GROUP BY album
On obtient alors une ligne pour chaque valeur de album présente dans la
table. On parle d'agrégat ou de paquet. Cela équivaut ici à
SELECT DISTINCT album FROM track
Une règle importante en SQL est qu'il est interdit de projeter des attributs
qui ne sont pas compris dans le GROUP BY (en dehors d'une fonction
d'agrégation). En effet, il y a ambiguïté sur la valeur qu'on pourrait choisir
pour ces attributs.
Là où les GROUP BY sont très utiles c'est qu'on peut calculer des fonctions
sur chaque agrégat, qui elles sont non ambiguës.
Ici la piste de numéro maximum sur un album indique le nombre de pistes de l'album (pour un album à un seul disque ; sinon, c'est le nombre de pistes de son plus long disque) :
SELECT album, MAX(posn) FROM track GROUP BY album
Question 11
Déterminer le numéro moyen d'une piste d'un album, tout disque compris.
Si on souhaite obtenir avec un GROUP BY les albums ayant au moins 10 pistes,
on pourrait être tenté d'écrire
SELECT album FROM track GROUP BY album WHERE MAX(posn) >= 10
Cette requête est invalide. Le WHERE doit être écrit avant le GROUP BY, et
surtout il s'effectue avant le regroupement : il filtre les lignes de la table,
et ne peut donc pas porter sur une fonction d'agrégation comme MAX(posn).
SQL fournit une syntaxe permettant de filtrer sur des conditions dans les
agrégats : HAVING. Ainsi, on écrira :
SELECT album FROM track GROUP BY album HAVING MAX(posn) >= 10
On aimerait aussi avoir le nom de l'album, pour cela, il y a plusieurs
solutions, une des solutions les plus simples est d'utiliser MAX(title) sur un
agrégat : tous les titres d'un même agrégat sont égaux, MAX sert uniquement à
en choisir un de manière non ambiguë.
SELECT MAX(title) FROM track JOIN album
ON track.album = asin
GROUP BY track.album
HAVING MAX(posn) >= 10
On peut le faire avec une requête imbriquée dans un JOIN interne qui ne va
donc sélectionner que les albums présents dans les deux tables. Ici, le
renommage est obligatoire pour que la requête soit valide.
SELECT title
FROM album
JOIN (SELECT album FROM track
GROUP BY album HAVING MAX(posn) >= 10) AS T
ON asin = T.album
On pourrait aussi utiliser une requête imbriquée et l'opérateur IN hors
programme pour tester la présence d'une valeur dans une table de résultat.
SELECT title FROM album
WHERE asin IN (SELECT album FROM track
GROUP BY album HAVING MAX(posn) >= 10)
Question 12
Trouver les noms des albums ayant au moins deux disques.
Films¶
On considère maintenant la base de données tp26_film. Ses tables sont
décrites dans le diagramme :
Quelques précisions :
- Les clés
idpermettent d'identifier de manière unique un film (movie) ou un acteur (actor). - L'attribut
directorfait référence à un id d'actorqui est également réalisateur de ce film (un pur réalisateur peut ne pas être un vrai acteur mais être présent dans la tableactorquand même). - L'entier
ordindique l'ordre dans lequel sont énumérés les acteurs dans le casting d'un film : du premier nom de valeur 1 (le plus important) au dernier. scoreest le score des internautes sur le film.votesest le nombre de votes.yrest un entier à quatre chiffres comme 1977.
On va rajouter un opérateur qui est pratique pour le TP mais pas au programme :
LIKE qui permet de comparer des textes avec un joker, le caractère %, qui
signifie n'importe quelle suite de caractères (éventuellement vide).
Ainsi,
SELECT title FROM movie WHERE title LIKE '%, The'
va sélectionner les films dont le nom finit par , The.
Question 13
Déterminer les noms des acteurs ayant joué dans des films dont le nom commence par Star.
Question 14
Déterminer le film qui a le plus d'acteurs au casting.
Question 15
Déterminer les noms des acteurs ayant tourné dans au moins 5 films tout en étant toujours premier au casting.
Question 16
Déterminer les noms des acteurs qui n'ont tourné qu'avec un seul réalisateur.
Question 17
Déterminer les noms des acteurs qui n'ont tourné que dans des films qu'ils ont réalisés.