Vous êtes sur la page 1sur 9

Bases de données - SQL

1 Introduction
L’objectif de ce chapitre est d’apprendre comment on peut organiser un grand nombre
de données entre elles dans des bases de données relationnelles et d’interroger ces bases à
travers le langage SQL.

La création et la modification des bases de données ne sont pas des objectifs du pro-
gramme.

Exemples de questions auxquels on souhaite pouvoir répondre avec une base de données
gérant le fonctionnement des colles d’une classe :
− Quels élèves ont eu moins de 12 à au moins deux colles de LV1 ?
− Quels sont les 3 colleurs de mathématiques donnant les meilleures notes en moyene ?
− Quels sont les adresses mail des élèves ayant Mme X en colle de Physique la semaine
13 ?

2 Bases de données relationnelles


Définition 2.1
Une table (ou relation) est une partie d’un produit cartésien D1 × · · · × Dn .

Définition 2.2
Une base de données relationnelle est un ensemble structuré de données, formé d’un en-
semble de tables.

Exemple 2.3
Dans l’exemple de la gestion des colles dans une classe, on peut par exemple organiser les
données en 4 tables :
− Une table Élève, formée des colonnes Identifiant, Nom, Prénom, Date de naissance,
Mail, LV1
− Une table Colleur, formée des colonnes Identifiant, Nom, Prénom, Matière
− Une table Matière formée des colonnes Identifiant, Nom, Professeur référent
− Une table Notes formée des colonnes Identifiant, Valeur, Élève, Date, Colleur, Matière

1
Ainsi, un élève est vu comme un élément du produit cartésien
{Identifiant} × {Nom} × {Prénom} × {Date de naissance} × {Mail} × {LV1}.

Définition 2.4
Étant donnée une table R ⊂ D1 × · · · × Dn , on appelle
− attribut : un nom de colonne. C’est un intitulé pour Dk .
− domaine d’un attribut : l’ensemble des valeurs qu’il peut prendre (notamment, type
de valeurs)
− ligne : un élément de R (donc un n-uplet)
− clé : un sous-ensemble d’attributs déterminant la ligne de façon unique
− clé primaire : une clé, spécifiée comme telle.

Remarques 2.5
− Une clé n’est pas toujours un unique attribut. Par exemple, pour la table Élève, une
clé est sans doute donnée par le couple (Nom,Prénom) (sauf homonymie rare).
− Le plus souvent, une clé primaire est un unique attribut et elle est créée dans l’unique
but d’être une clé. C’est l’intérêt de la colonne Identifiant dans toutes les tables de
l’exemple de gestion des colles.
− La clé primaire est donc souvent artificielle. Penser aux exemples du numéro de
Sécurité Sociale, à un numéro de compte en banque, à un numéro de commande
passée en ligne...

3 Sélection et projection
Définition 3.1
L’opération de projection sur une table R ⊂ D1 ×. . . Dn consiste à n’en garder que certaines
colonnes.

Remarque 3.2
En notant i1 , . . . , ik ces colonnes (non nécessairement distinctes ni dans l’ordre), cela cor-
respond essentiellement à considérer π(R) où π : D1 × . . . Dn → Di1 × · · · × Dik est défini
canoniquement. Petite subtilité : deux lignes de R qui auraient la même image par π seront
a priori répétées après l’opération de projection.

Définition 3.3
L’opération de sélection sur une table consiste à n’en garder que certaines lignes.

Une requête SQL minimale est de la forme


SELECT colonne 1 , colonne2 , . . . FROM table (WHERE . . . )
− Après SELECT, on donne le nom des colonnes à afficher (donc celles sur lesquelles
on projette ; la terminologie est maladroite).

2
− Après FROM, on donne le nom de la table.
− Après WHERE, on écrit des conditions permettant de sélectionner certaines lignes.
Remarque 3.4 − Pour afficher toutes les colonnes, on peut écrire SELECT *.
− L’usage est d’utiliser des majuscules pour les mots-clé du SQL.
Remarque 3.5
On dispose de quelques options pour enrichir cette requête minimale :
− SELECT DISTINCT : pour n’afficher que les lignes différentes
− ORDER BY : pour trier les résultats. On écrit ORDER BY col (ou ORDER BY col
ASC) pour ordonner de manière croissante (selon le contenu de col), ORDER BY col
DESC pour ordonner de manière décroissante
− LIMIT N : pour afficher (au plus) N lignes
− OFFSET k : pour démarrer à la ligne k, la première ligne étant la ligne 0.
Sans ORDER BY, l’ordre d’affichage des lignes est a priori quelconque. On n’utilisera
LIMIT et OFFSET qu’après un ORDER BY.
Avec ces options, la requête SQL s’écrit :
SELECT (DISTINCT) c o l 1 , c o l 2 , . . . FROM table
(WHERE . . . )
(ORDER BY . . . )
(LIMIT N OFFSET k )

