Apprendre SQL : Lire dans sa BDD (SELECT)
Récupérez les données de votre base de données avec des requêtes SQL.
Dans un CRUD, on retrouve également une opération dite de lecture. Pour lire des données, on effectuera des requêtes de sélection.
Sélection
Pour récupérer des données stockées en BDD, on utilise les mots-clés SELECT
et FROM
.
SELECT
permet de spécifier quelles colonnes récupérer au sein de la table.FROM
permet de spécifier dans quelle table effectuer la sélection.
Cette commande retourne des enregistrements dans un tableau de résultat.
-- Récupération d'une colonne
SELECT colonne FROM nom_table;
-- Récupération de plusieurs colonnes
SELECT colonne_1, colonne_2 FROM nom_table;
-- Récupération de toutes les colonnes
SELECT * FROM nom_table;
📌 En pratique
Considérons la table articles
, stockant les articles d’un blog :
id | titre | contenu | auteur |
---|---|---|---|
1 | Maitriser les variables CSS | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. | Sébastien Chopin |
2 | Netlify VS Vercel : quelle est la meilleure solution d’hébergement de sites statiques ? | Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. | Evan You |
3 | Tout savoir sur les balises sémantiques en HTML. | Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. | Sébastien Chopin |
La requête suivante permet de récupérer tous les titres d’articles :
SELECT titre FROM articles;
titre |
---|
Maitriser les variables CSS |
Netlify VS Vercel : quelle est la meilleure solution d’hébergement de sites statiques ? |
Tout savoir sur les balises sémantiques en HTML. |
L’utilisation de la commande SELECT
récupère l’ensemble des enregistrements d’une table.
En revanche, cette commande peut potentiellement afficher des lignes en double. Pour éviter des doublons dans les résultats il faudra alors ajouter DISTINCT
après le mot SELECT
.
SELECT DISTINCT colonne
FROM nom_table;
📌 En pratique
Considérons la table articles
, stockant les articles d’un blog :
id | titre | contenu | auteur |
---|---|---|---|
1 | Maîtriser les variables CSS | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. | Sébastien Chopin |
2 | Netlify VS Vercel : quelle est la meilleure solution d’hébergement de sites statiques ? | Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. | Evan You |
3 | Tout savoir sur les balises sémantiques en HTML. | Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. | Sébastien Chopin |
La requête suivante permet de récupérer la liste des auteurs (sans doublons) :
SELECT DISTINCT auteur FROM articles;
auteur |
---|
Sébastien Chopin |
Evan You |
Si ces commandes s’avèrent très utiles lorsqu’il s’agit de travailler sur un jeu de données complet, bien souvent, nous ne souhaitons en récupérer qu’une partie. Pour cela, nous aurons la possibilité de filtrer les résultats avec la clause WHERE
, abordée plus tard dans ce cours.
Calculs
Parfois, il est intéressant d’effectuer des calculs sur un ensemble de données d’une colonne. Nous aurons alors besoin de fonctions d’agrégations statistiques.
SELECT FONCTION(colonne) FROM nom_table;
Il existe plusieurs fonctions d’agrégations statistiques qui s’appliquent sur un ensemble d’enregistrements. Les principales sont les suivantes :
SUM()
pour calculer la somme de plusieurs lignes.AVG()
pour calculer la moyenne de plusieurs lignes.COUNT()
pour compter le nombre de lignes concernées.MAX()
pour récupérer la plus grande valeur.MIN()
pour récupérer la plus petite valeur.
Faire appel à une fonction d’agrégation statistique a pour effet de créer une nouvelle colonne contenant le résultat. Cette colonne sera nommée du nom de la fonction utilisée.
📌 Cas pratique
Considérons la table videos
, comptabilisant le nombre de vues pour chaque vidéo d’un Youtubeur :
id | titre | vues |
---|---|---|
1 | Apprendre HTML/CSS en 1h chrono | 190 652 |
2 | Daily.dev, cette extension navigateur que vous devez avoir | 23 000 |
3 | Top 5 des raisons de devenir développeur, la dernière va vous étonner | 675 032 |
La requête suivante permet de connaître le nombre de vues total, moyen, maximal ainsi que le nombre de vidéos de la chaîne YouTube.
SELECT
SUM(vues) AS total,
AVG(vues) AS moyenne,
MAX(vues) AS record,
COUNT(vues) AS videos
FROM videos;
total | moyenne | record | videos |
---|---|---|---|
888 684 | 296 228 | 675 032 | 3 |
Groupement
Bien souvent, il est utile de grouper des données par colonne et d’utiliser une fonction statistique d’agrégation sur un groupe de résultats. On utilisera pour cela la commande GROUP BY
.
SELECT colonne_1, FONCTION(colonne_2)
FROM nom_table
GROUP BY colonne_1;
📌 Cas pratique
Considérons la table transactions
, regroupant les achats des utilisateurs d’une plateforme de cryptomonnaie :
id | pseudo | devise | quantite |
---|---|---|---|
1 | Yindi | BTC | 0.55 |
2 | Athios | SOL | 20 |
3 | Hackay | BTC | 2.25 |
4 | Hackay | ETH | 17 |
5 | Yindi | SOL | 5 |
6 | Athios | SOL | 15 |
7 | Yindi | BTC | 0.10 |
La requête suivante permet de connaître la quantité totale achetée pour chacune des cryptos.
SELECT devise, SUM(quantite) AS total
FROM transactions
GROUP BY devise;
devise | total |
---|---|
BTC | 2.9 |
ETH | 17 |
SOL | 40 |
La requête suivante permet de connaître la quantité achetée par crypto, par utilisateur.
SELECT pseudo, devise, SUM(quantite) as total
FROM transactions
GROUP BY pseudo, devise;
pseudo | devise | total |
---|---|---|
Athios | SOL | 35 |
Hackay | BTC | 2.25 |
Hackay | ETH | 17 |
Yindi | BTC | 0.65 |
Yindi | SOL | 5 |
Filtrage
Filtrer sur un tuple
Dans une requête SQL, la commande WHERE
permet d’extraire des lignes d’une base de données respectant une condition. Cette clause vient compléter un SELECT
de la manière suivante :
SELECT * FROM nom_table WHERE {condition};
Filtrer sur un groupe de tuples
Si un SELECT
est combiné à un GROUP BY
, il sera également possible de spécifier une condition de filtre non pas sur une ligne individuelle (WHERE
) mais sur une agrégation de lignes avec la commande HAVING
.
Pour rappel, cette agrégation est possible grâce à des fonctions statistiques comme COUNT()
, SUM()
, AVG()
, MIN()
ou encore MAX()
.
SELECT * FROM nom_table GROUP BY colonne HAVING {condition};
Ecrire une condition
Opérateurs de comparaison
Pour écrire une condition, on fait appel à des opérateurs de comparaison.
SELECT * FROM nom_table WHERE colonne {operateur_de_comparaison} valeur;
Opérateurs de comparaisons génériques
Ces opérateurs de comparaisons génériques sont identiques aux opérateurs élémentaires utilisés en algorithmie.
Opérateur | Description | Exemple |
---|---|---|
= | Égal | colonne = ‘truc’ |
<> ou != | Différent | colonne != ‘truc’ |
> | Supérieur | colonne > 20 |
< | Inférieur | colonne < 20 |
>= | Supérieur ou égal | colonne >= 20 |
<= | Inférieur ou égal | colonne <= 20 |
Opérateurs de comparaison spécifiques
En plus des opérateurs de comparaison universels, SQL propose des opérateurs spécifiques au langage, permettant d’écrire des requêtes plus simplement.
Ces opérateurs sont les suivants :
Opérateur | Description | Exemple |
---|---|---|
IN | Liste de plusieurs valeurs possibles | colonne IN (‘machin’, ‘bidule’, ‘truc’) |
BETWEEN | Valeur comprise dans un intervalle donné (très utile pour les nombres et dates) | colonne BETWEEN 1 AND 10 |
LIKE | Recherche en spécifiant le début, milieu ou fin d’un mot. | colonne LIKE ‘%.com’ |
IS NULL | Valeur est nulle | colonne IS NULL |
IS NOT NULL | Valeur n’est pas nulle | colonne IS NOT NULL |
SELECT * FROM nom_table WHERE colonne IN ('machin', 'bidule', 'truc')
permet d’éviter d’écrire :
SELECT * FROM nom_table WHERE
colonne = 'machin' OR
colonne = 'bidule' OR
colonne = 'truc';
On qualifie cela de « sucre syntaxique ». Le sucre syntaxique constitue une écriture propre à un langage (ici SQL) qui permet d’écrire et de lire une expression de manière plus agréable, plus simple et expressive.
Opérateurs logiques
AND
et OR
Comme il est souvent utile de vérifier la véracité de plusieurs conditions, il existe les opérateurs AND
et OR
qui permettent de cumuler des conditions.
SELECT * FROM nom_table WHERE condition_1 AND_ou_OR condition_2;
Opérateur | Description | Exemple |
---|---|---|
AND | Les deux conditions doivent être vraies. | condition_1 AND condition_2 |
OR | Au moins une des conditions doit être vraie. | condition_1 OR condition_2 |
NOT
Il existe également l’opérateur NOT
qui va quant à lui nous servir à vérifier qu’une condition écrite avec les opérateurs (LIKE
, BETWEEN
ou encore LIKE
) n’est pas vraie.
Opérateur | Description | Exemple |
---|---|---|
NOT | Vérifie qu’une condition n’est pas vraie. | colonne NOT IN (‘machin’, ‘bidule’, ‘truc’) |
📌 Cas pratique
Considérons la table utilisateurs
stockant des utilisateurs, leur âge et le fait qu’ils soient vaccinés contre la grippe ou non :
id | prenom | age | vaccine |
---|---|---|---|
1 | Pierre | 37 | 0 |
2 | Paul | 55 | 1 |
3 | Jacques | 14 | 1 |
La requête suivante permet de connaître le nombre de majeurs vaccinés contre la grippe.
SELECT COUNT(id) FROM utilisateurs
WHERE age >= 18 AND vaccine = 1;
id | prenom | age | vaccine |
---|---|---|---|
2 | Paul | 55 | 1 |
📌 Cas pratique
Considérons la table notes
stockant les notes de collégiens obtenues au cours d’une année scolaire :
id | prenom | nom | note |
---|---|---|---|
1 | Pierre | Machin | 12 |
2 | Paul | Bidule | 20 |
3 | Jacques | Truc | 10.5 |
4 | Jacques | Truc | 8 |
5 | Pierre | Machin | 16 |
6 | Paul | Bidule | 13 |
La requête suivante permet d’afficher la liste des étudiants qui ont plus de 10/20 de moyenne générale.
SELECT prenom, nom
FROM notes
GROUP BY prenom, nom
HAVING AVG(note) >= 10;
prenom | nom |
---|---|
Paul | Bidule |
Pierre | Machin |
Tri
Trier les données renvoyées par une requête est possible avec la commande ORDER BY
.
Cette commande doit être suivie d’un mot-clé caractérisant le sens de tri souhaité :
ASC
(ascendant) : croissant, alphabétique ou chronologique.DESC
(descendant) : décroissant, anti-alphabétique ou anti-chronologique.
SELECT * FROM nom_table ORDER BY colonne_1 ASC, colonne_2 DESC;
📌 Cas pratique
Considérons la table utilisateurs
stockant des utilisateurs, leur âge et le fait qu’ils soient vaccinés contre la grippe ou non :
id | prenom | age | vaccine |
---|---|---|---|
1 | Pierre | 37 | 0 |
2 | Paul | 55 | 1 |
3 | Jacques | 14 | 1 |
La requête suivante permet d’afficher la liste des utilisateurs vaccinés par âge décroissant.
SELECT * FROM utilisateurs
WHERE vaccine = 1
ORDER BY age DESC;
id | prenom | age | vaccine |
---|---|---|---|
2 | Paul | 55 | 1 |
3 | Jacques | 14 | 1 |
La requête suivante permet d’afficher les prénoms (sans doublons) des utilisateurs par ordre alphabétique.
SELECT DISTINCT prenom FROM utilisateurs
ORDER BY prenom;
prenom |
---|
Jacques |
Paul |
Pierre |
Pagination
Limite
Parfois, il peut être intéressant de limiter le nombre de résultats que l’on souhaite récupérer (affichage des X derniers articles sur la page d’accueil d’un blog, pagination affichant Y produits par page, etc.).
Pour cela nous utiliserons la commande LIMIT
en fin de requête.
SELECT * FROM nom_table ORDER BY colonne DESC LIMIT nombre_limite;
Décalage
Parfois, il est utile de décaler les lignes à obtenir. C’est-à-dire qu’au lieu de récupérer les X dernières ressources, on souhaiterait récupérer X ressources en sautant un certain nombre de résultats. On parle d’offset.
On précisera alors cet offset avant la limite, séparé d’une virgule ,
.
SELECT * FROM nom_table ORDER BY colone DESC LIMIT nombre_decalage, nombre_limite;
La meilleure manière de comprendre cette notion est de penser à un système de pagination :
- Page 1 : Je souhaite récupérer les 10 derniers ***.
- Page 2 : Je souhaite récupérer les 10 *** suivants (je saute les 10 premiers).
- Page 3 : Je souhaite récupérer les 10 *** suivants (je saute les 20 premiers).
- Etc.
📌 Cas pratique
Considérons la table produits
stockant des produits sur un site ecommerce :
id | nom | prix |
---|---|---|
1 | PC portable DELL XPS 15 | 1800 |
2 | Souris MX Master 3 | 105 |
3 | Webcam Logitech C920 HD PRO | 90 |
4 | Smartphone Xiaomi MI 9T PRO | 450 |
5 | Ecran Asus ProArt PA248QV | 260 |
6 | Hub USB Type-C Lemorele | 35 |
7 | Tapis de souris Steelseries Qck | 50 |
La requête suivante permet d’afficher les 3 produits les moins chers :
SELECT * FROM produits
ORDER BY prix
LIMIT 3;
id | nom | prix |
---|---|---|
6 | Hub USB Type-C Lemorele | 35 |
7 | Tapis de souris Steelseries Qck | 50 |
3 | Webcam Logitech C920 HD PRO | 90 |
La requête suivante permet d’afficher les produits du 7ᵉ au 9ᵉ moins chers :
SELECT * FROM produits
ORDER BY prix
LIMIT 6, 3;
id | nom | prix |
---|---|---|
1 | PC portable DELL XPS 15 | 1800 |
Jointures
Les jointures en SQL permettent d’obtenir des résultats qui combinent des données de plusieurs tables liées entre elles. Basées sur la théorie mathématique des ensembles, elles sont l’essence même du potentiel offert par les bases de données dites relationnelles.
Pour bien comprendre l’intérêt des jointures et par extension des relations, écrivons une aberration. Voici une table articles
qui stocke les articles d’un blog.
id | titre | contenu | date_publication | auteur_prenom | auteur_nom | auteur_bio |
---|---|---|---|---|---|---|
1 | Article n°1 | Blablabla | 2022-01-17 | John | Doe | J’aime la vie. |
2 | Article n°2 | Blablabla blablabla blablabla | 2019-12-03 | James | Bakels | Expert en BDD relationnelles. |
3 | Article n°3 | Blablabla blablabla | 2021-05-14 | John | Doe | J’aime la vie. |
3 | Article n°4 | Blablabla blablabla | 2017-09-10 | John | Doe | J’aime la vie. |
3 | Article n°5 | Blablabla blablabla blablabla | 2020-06-29 | James | Bakels | Expert en BDD relationnelles. |
Plusieurs problèmes évidents se dégagent de cette structure :
- ❌ Une base de données trop lourde par duplication d’informations.
- ❌ Une base de données brouillon, avec des types d’informations mélangés.
- ❌ Une base de données non évolutive.
- Admettons qu’un auteur souhaite modifier sa biographie ; il faudra modifier autant de lignes qu’il a écrit d’articles.
- Si on souhaite ajouter une caractéristique à un auteur, alors il faudra la mettre à jour autant de fois qu’il a écrit d’articles.
Pour pallier à ces problématiques, la solution est de séparer ces informations en deux tables dont le rôle de chacune va être de stocker un type d’information spécifique.
Table articles
id | titre | contenu | date_publication | auteur_id |
---|---|---|---|---|
1 | Article n°1 | Blablabla | 2022-01-17 | 1 |
2 | Article n°2 | Blablabla blablabla blablabla | 2019-12-03 | 2 |
3 | Article n°3 | Blablabla blablabla | 2021-05-14 | 1 |
4 | Article n°4 | Blablabla blablabla | 2017-09-10 | 1 |
5 | Article n°5 | Blablabla blablabla blablabla | 2020-06-29 | 2 |
Table auteurs
id | prenom | nom | bio |
---|---|---|---|
1 | John | Doe | J’aime la vie. |
2 | James | Bakels | Expert en BDD relationnelles. |
Maintenant que vous êtes convaincus, parlons jointures !
En SQL, il existe plusieurs types de jointures, mais la plupart du temps nous utilisons la même, à savoir le INNER JOIN
. Il s’agit littéralement d’une « jointure interne », permettant de retourner les enregistrements liés par une valeur commune au sein de deux tables, définie via le mot-clé ON
.
SELECT * FROM table_1
INNER JOIN table_2 ON table_1.fk_id = table_2.id;
Cette syntaxe stipule qu’il faut sélectionner les enregistrements des tables table_1
et table_2
lorsque la clé étrangère de la table_1 (table_1.fk_id
) est égale à la clé primaire de la table_2 (table_2.id
).
📌 Cas pratique
Reprenons nos tables articles
et auteurs
:
La requête suivante permet d’afficher les articles publiés par John Doe :
SELECT articles.titre FROM articles
INNER JOIN auteurs ON articles.auteur_id = auteurs.id
WHERE auteurs.prenom = 'John' AND auteurs.nom = 'Doe';
titre |
---|
Article n°2 |
Article n°5 |
Requêtes imbriquées
Dans le langage SQL une sous-requête (aussi appelé « requête imbriquée ») consiste à intégrer une requête SQL à l’intérieur d’une autre.
Les requêtes imbriquées sont notées entre parenthèses et peuvent être intégrées à diverses parties de la requête parente. Habituellement, elles sont exploitées dans une clause WHERE
ou HAVING
, bien que leur utilisation ne soit pas limitée à cela.
Une requête imbriquée peut alors retourner :
- Une valeur
- Un enregistrement
- Plusieurs enregistrements
📌 Cas pratique
Considérons la table produits
, répertoriant les produits d’un site ecommerce :
Table produits
id | nom | prix |
---|---|---|
1 | Produit n°1 | 10 |
2 | Produit n°2 | 30 |
3 | Produit n°3 | 8 |
4 | Produit n°4 | 12 |
SELECT * FROM produits WHERE prix > (SELECT AVG(prix) FROM produits);
Cette requête permet de récupérer les produits dont le prix est supérieur au prix moyen (ici 15
).
id | nom | prix |
---|---|---|
2 | Produit n°2 | 30 |
En permettant d’utiliser les résultats d’une requête à l’intérieur d’une autre, les requêtes imbriquées permettent des opérations complexes et spécifiques (filtrages, comparaisons, agrégations complexes…).