Exemple 3.6
On dispose d’une table movies avec une liste de films avec colonnes id, title et year. Pour
afficher les 100 premiers films par ordre alphabétique) sortis en 1978 :
SELECT t i t l e FROM movies WHERE year = 1978
ORDER BY t i t l e
LIMIT 100

Union, intersection, complémentaire Dans des cas assez rares, il peut être utile de
faire l’union/l’intersection/la différence de deux tables ayant le même schéma relationnel
(c’est-à-dire vivant dans le même produit cartésien). Avec la table movies précédente :
− UNION.
SELECT t i t l e FROM movies WHERE year = 2000 UNION
SELECT t i t l e FROM movies WHERE year = 2010
Affiche la liste des films sortis en 2000 ou en 2010. Il aurait été plus simple d’écrire
SELECT t i t l e FROM movies WHERE year IN ( 2 0 0 0 , 2 0 1 0 )
ou
SELECT t i t l e FROM movies WHERE year = 2000 OR year = 2010

3
− INTERSECT.
SELECT t i t l e FROM movies WHERE year IN 2000 INTERSECT
SELECT t i t l e FROM movies WHERE year IN 2010
Affiche la liste des titres d’un film sorti en 2000 et d’un (autre) sorti en 2010.
− EXCEPT.
SELECT t i t l e FROM movies WHERE year IN 2000 EXCEPT
SELECT t i t l e FROM movies WHERE year IN 2010
Affiche les films sortis en 2000, sauf ceux ayant un homonyme en 2010.

4 Jointure
Exemple 4.1
On dispose d’une base de données de films. On ne considère ici que la table movies avec
colonnes id, title et year et de la table ratings avec colonnes movie_id, rating et votes.
On cherche à afficher la liste des films sortis en 2013 avec leur note.
Pour faire cette opération, on devrait afficher les films sortis en 2013 et pour chacun, noter
son identifiant, le rechercher dans la table ratings et afficher la note correspondante. On
peut heureusement faire beaucoup plus simple en joignant les deux tables selon l’égalité
des identifiants.
SELECT t i t l e , r a t i n g
FROM movies JOIN r a t i n g s ON i d = movie_id
WHERE year = 2013

Remarque 4.2
La table movies JOIN ratings est en fait le produit ensembliste des deux tables. Ce
produit comporte beaucoup d’éléments et n’a pas vraiment de sens : la plupart des entrées
de la première table n’ont aucun rapport avec celles de la deuxième. En ajoutant le ON id
= movie_id, on ne garde que les lignes pour lesquelles les deux identifiants coïncident.
La table movies JOIN ratings ON id = movie_id peut ensuite être traitée comme une
table à part entière.

Remarque 4.3
Dans certains cas, les deux tables ont des noms de colonnes communs. Il peut donc y avoir
ambiguïté sur la colonnes qu’on souhaite afficher ou sur l’égalité spécifiée dans la condition
de jointure. Pour préciser qu’on parle de la colonne col de la table tab, on peut écrire
tab.col au lieu de col.

Exemple 4.4
On dispose d’une BDD jo-continents, composée de deux tables. La table JO avec les colonnes
annee, ville, pays, saison regroupe ces informations pour tous les jeux olympiques d’hiver
et d’été. La table correspondances n’a que les colonnes pays et continent : elle indique

4
dans quel continent se situe le pays.
On souhaite afficher, l’année, la ville et le continent de chaque session des JO d’été, en les
ordonnant du plus au moins récent. On va avoir besoin de faire une jointure sur les deux
tables, en identifiant les pays.
SELECT annee , v i l l e , c o n t i n e n t
FROM JO JOIN c o r r e s p o n d a n c e s ON JO . pays = c o r r e s p o n d a n c e s . pays
WHERE s a i s o n = " é t é "
ORDER BY annee DESC
On aurait pu écrire JO.annee, JO.ville, correspondances.continent et JO.saison mais ce
n’est pas nécessaire, car il n’y a pas d’ambiguïté pour ces colonnes.

Renommage. Indiquer à chaque fois le nom de la table dont est issue la colonne peut
être un peu lourd. On peut utiliser un renommage à la place. On écrit ainsi
FROM t a b l e 1 AS t 1 JOIN t a b l e 2 AS t 2 ON t 1 . c o l 1 = t 2 . c o l 2
Le renommage peut aussi être utilisée sur les noms de colonnes. Par exemple, si la base
de données a des noms de colonnes en anglais mais qu’on veut les afficher en français, on
peut les renommer. Avec l’exemple traité précédemment :
SELECT t i t l e AS T i t r e , r a t i n g AS Note
FROM movies JOIN r a t i n g s ON i d = movie_id
WHERE year = 2013
Cette opération de renommage peut aussi être faite en l’absence de jointure.

Jointures multiples et auto-jointure.


− On peut joindre un nombre quelconque de tables par la syntaxe
SELECT . . . FROM t a b l e 1 JOIN t a b l e 2 JOIN . . . JOIN tableN ON . . .
Après le ON, la condition doit être une conjonction d’égalités (une suite d’égalité
avec des AND).
− Il est possible de joindre une table avec elle-même. Comme exemple d’application,
écrivons une requête utilisant la table JO pour déterminer les pays ayant déjà accueilli
les JO d’hiver et les JO d’été.
SELECT DISTINCT(H. pays )
FROM JO AS H JOIN JO AS E ON H. pays = E . pays
WHERE H. s a i s o n = " h i v e r " AND E . s a i s o n = " é t é "

Sous-requêtes. Supposons qu’on veuille afficher tous les films ayant le même réalisateur
que The Shining, mais qu’on ne sache pas qui est ce réalisateur. Pour ce faire, on crée une
requête qui recherche l’identifiant du réalisateur de The Shining, puis on utilise ce résultat
pour déterminer les films ayant pour réalisateur ce même identifiant. L’implémentation la
plus simple est par le biais d’une sous requête.

5
SELECT m. t i t l e , m. year FROM
movies AS m JOIN d i r e c t o r s AS d ON m. i d = d . movie_id
WHERE d . person_id =
(SELECT d . person_id FROM
movies AS m JOIN d i r e c t o r s AS d on m. i d = d . movie_id
WHERE m. t i t l e = "The␣ S h i n i n g " )
− Si on veut absolument se passer de sous-requêtes, on va devoir faire une jointure de
deux copies de movies et de deux copies de directors, ce qui ne sera pas très lisible.
− On peut utiliser les sous-requêtes à la place de jointures dans de nombreuses circons-
tances. Cependant, le résultat renvoyé par une sous-requête devrait être constitué
d’une seule colonne ; s’il y a plusieurs lignes et qu’une requête externe demande
l’égalité avec l’une des lignes, on écrira WHERE ... IN au lieu de WHERE ... =.

5 Agrégation
Définition 5.1
Une fonction d’agrégation est une fonction portant sur des ensembles de lignes.

Remarque 5.2
Ces fonctions vous par exemple nous permettre de compter le nombre de résultats ou de
donner la valeur moyenne d’un résultat à une requête.

Fonctions d’agrégation. Il y en a 5 au programme.


− COUNT : pour compter le nombre de résultats
− SOMME : pour faire la somme des résultats
− MIN, MAX : renvoie le minimum/le maximum des résultats
− AVG : renvoie la moyenne des résultats
Toutes ces fonctions s’appliquent sur un attribut donné de la table renvoyée.

Exemple 5.3
Pour renvoyer le nombre de films et l’année moyenne de sortie des films présents dans la
base de données :
SELECT COUNT( ∗ ) , AVG( year ) FROM movies

Clause GROUP BY. Cette clause permet de regrouper des résultats selon un attribut
commun. Si on utilise en plus des fonctions d’agrégation, celles-ci porteront sur l’ensemble
des lignes partageant cet attribut. Par exemple,
SELECT COUNT( i d ) , year FROM movies
GROUP BY year

6
Pour chaque année, on affiche le nombre de films sortis cette année (et l’année correspon-
dante).
Dans ce cas, on aurait pu écrire COUNT(*) au lieu de COUNT(id) (il y aura une différence
seulement si certains id ne sont pas renseignés).

Clause HAVING. Si un GROUP BY a été utilisé pour partitionner les résultats, on


peut vouloir afficher seulement certaines parties respectant une condition. Un WHERE
n’est pas adapté dans ce cas car la condition porte sur des données agrégées. On utilise
HAVING à la place.
SELECT COUNT( i d ) , year FROM movies
GROUP BY year
HAVING COUNT( i d ) >= 5000
On affiche seulement les années où au moins 5000 films répertoriés dans la base de données
sont sortis.

6 Exemple : base de données movies.db


Elle est constituée de 5 tables :
− la table movies(id,title,year) où id est la clef primaire correspondant à l’identi-
fiant du film, title est le titre du film, et year est l’année de sortie du film,
− la table people(id,name,birth) qui répertorie les caractéristiques des personnes
présentes dans la base de données, où id est l’identifiant de la personne, name son
nom et birth sa date de naissance,
− la table directors(person_id,movie_id) qui répertorie les réalisatrices et les réa-
lisateurs, où person_id correspond à l’id de la personne et movie_id à l’id du film
qu’elle a réalisé,
− la table stars(person_id,movie_id) qui liste les stars ayant joué dans les films,
avec person_id correspond à l’id de la personne et movie_id à l’id du film où elle a
joué,
− la table ratings(movie_id,rating,votes), qui liste les notes données sur imbd par
les internautes : movie_id correspond à l’identifiant du film, rating à la note (sur
10) donnée par les internautes, et votes le nombre de votants.

Vocabulaire
1. A quoi correspondent les champs soulignés ? Pourquoi y a-t-il deux champs soulignés
dans les tables directors et stars ?

Requêtes de base.
2. En quelle année le film Pulp Fiction est-il sorti ?

7
3. Lister tous les films dont le nom commence par Alien. On utilisera le test LIKE. Les
trier par année de sortie.

Jointures.
4. Déterminer tous les films réalisés par Sofia Coppola.
5. Déterminer le casting du premier Alien.
6. Déterminer tous les films dans lesquels a joué Nicolas Cage.
7. Trouver tous les films ayant une note supérieure à celle de Pulp Fiction.
8. Déterminer le deuxième film le mieux noté, en ne comptabilisant que les films ayant
eu + de 50000 votes.

Fonctions et agrégation.
9. Afficher les 50 réalisateurs ayant réalisé le plus de films.
10. Lister les réalisateurs selon la moyenne de la note de leurs films. Les trier par moyenne
décroissante.

Corrigé.
1. La/les clé(s) primaire(s).
2. SELECT year FROM movies where t i t l e = " Pulp ␣ F i c t i o n "

3. SELECT t i t l e , year FROM movies WHERE t i t l e LIKE " A l i e n%"


ORDER BY year

4. SELECT t i t l e FROM
movies AS m JOIN d i r e c t o r s AS d JOIN p e o p l e AS p ON
m. i d = d . movie_id AND p . i d = d . person_id
WHERE p . name = " S o f i a ␣ Coppola "

5. SELECT p . name FROM


movies AS m JOIN s t a r s AS s JOIN p e o p l e AS p ON
m. i d = s . movie_id AND p . i d = s . person_id
WHERE t i t l e = " A l i e n "

6. SELECT t i t l e FROM
movies AS m JOIN s t a r s AS s JOIN p e o p l e AS p ON
m. i d = s . movie_id AND p . i d = s . person_id
WHERE p . name = " N i c o l a s ␣Cage"

7. SELECT t i t l e , r a t i n g FROM
movies AS m JOIN r a t i n g s AS r ON
m. i d = r . movie_id
WHERE r . r a t i n g >=
(SELECT r a t i n g FROM

8
movies AS m JOIN r a t i n g s AS r ON
m. i d = r . movie_id
WHERE m. t i t l e = " Pulp ␣ F i c t i o n " )

8. SELECT t i t l e FROM
movies AS m JOIN r a t i n g s AS r ON m. i d = r . movie_id
WHERE r . v o t e s >= 50000
ORDER BY r . r a t i n g DESC
LIMIT 1 OFFSET 1

9. SELECT p . name , COUNT( t i t l e ) FROM


d i r e c t o r s AS d JOIN movies AS m JOIN p e o p l e AS p
ON d . movie_id = m. i d AND d . person_id = p . i d
GROUP BY p . i d
ORDER BY COUNT( t i t l e ) DESC
LIMIT 50

10. SELECT p . name , AVG( r a t i n g ) FROM


d i r e c t o r s AS d JOIN movies AS m JOIN p e o p l e AS p JOIN r a t i n g s as r
ON d . movie_id = m. i d AND d . people_id = p . i d AND d . movie_id = r . i d
GROUP BY p . i d
ORDER BY AVG( r a t i n g ) DESC

Vous aimerez peut-être aussi